Forced to unroll loop, but unrolling failed [RESOLVED]

Started by
8 comments, last by EnlightenedOne 13 years, 8 months ago
Hi there I have a for loop in my shader (model 3) that gives me an error.

AdvancedPassShader.fx(359,6): error X3511: forced to unroll loop, but unrolling failed.

I have iscolated the problem down pretty finely, it seems to be a matter of depth complexity.

	for(int x = 0; x < totalProjections; x++)	{		float4 ProjLight = tex2Dproj(ProjTexSampler, IN.TexCoordProj[x]);		if (IN.TexCoordProj[x].w < 0.0)		{   			//We do not modify the projection at all if we are the opposite direction from it.			finalColor += 0.5;		}		else		{                        //If I use x for anything in here the shader throws the above wobbly.	        }	}


The problem is I have no alternative but to use that structure if I want multiple projections to be rendered in one pass without a backfacing issue. Do I have to scrap batch processing projections and create a seperate technique to render per projection?

[Edited by - EnlightenedOne on August 19, 2010 7:18:56 AM]
Advertisement
The reason it's forced to unroll that loop is because of that texture load and the way D3D handles automatic mip level calculations.

If you used say tex2dlod (or a texture reading funciton that accepts the ddx and ddy parameters) it would be able to use a real loop. I think that would require manually doing the projection calculation (divide by w).

Alternatively make the totalProjections value a compile time constant so it can unroll the loop.
Hey there, totalProjections could not be made a constant without removing a layer of abstraction higher up. Can you give more fine detail on doing manual projection calculations?

I attempted to use tex2Dlod but I got an error thrown at me that I had fed in some incorrect value. Evidently I would need to figure out how to manage a mp mapped image and its lod in HLSL. I have only done that in the FFP before im fairly new to shaders, not able to use multiple techniques yet so a long way to go!

Thanks for the advice, I had seen the lod thing in another game dev I found via googling the error for a solution.
If you could post your shader (as minimum complete repro) that would make it easier to help find work a rounds that would get it to compile.
Try something like this. The w component is the mip map to use. Just using the biggest one will work.

float4 TC = float4(IN.TexCoordProj[x].x / IN.TexCoordProj[x].w, IN.TexCoordProj[x].y / IN.TexCoordProj[x].w, 0.0f, 0.0f);float4 ProjLight = tex2Dlod(ProjTexSampler, TC);
Gave it a try had the same error, it seems any reference to x inside of the for loop combined with the if causes the trouble, if you remove either it works thats why I thought it was a depth of complexity issue.

If you want detail on code here is that detail and an explanation as to whats going on. To skip plot go down to the line of *****.

This is something I have been playing around with, it under no circumstances does what I had desired at the moment but your welcome to pick at it. The idea was to project a texture onto the surrounding environment (ideally a cube light sort of deal) so that I can project a disco ball or some funky colours everywhere within a falloff range. So I started out trying to get a basic projector to work. It did work but the lighting on the wall was flat and destroyed the illusion of depth created by the parallax relief mapping I had implemented.

Flat Projection on Parallax Wall

The aim being to find a way to make the projectors lighting work with the normal map of the wall and its heightmap to create accurate depth on the surface based on the projectors position. Obviously at this point I am just getting a framework with which to play around with values to try and get that to happen I have never done a stencil buffer trick before but I was going to look into that when I got this working.

I am not sure if its possible to figure out how the walls UV texture is mapped in order to handle throwing its normals to display the image correctly, but you dont learn without trying.

********************************************************************

Here are all my constants and the projected textures sampler state.

float4x4 WorldViewProj; //World * View * Projection Matrixfloat4x4 World;         //World matrix of objectfloat4 EyePos;          //Position of eye in world space//PARALLAX REQSfloat4 LightPos[6];        //Light position in world spacefloat4 LightColor[6];      //Color of the lighttexture ColorMap;       //Color texturetexture NormalMap;      //Normal map texturetexture HeightMap;      //Height map texturetexture ColorMap2;       //Color texturetexture NormalMap2;      //Normal map texturetexture HeightMap2;      //Height map texturetexture BlendMap;	//The map for blending the two effectsfloat Falloff[6];          // Distance until light begins to fallofffloat Ambient;          // Ambient amount of lightingfloat DepthScale = 0.04f; //Depth of the parallax mapfloat Bias = 0.02f;       //Bias of the parallax map//PROJECTIVE TEX REQSfloat4x4 TexTransform[3];  //Texture transformation matrixtexture ProjTex; //The projected image, could be seperated for multiple types.float3 ProjectorPos[3];     //World position of the projection matrixfloat ProjFalloff[3]; //Degree to which the image attenuates over distanceint totalProjections;//PROJECTIVE TEX REQsampler ProjTexSampler = sampler_state{	Texture = <ProjTex>;	MinFilter = anisotropic;	MagFilter = anisotropic;	MipFilter = anisotropic;	AddressU  = Border;	AddressV  = Border;};


Here are my relevant structures.

////////////////////////////////////////////////////////////////Structures////////////////////////////////////////////////////////////////Application to vertex shaderstruct A2V_AdvancedLight{ 	float4 Position : POSITION;	float3 Normal : NORMAL;	float2 TexCoord0 : TEXCOORD0;	float3 Tangent : TANGENT;	float3 Binormal : BINORMAL;};//PROJECTIVE TEX REQS////////////////////////////////////////////////////////////// Structures////////////////////////////////////////////////////////////struct V2P_Projection{	float4 Position  : POSITION;	float2 TexCoord0 : TEXCOORD0;	float4 TexCoordProj[3] :TEXCOORD1;	float3 ProjVec[3]  : TEXCOORD4;	float3 ViewDir : TEXCOORD7;};


Here are my shaders.

////////////////////////////////////////////////////////////// Vertex Shader PROJECTIVE TEX////////////////////////////////////////////////////////////void VS_PT(in A2V_AdvancedLight IN, out V2P_Projection OUT){	//Transform the position from view space to homogeneous projection space	OUT.Position = mul(IN.Position, WorldViewProj);	//Compute world space position	float4 WorldPos = mul(IN.Position, World);    	//Calculate Binormal and set Tangent Binormal and Normal matrix	float3x3 TBNMatrix = mul(float3x3(IN.Binormal, IN.Tangent , IN.Normal), (float3x3)World); 	//Compute view direction * TBN Matrix	OUT.ViewDir = mul(TBNMatrix, EyePos - WorldPos);		for(int x=0; x < totalProjections; x++)	{		//Position to projection vector		OUT.ProjVec[x] = mul(IN.Position.xyz, (float3x3)World) - ProjectorPos[x];		//Compute projection direction * TBN Matrix		OUT.ProjVec[x] = mul(TBNMatrix, OUT.ProjVec[x]);		//Need to calculate the texture coordinates between persons positon and their transformations position to work out actual location.		OUT.TexCoordProj[x] = mul(IN.Position, TexTransform[0]);	} 	//Copy the texture coordinate as is	OUT.TexCoord0 = IN.TexCoord0;}////////////////////////////////////////////////////////////// Pixel Shader PROJECTIVE TEX////////////////////////////////////////////////////////////float4 PS_PT(in V2P_Projection IN) : COLOR {	IN.ViewDir = normalize(IN.ViewDir);	//We need to define everything ready for our loop.	float Height;	float2 TexCorrected;	float4 ProjC;	float3 Normal;	float LenSq;	float Attn;	float Diffuse;	float4 finalColor;	finalColor = 0;	//We need to sort the blend map	vector BlendMapV  = tex2D( BlendMapSampler, IN.TexCoord0);//Here is the for loop that crashes things.	for(int x = 0; x < totalProjections; x++)	{		float4 ProjLight = tex2Dproj(ProjTexSampler, IN.TexCoordProj[x]);//Remove this if and it works with x mentioned inside the loop.		if (IN.TexCoordProj[x].w < 0.0)		{   			//We do not modify the projection at all if we are the opposite direction from it.			finalColor += 0.5;		}		else		{//Remove any mention of x inside the if and it works.			Height = DepthScale * tex2D(heightSampler, IN.TexCoordProj[0]) - Bias;			                			//Compute the new texture coorddinate to use			TexCorrected = Height * IN.ViewDir + IN.ProjVec[0];			//Pixel to light vector			LenSq = dot( IN.ProjVec[0], IN.ProjVec[0] );			IN.ProjVec[0] = normalize( IN.ProjVec[0] );			//Compute the light's attenuation			Attn = min((ProjFalloff[0]* ProjFalloff[0]) / LenSq, 1.0f);			//Compute the diffuse lighting amount			Diffuse = Attn * saturate(dot(TexCorrected, IN.ProjVec[0]));			//Lighting amount * Texture Color * Light Color			ProjC =  ProjLight * Diffuse;			//Combinant of the two based on the blend map-------------			finalColor += ProjC;		}			}	//Return the combinant of the two based on the blend map-------------	return finalColor;}


and finally the technique is below.

////////////////////////////////////////////////////////////////Technique//////////////////////////////////////////////////////////////technique ParallaxMapPointLightBlend{	pass p0	{		vertexshader = compile vs_3_0 VS_P();		pixelshader = compile ps_3_0 PS_PBM();	}	pass p1	{		ALPHABLENDENABLE = TRUE;		SRCBLEND = ONE;		DESTBLEND = ONE;		VertexShader = compile vs_3_0 VS_PT();		PixelShader = compile ps_3_0 PS_PT();	}}


To clarify I am not desperate for help in getting the full effect to work. I just need to be able to figure out why the pixel shader cant have a nested if use the x variable from the for loop.
Ok I perfected everything and got the shader to work without the for loop, looks beautiful if you want proof I will be happy to post it :D

I then went on to try and add the for loop so I can batch draw 3 projections per draw.

I wont bore you with alot of code but here is what I did using what you gave as an example.

	for(int x = 0; x < totalProjections; x++)	{		float4 TC = float4(IN.TexCoordProj[x].x / IN.TexCoordProj[x].w, IN.TexCoordProj[x].y / IN.TexCoordProj[x].w, 0.0f, 0.0f);		if (TC.w < 0.0)		{   			//We do not modify the projection at all if we are the opposite direction from it.			finalColor += 0;		}		else		{			ProjDirHolder = IN.ProjVec[x];			Height = DepthScale * tex2D(heightSampler, IN.TexCoord0) - Bias;                			//Compute the new texture coorddinate to use			TexCorrected = Height * IN.ViewDir + IN.TexCoord0;			ProjLight = tex2Dproj(ProjTexSampler, TC);


Of my now three shaders (one overlays wireframe) the projection one compiles and lets me do its pass, but it no longer draws anything to screen using this TC solution. Am I applying the solution wrongly? Thanks for the feedback, I prefer compilation over nothing, I will play with the values in TC.
Cracked it in the first go!

float4 TC = float4(IN.TexCoordProj[x].x / IN.TexCoordProj[x].w, IN.TexCoordProj[x].y / IN.TexCoordProj[x].w, 1.0f, 1.0f);

I had to have 1 and 1 to draw to the correction display, thank you so much for your advice! Up goes your rating!
Ok I had laid to rest my issues with this task thinking it was finished until earlier today when experimenting with the projection matrix something went terribly wrong.

float4 TC = float4(IN.TexCoordProj[x].x / IN.TexCoordProj[x].w, IN.TexCoordProj[x].y / IN.TexCoordProj[x].w, 1.0f, 1.0f);

works fine inside the loop.... but

		if (TC.w < 0.0)		{   			//We do not modify the projection at all if we are the opposite direction from it.			finalColor += 0.5;		}		else		{                        //If I use x for anything in here the shader throws the above wobbly.	        }


TC.w is always above 1! so the backfacing projections are not removed with this corrected code.

Of course IN.TexCoordProj[x].w is what I need to apply here, yet despite it being used inside the loop directly above this line when I try and use it the program crashes and the loop unrolls with no further error details.

If it were a matter of complexity I would not be able to use the value in the for loop directly above where I need it now! So what is going on here???
I found an override! because I was looping around an external variable it must have been trying to predict how many I would need above what it could handle.

I can never have it draw more than 3 projections at once anyway! so why bother letting it try and manage more memory than that amount?

I am please to be able to fix so many of my own problems these days :) I almost feel bad for posting this extension now! Hopefully this helps someone.

	for(int x = 0; x < 3; x++)	{		if (x < totalProjections) // 0 to 1		{		float4 TC = float4(IN.TexCoordProj[x].x / IN.TexCoordProj[x].w, IN.TexCoordProj[x].y / IN.TexCoordProj[x].w, 1.0, 1.0);				if (IN.TexCoordProj[0].w < 0.0)		{   			//We do not modify the projection at all if we are the opposite direction from it.			finalColor += 0.1;		}		else		{

This topic is closed to new replies.

Advertisement