3
\$\begingroup\$

I'm pretty new to compute shaders and shader writing in general. I'm trying to write a compute shader for a procedural generation project I'm working on, it's purpose is to blend biomes together. The function works by taking a sample of points around the point it's trying to calculate, and counting up how many points of each biome are in the sample, then it uses this info to blend the biomes at the given point.

The problem is that I have to loop through all of the sample points, and I keep getting the error “forced to unroll loop, but unrolling failed.” I've tried various different things to try and fix such as using the [loop] attribute, in which case I get “can't unroll loops marked with loop attribute”, and I've tried using the [unroll()] attribute to specify the amount of iterations the loop goes through, but I get the unrolling failed message again. I was wondering if anyone could suggest a solution? Here is my code:

#pragma kernel CSMain

struct BlendInputData
{
    int x;
    int z;
    int i;
    int blendRadius;
    int biomeIndexIterat;
    int xSize;
    int zSize;
};

StructuredBuffer<BlendInputData> inputData;
StructuredBuffer<int> biomeList;
RWStructuredBuffer<float4> outputData;

static int blendRadius = inputData[0].blendRadius;
static int biomeIndexIterat = inputData[0].biomeIndexIterat;
static int xSize = inputData[0].xSize;
static int zSize = inputData[0].zSize;


int MeshIndexToBiomeIndex(int meshIndex)
{
    int biomeIndex = meshIndex;
    biomeIndex += (2 * blendRadius * blendRadius) + (blendRadius * xSize);
    biomeIndex += floor((meshIndex / (xSize + 1)) + 1) * 2 * blendRadius;
    return biomeIndex;
};

float Vector2Distance(int xOne, int yOne, int xTwo, int yTwo)
{
    float distance = sqrt(pow(xOne - xTwo, 2) + pow(yOne - yTwo, 2));
    return distance;
};

[numthreads(1, 1, 1)]

void CSMain(uint3 id : SV_DispatchThreadID)
{
    RWStructuredBuffer<float> blendedBiome;
    int x = inputData[id.x].x;
    int z = inputData[id.x].z;
    int i = inputData[id.x].i;
    int index = MeshIndexToBiomeIndex(i) - biomeIndexIterat - blendRadius;
    for (int sampleZ = -blendRadius; sampleZ <= blendRadius; sampleZ++)
    {
        for (int sampleX = -blendRadius; sampleX <= blendRadius; sampleX++)
        {
            int iterator = 1 - (floor(Vector2Distance(x, z, sampleX + x, sampleZ + z) / blendRadius));
            int biome = biomeList[index];
            blendedBiome[biome] += iterator;
            index++;
        }
        index += (biomeIndexIterat / blendRadius) - (2 * blendRadius) - 1;
    }
        
    float denominator = pow(blendedBiome[0], 2) + pow(blendedBiome[1], 2) + pow(blendedBiome[2], 2) + pow(blendedBiome[3], 2);
    blendedBiome[0] = pow(blendedBiome[0], 2) / denominator;
    blendedBiome[1] = pow(blendedBiome[1], 2) / denominator;
    blendedBiome[2] = pow(blendedBiome[2], 2) / denominator;
    blendedBiome[3] = pow(blendedBiome[3], 2) / denominator;
    
    outputData[id.x].x = blendedBiome[0];
    outputData[id.x].y = blendedBiome[1];
    outputData[id.x].z = blendedBiome[2];
    outputData[id.x].w = blendedBiome[3];
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Note this similar problem in HLSL. May have to do with the data structure you're using. \$\endgroup\$
    – Engineer
    Commented Nov 4, 2020 at 16:49

2 Answers 2

0
\$\begingroup\$

I have encountered a similar issue and I believe it is because you are assigning data to an array inside the loop. If you comment out the blendedBiome[biome] line you should find it compiles fine. Though obviously the shader would no longer do the job you want.

I think it is because after compilation the shader may try to run multiple iterations of the loop simultaneouly and therefore can come into conflict if the results can go to the same location. So it does not like it. By unrolling the loops it can prevent that from happening.

Sorry for being so late answering this but I have been investigating it recently as I have the same issue. If there is a solution I would love to know.

\$\endgroup\$
0
\$\begingroup\$

One way to get the shader compiling is to change blendedBiome into an array instead of a buffer: float blendedBiome[4];.

You might also want to add some checks in there to make sure that the index that you're writing to inside that array is valid.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .