Some Problem when trying to implement ParallaxMapping

Started by
1 comment, last by viX0026 10 years, 6 months ago

Hi, guys, I'm trying to implement parallax mapping in hlsl, I use the algorithm in "ParallaxOcclusionMapping" in D3D Sample, But I always get a complie error X3511: Unable to unroll loop, loop does not appear to terminate in a timely manner (1024 iterations). I have tried on RenderMonkey and D3D9, neither of them works. Here is my code(simplified, I just implemented the height profile-ray intersection):


struct PS_INPUT
{
    float2 texCoord    : TEXCOORD0;
    float3 vLightDirTS : TEXCOORD1;
    float3 vViewDirTS  : TEXCOORD2;
    float3 vNormalWS   : TEXCOORD3;
    float3 vViewDirWS  : TEXCOORD4;
};


float4 CalculateLighting(float3 vViewTS, float3 vLightTS, float2 texCoord)
{
    float3 vNormalTS = normalize(tex2D(tNormalHeightMap, texCoord).xyz * 2 - 1);
    float4 cBaseColor = tex2D(tBase, texCoord);
    float4 cDiffuse = saturate(dot(vLightTS, vNormalTS)) * g_LightDiffuse;
    float4 cFinal = (g_LightAmbient + cDiffuse) * cBaseColor;
    return cFinal;
}

float4 PM_PS( VS_OUTPUT In ) : COLOR0
{ 
    float2 vOffsetTS = float2(In.vViewDirTS.x, In.vViewDirTS.y) / In.vViewDirTS.z;
    float3 vViewTS   = normalize(In.vViewDirTS);   // view direction in tangent space
    float3 vViewWS   = normalize(In.vViewDirWS);   // view direction in world space
    float3 vLightTS  = normalize(In.vLightDirTS);  // light direction in tangent space
    float3 vNormalWS = normalize(In.vNormalWS);    // normal in world space

    vOffsetTS *= g_fHeightMapScale;
    int NumSteps = (int)lerp(g_MaxSample, g_MinSample, max(dot(vNormalWS, vViewWS), 0.0f));
    float fStepSize = 1.0f / (float)NumSteps;
    float fCurrHeight = 0.0f;
    float fPrevHeight = 1.0f;
    float fCurrBound  = 1.0f;
    float fHeight = 0.0f;

    int nStepIndex = 0;
    float2 vTexOffsetPerStep = vOffsetTS * fStepSize;
    float2 vCurrTexCoord = In.texCoord;

	while(nStepIndex < NumSteps)   // height profile-ray intersection
	{
		vCurrTexCoord -= vTexOffsetPerStep;
		fCurrHeight = tex2D(tNormalHeightMap, vCurrTexCoord);
		fCurrBound -= fStepSize;
		if(fCurrHeight > fCurrHeight)   // we have found the intersection point
		{
			float delta1 = fCurrHeight - fCurrBound;
			float delta2 = fCurrBound + fStepSize - fPrevHeight;
			float alpha = delta1 / (delta1 + delta2);
			fHeight = 1.0f - lerp(fCurrHeight, fPrevHeight, alpha);  // calculate height approximately
			nStepIndex = NumSteps + 1;
		}
		else
		{
			fPrevHeight = fCurrHeight;
			nStepIndex++;
		}
	}

    float2 vParallaxOffset = vOffsetTS * fHeight;
    float2 texCoord = In.texCoord - vParallaxOffset;
   
    float4 cFinalColor = CalculateLighting(In.vViewDirTS, In.vLightDirTS, texCoord);
    return cFinalColor;
}

I compiled the "ParallaxOcclusionMapping" in D3D Sample, everything is OK. But mine couldn't work. I can't figure it out how to solve this problem.

Advertisement

Next time please post the entire shader, since what you posted doesn't include the textures and constants that you use.

Anyway the problem is that you're using tex2D inside a loop, which isn't allowed since the hardware can't compute gradients for mipmapping inside of dynamic flow control (since neighboring pixels in a 2x2 quad might take different paths at a branch). You should compute the gradients outside the loop and pass them into tex2Dgrad, like the sample does. The reason the compiler isn't giving the right error message is because it's trying to be too clever for its own good. When you try to use gradient operations inside a branch or loop, it will try to either pull the operation out of the loop/branch or flatten/unroll the branch. In your particular case it tried to unroll, but it failed to do it since the loop is meant to be dynamic. If you force the compiler to try to use a dynamic loop instead of unrolling it by putting [loop] above the while loop, it gives the correct error message.

BTW once you fix that you'll also want to change "if(fCurrHeight > fCurrHeight)" to "if(fCurrHeight > fCurrBound)", otherwise it's never going to take that branch and the whole thing will get optimized away.

Next time please post the entire shader, since what you posted doesn't include the textures and constants that you use.

Anyway the problem is that you're using tex2D inside a loop, which isn't allowed since the hardware can't compute gradients for mipmapping inside of dynamic flow control (since neighboring pixels in a 2x2 quad might take different paths at a branch). You should compute the gradients outside the loop and pass them into tex2Dgrad, like the sample does. The reason the compiler isn't giving the right error message is because it's trying to be too clever for its own good. When you try to use gradient operations inside a branch or loop, it will try to either pull the operation out of the loop/branch or flatten/unroll the branch. In your particular case it tried to unroll, but it failed to do it since the loop is meant to be dynamic. If you force the compiler to try to use a dynamic loop instead of unrolling it by putting [loop] above the while loop, it gives the correct error message.

BTW once you fix that you'll also want to change "if(fCurrHeight > fCurrHeight)" to "if(fCurrHeight > fCurrBound)", otherwise it's never going to take that branch and the whole thing will get optimized away.

Thanks, that works ! But I'm a little bit confused about gradient operation in dynamic flow. I read the "Flow Control Limitations" in MSDN. This is how it describes:

"When flow control is present in a shader, the result of a gradient calculation requested inside a given branch path is ambiguous when adjacent pixels may execute separate flow control paths. Therefore, it is deemed illegal to use any pixel shader operation that requests a gradient calculation to occur at a location that is inside a flow control construct which could vary across pixels for a given primitive being rasterized."

I couldn't imagine how the error occurs when there are some gradient operations inside a dynamic flow. Can you show me some examples about this ? Thanks again !

This topic is closed to new replies.

Advertisement