작성
·
524
0
안녕하세요. 벌써 3달째 이 작업만 계속 하고 있어요. 유니티 compute shader(hlsl)에서 convolution matrix를 구현해 가장 가까운 게임 오브젝트까지의 거리를 모드 계산후 추후 효과를 입히는데 적용하고 싶은데 무슨 이유인진 몰라도 제 코드가 너무 이상하게 돌아가요ㅠㅠㅠㅠ
[numthreads(12,12,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
if(int(id.x) - 59 < 0 || int(id.x) + 58 >= MaxWidth || int(id.y) - 59 < 0 || int(id.y) + 58 >= MaxHeight) {
//Overflow prevention.
//For now, ignore screen edges.
return;
}
float4 srcPixel = Src[id.xy];
if(any(srcPixel.rgba > float4(0,0,0,0).rgba)) {
//Center of convolution matrix on opaque pixel
float4 displayPixel = float4(0,0,0,0);
uint visibleGameObjectCount = 0;
for(int i = 0; i < GameObjectListCount; i++) {
float4 colorAtDepth = ColorTextureArray.Load(uint3(id.xy, i));
if(any(colorAtDepth.rgba > float4(0,0,0,0).rgba)) {
displayPixel += colorAtDepth / GameObjectListCount;
visibleGameObjectCount++;
}
}
displayPixel *= (GameObjectListCount / visibleGameObjectCount);
Dest[id.xy] = displayPixel;
return;
}
else {
bool emptyMatrix = true;
//Variables to store minimum distances to each game object
//deltaX and deltaY added here may be negative, because it is distance from id.xy
//I need separate storages for positive and negative delta
//Because adding a negative index to omegaX and omegaY makes the added number go out of its bounds
uint omegaX = 0;
uint omegaY = 0;
//Or simply store only absolute values in omegaX and omegaY, store a separate variable that represents -,- or +,+ one for x and one for y for each game object, which is similarly indexed using each game object's index
//Every time omegaX and omegaY is being updated, signUnsignXY will also be updated 1 for sign, 0 for unsign
uint signUnsignXY = 0;
//Will be used for avg. distance calculation
float indexesForDistance = 0;
//Counter for visible game objects within each convolution matrix
float visibleGameObjectCountMatrix = 0;
//Modified logic:
//Check if a pixel within the convolution matrix is opaque
//If it is, start iterating through ColorTextureArray at that location(xy)
//In order to compare with the previous minimum, for *every* pixel that is *opaque* within
//that xy's *ColorTextureArray*, use its index to access the actual deltaX and deltaY
//that belongs to that game object, and if the current value is less than the previously
//update the values using:
//omegaX = omegaX - ((omegaX / 100^i) % 100) + (deltaX * 100^i)
//omegaY = omegaY - ((omegaY / 100^i) % 100) + (deltaY * 100^i)
//When doing the actual comparison, it must be between pythagorean distances
//Convolution matrix: size = 57x57(i.e. ~1.5 cm)
//Caution: Proceed to read in a peaceful environment
for(int i = 29; i > -28; i--) {
for(int j = 29; j > -28; j--) {
float4 srcPixel = Src[id.xy - int2(j, i)];
if(any(srcPixel.rgba > float4(0,0,0,0).rgba)) {
emptyMatrix = false;
// Dest[id.xy] = float4(1,1,1,1);
//Current minimum that may or may not overwrite previous minimum
//For the first current minimum, either deltaX or deltaY must > 0, since case 0 is already
//taken care of above and the fact that it is visible at this location means a minimum of a GO
int deltaX = -j;
int deltaY = -i;
//Positive by default
uint signX = 1;
uint signY = 1;
if(deltaX < 0) {
signX = 0;
}
if(deltaY < 0) {
signY = 0;
}
//As long as a deltaX or deltaY exists, it's abs is guaranteed to be > 0
float minimumDistance = 1 / rsqrt(deltaX * deltaX + deltaY * deltaY);
for(int c = 0; c < GameObjectListCount; c++) {
float4 minimumDistancePixel = ColorTextureArray.Load(uint3(id.xy - int2(j, i), c));
//First check whether each pixel in ColorTextureArray at this location is opaque
if(any(minimumDistancePixel.rgba > float4(0,0,0,0).rgba)) {
//id.x + omegaX(indexed)
uint previousGameObjectAccessor = (uint)pow(100, c);
uint previousDeltaX = (omegaX / previousGameObjectAccessor) % 100;
//id.y + omegaY(indexed)
uint previousDeltaY = (omegaY / previousGameObjectAccessor) % 100;
//Previous pythagorean distance
float previousMinimumDistance = 0;
//Problem: while 1 / (1 / x) = x for most numbers, for 0, it becomes division by 0
if(previousDeltaX > 0 || previousDeltaY > 0) {
previousMinimumDistance = 1 / rsqrt(previousDeltaX * previousDeltaX + previousDeltaY * previousDeltaY);
}
if(previousMinimumDistance > minimumDistance) {
//New minimum for game object at index c, but it has been mapped already and can be indexed with discrete values
//Write new minimum in StorageTextureArray:
float4 previousStoredPixel = StorageTextureArray.Load(uint3(id.xy - int2(j, i), c));
if(all(previousStoredPixel.rgba <= float4(0,0,0,0).rgba)) {
StorageTextureArray[uint3(id.xy - int2(j, i), c)] = minimumDistancePixel;
}
//Dest[id.xy - int2(j, i)] = float4(0,0,1,1);
//Update omegaX and omegaY while replacing previous deltaX and deltaY
omegaX = omegaX - ((omegaX / previousGameObjectAccessor) % 100) + abs(deltaX) * previousGameObjectAccessor;
omegaY = omegaY - ((omegaY / previousGameObjectAccessor) % 100) + abs(deltaY) * previousGameObjectAccessor;
//Update signUnsignXY (rewrite)
uint totalSign = signX * 10 + signY;
signUnsignXY = signUnsignXY - ((signUnsignXY / previousGameObjectAccessor) % 100) + totalSign * previousGameObjectAccessor;
//Once a mapping has been created for every visible game object, further updating indexes for distance not necessary,
//because every game object that was visible at least once in the matrix will also be factored in the weighted color
//computation that uses minimum distances of all game objects
}
//Is this valid logic to count unique game objects using this conditional?
else if(previousMinimumDistance == 0) {
//Very first instance of a unique game object index at xy
//i.e. this if condition will run only once for each game object index
//Why can the matrix detect one game object but not 2???
//This means previousMinimumDistance == 0 is true only once within the convolution matrix
//Even though accessing a game object that hasn't been indexed yet must return 0
//Write new minimum in StorageTextureArray:
float4 previousStoredPixel = StorageTextureArray.Load(uint3(id.xy - int2(j, i), c));
if(all(previousStoredPixel.rgba <= float4(0,0,0,0).rgba)) {
StorageTextureArray[uint3(id.xy - int2(j, i), c)] = minimumDistancePixel;
}
//Dest[id.xy - int2(j, i)] = float4(0,1/c,0,1);
//Update omegaX and omegaY without replacing with deltaX and deltaY (absolute value)
omegaX += abs(deltaX) * previousGameObjectAccessor;
omegaY += abs(deltaY) * previousGameObjectAccessor;
//Update signUnsignX
uint totalSign = signX * 10 + signY;
signUnsignXY += totalSign * previousGameObjectAccessor;
//Create (discrete index) to (game object index) mapping
//indexesForDistance += c * pow(100, visibleGameObjectCountMatrix);
//Increment this value until it becomes the maximum # of GO in matrix
//visibleGameObjectCountMatrix++;
//visibleGameObjectCountMatrix runs once for either case, but if one case runs, the other case doesn't
//Why the fuck does this happen?
visibleGameObjectCountMatrix++;
}
}
}
}
}
}
//End of convolution matrix processing
//Come up with a test:
//Test for accuracy of matrix
// if(visibleGameObjectCountMatrix == 0) {
// //Dest[id.xy] = float4(1,0,0,1);
// }
//At this point, either emptyMatrix or we have all the information needed to apply to this pixel
if(!emptyMatrix) {
if(visibleGameObjectCountMatrix == 2) {
Dest[id.xy] = float4(1,0,0,1);
}
//Test of whether for each xy, it properly colors the right location in StorageTextureArray
// for(int i0 = 0; i0 < visibleGameObjectCountMatrix; i0++) {
// uint currentGameObjectIndex = (indexesForDistance / pow(100, i0)) % 100;
// //Access color
// int finalDeltaX = (omegaX / pow(100, currentGameObjectIndex)) % 100;
// int finalDeltaY = (omegaY / pow(100, currentGameObjectIndex)) % 100;
// float pythagoreanDelta = 1 / rsqrt(finalDeltaX * finalDeltaX + finalDeltaY * finalDeltaY);
// //Here, apply appropriate signs
// //Fetch sign for x
// if((((signUnsignXY / pow(100, currentGameObjectIndex)) % 100) / pow(10, 1)) % 10 == 0) {
// finalDeltaX = -finalDeltaX;
// }
// //Fetch sign for y
// if(((signUnsignXY / pow(100, currentGameObjectIndex)) % 100) % 10 == 0) {
// finalDeltaY = -finalDeltaY;
// }
// float4 storageColor = StorageTextureArray.Load(uint3(id.xy + int2(finalDeltaX, finalDeltaY), currentGameObjectIndex));
// //This is supposed to color only the slime borders...
// Dest[id.xy + int2(finalDeltaX, finalDeltaY)] = float4(1,0,0,1);
// }
//This logic seems to be problematic ()
//Why the fuck is the shape of all the id.xy where # of game objects found within the matrix >= 2 fucked up?
//This logic must be true for a wide area?
// if(visibleGameObjectCountMatrix >= 2) {
// Dest[id.xy] = float4(1,0,1,1);
// }
// if(visibleGameObjectCountMatrix >= 2) {
// //Only apply metaball effect if at least 2 game objects are within the matrix, otherwise, meaningless
// float avgDistanceDelta = 0;
// float totalDistanceDelta = 0;
// float4 weightedColor = float4(0,0,0,0);
// //Loop responsible for computing:
// //1. avg distance
// //2. total distance
// for(uint i1 = 0; i1 < visibleGameObjectCountMatrix; i1++) {
// uint currentGameObjectIndex = (indexesForDistance / pow(100, i1)) % 100;
// //finalDeltaX and finalDeltaY are guaranteed to be > 0, since they were stored that way
// uint finalDeltaX = (omegaX / pow(100, currentGameObjectIndex)) % 100;
// uint finalDeltaY = (omegaY / pow(100, currentGameObjectIndex)) % 100;
// //pythagorean delta distance
// float pythagoreanDelta = 1 / rsqrt(finalDeltaX * finalDeltaX + finalDeltaY * finalDeltaY);
// //Avg
// avgDistanceDelta += pythagoreanDelta / visibleGameObjectCountMatrix;
// //Total
// totalDistanceDelta += pythagoreanDelta;
// }
// //Loop responsible computing weighted color
// for(uint i2 = 0; i2 < visibleGameObjectCountMatrix; i2++) {
// uint currentGameObjectIndex = (indexesForDistance / pow(100, i2)) % 100;
// //Access color
// int finalDeltaX = (omegaX / pow(100, currentGameObjectIndex)) % 100;
// int finalDeltaY = (omegaY / pow(100, currentGameObjectIndex)) % 100;
// float pythagoreanDelta = 1 / rsqrt(finalDeltaX * finalDeltaX + finalDeltaY * finalDeltaY);
// //Here, apply appropriate signs
// //Fetch sign for x
// if((((signUnsignXY / pow(100, currentGameObjectIndex)) % 100) / pow(10, 1)) % 10 == 0) {
// finalDeltaX *= -1;
// }
// //Fetch sign for y
// if(((signUnsignXY / pow(100, currentGameObjectIndex)) % 100) % 10 == 0) {
// finalDeltaY *= -1;
// }
// float4 unweightedColor = StorageTextureArray.Load(uint3(id.xy + int2(finalDeltaX, finalDeltaY), currentGameObjectIndex));
// //Why is this not contained in
// //int2(finalDeltaX / 1000, finalDeltaY / 1000)
// //int2(finalDeltaX, finalDeltaY)
// //Dest[id.xy + int2(finalDeltaX, finalDeltaY)] = float4(1,0,0,1);
// float weight = (totalDistanceDelta - pythagoreanDelta - ((visibleGameObjectCountMatrix * totalDistanceDelta - 2 * totalDistanceDelta) / visibleGameObjectCountMatrix)) / totalDistanceDelta;
// weightedColor += unweightedColor * weight;
// }
// //Condition to decide whether or not to color current dest.xy SV_DispatchThreadID
// if(avgDistanceDelta < 20) {
// //Dest[id.xy] = weightedColor;
// //Dest[id.xy] = weightedColor;
// }
// //Dest[id.xy] = float4(0,1,0,1);
// //Dest[id.xy] = max(testColor0, testColor1);
// Dest[id.xy] = float4(1,0,0,1);
// }
//else if (visibleGameObjectCountMatrix < 2) {
//Dest[id.xy] = float4(1,0,0,1);
//}
//Dest[id.xy] = float4(1,0,1,1);
// if((int)visibleGameObjectCountMatrix == 2) {
// Dest[id.xy] = float4(1,0,1,1);
// }
//Dest[id.xy] = float4(1,0,0,1);
}
return;
}
//Test:
//If storage texture array was updated properly, then
//float4 testColor0 = StorageTextureArray.Load(uint3(id.xy, 0));
//float4 testColor1 = StorageTextureArray.Load(uint3(id.xy, 1));
//Dest[id.xy] = max(testColor0, testColor1);
//Dest[id.xy] = testColor1;
//return;
}
여기 테스팅 단계에서 보시다시피 매트릭스 내에서 게임 오브젝트가 2개 발견된 중앙 픽셀들을 모두 빨간색으로 칠하라고 했더니 이런 이상하고 징그러운 모양이 나오네요.
저좀 도와주세요ㅠㅠ
답변 1
0
안녕하세요, 인프런 AI 인턴이에요. compute shader에서 convolution matrix를 구현하고 싶은데 코드가 이상하게 돌아간다고 하셨군요. 혹시 어떤 부분이 이상하게 돌아가는지 자세히 설명해주실 수 있을까요? 그러면 더 정확한 도움을 드릴 수 있을 것 같아요.