How to rotate the texture coordinate in the HLSL

Started by
3 comments, last by ITboy_Lemon 10 years, 5 months ago

These days , I have read the <Intruduction to the 3D Game Programming with DirectX 9.0c : A shader Approach> . And when I do the exercise in the Chapter 11 Texture , I come across a problem . I want to rotate the texture coordinate to do the texture animation in the Flare.fx file .

Here is my code :


//-------------------------------------------------------------------------------------
// declaration	: Copyright (c) , 2013 , XJ . All right reserved .
// brief	: This effect file make a flare effect .
// author	: XJ
// file		: Flare.fx
// data		: 2013 / 10 / 27
//--------------------------------------------------------------------------------------

//define the global variant
uniform extern float4x4 gWVP ;
uniform extern float	gRotationFlare ;
uniform extern float	gRotationBlend ;
uniform extern texture	gTexFlare ;
uniform extern texture  gTexBlend ;

//define the OutputVS
struct OutputVS
{
	float4 posH: POSITION0 ;
	float2 tex: TEXCOORD0 ;
	float4 rotationFlare: COLOR0 ;
	float4 rotationBlend: COLOR1 ;
};

//define the sampler
sampler BlendTex = sampler_state
{
	Texture = <gTexBlend> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
};

sampler FlareTex = sampler_state
{
	Texture = <gTexFlare> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
};

//define the Vertex Shader
OutputVS FlareVS(float3 posL: POSITION0, float2 tex: TEXCOORD0)
{
	//Zero out the OutputVS
	OutputVS outVS = (OutputVS) 0 ;

	//Transform the local position to the homogenous clip space
	outVS.posH = mul(float4(posL, 1.0f), gWVP);
	outVS.tex = tex ;
	
	//Compute the 2x2 matrix
	float cosf = cos(gRotationFlare) ;
	float sinf = sin(gRotationFlare) ;
	float4 rotation = float4(cosf,-sinf,sinf,cosf);
	outVS.rotationFlare = rotation ;

	cosf = cos(gRotationBlend);
	sinf = sin(gRotationBlend);
	rotation = float4(cosf,-sinf,sinf,cosf);
	outVS.rotationBlend = rotation ;

	//Done
	return outVS ;
}

//define the Pixel Shader
float4 FlarePS(float2 tex: TEXCOORD0, float4 rotationFlare:COLOR0, float4 rotationBlend:COLOR) : COLOR
{
	float2 flare_tex = tex ;
	float2 blend_tex = tex ;

	//Translate the texture coordinate
	flare_tex -= 0.5f ;
	blend_tex -= 0.5f ;

	//Rotate the texture coordinate
	flare_tex = mul(flare_tex, float2x2(rotationFlare));
	blend_tex = mul(blend_tex, float2x2(rotationBlend));

	//Translate the texture coordinate
	flare_tex += 0.5f ;
	blend_tex += 0.5f ;
	
	//Do some logic and get the texl color
	float3 flare = (float3)0  ;
	if(flare_tex.x < 0 || flare_tex.x > 1 || flare.y < 0 || flare.y > 1)
	{
		flare = float3(0.0f, 0.0f, 0.0f);
	}
	else
	{
		flare = tex2D(FlareTex, flare_tex).rgb ;	
	}

	float3 blend = (float3) 0 ;
	if(blend_tex.x < 0 || blend_tex.x > 1 || blend_tex.y < 0 || blend_tex.y > 1)
	{
		blend = float3(0.0f, 0.0f, 0.0f);
	}
	else
	{
		blend = tex2D(BlendTex, blend_tex).rgb ;
	}
	
	//Done.
	return float4(flare*blend, 1.0f);
}

//define the technique
technique FlareTech
{
	pass P0
	{
		vertexShader = compile vs_2_0 FlareVS();
		pixelShader  = compile ps_2_0 FlarePS();
	}
}



This file will do the multi-texturing and rotate the texture code in the cube object .
Here is the problem , some time , the texture will be stretched not be rotated .Just like this :
[attachment=18574:QQ??20131028144534.jpg]

but actually , the real effect I want to get is this :

[attachment=18575:QQ??20131028142939.jpg]

just rotate the multi-textured texture , not stretched one .

So , is there anybody who can save me ?

Advertisement

What are you doing?

rotationFlare is nonsense. If you need to transform a texcoord, just transform it in the VS. No need to pass it in the PS. Personally, I would just upload the matrix from CPU, but if you want to compute in VS... that might be good in certain situations.

You are doing significantly odd things. You pass a 2D texcoord so it can be assigned to both flare_tex and blend_tex, displace those values by -0.5, transform by rotationFlare (instead of just passing two texcoords, which would take the same number of interpolators), then add +0.5, which I'm pretty sure doesn't do what you expect.

Last but not least, you clamp texcoords in the PS, instead of just setting up your texture fetching correctly.

My suggestion? Don't fix this shader. Check your theory again, then write another one.

Previously "Krohm"

I get your idea . Here is my second Flare.fx :


//-------------------------------------------------------------------------------------
// declaration	: Copyright (c) , 2013 , XJ . All right reserved .
// brief	: This effect file make a flare effect .
// author	: XJ
// file		: Flare.fx
// data		: 2013 / 10 / 27
//--------------------------------------------------------------------------------------

//define the global variant
uniform extern float4x4 gWVP ;
uniform extern float	gRotationFlare ;
uniform extern float	gRotationBlend ;
uniform extern texture	gTexFlare ;
uniform extern texture  gTexBlend ;

//define the OutputVS
struct OutputVS
{
	float4 posH: POSITION0 ;
	float2 texFlare: TEXCOORD0 ;
	float2 texBlend: TEXCOORD1 ;
};

//define the sampler
sampler BlendTex = sampler_state
{
	Texture = <gTexBlend> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
};

sampler FlareTex = sampler_state
{
	Texture = <gTexFlare> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
	AddressV = CLAMP ;
	AddressU = CLAMP ;
};

//define the Vertex Shader
OutputVS FlareVS(float3 posL: POSITION0, float2 tex: TEXCOORD0)
{
	//Zero out the OutputVS
	OutputVS outVS = (OutputVS) 0 ;

	//Transform the local position to the homogenous clip space
	outVS.posH = mul(float4(posL, 1.0f), gWVP);
	outVS.texFlare = tex ;
	outVS.texBlend = tex ;

	outVS.texFlare.x -= 0.5 ;
	outVS.texBlend.x -= 0.5 ;
	
	outVS.texFlare.y = -outVS.texFlare.y ;
	outVS.texFlare.y += 0.5f ;
	outVS.texBlend.y = -outVS.texBlend.y ;
	outVS.texBlend.y +=  0.5f ;

	outVS.texFlare.x = outVS.texFlare.x*cos(gRotationFlare) - outVS.texFlare.y*sin(gRotationFlare) ;
	outVS.texFlare.y = outVS.texFlare.x*sin(gRotationFlare) + outVS.texFlare.y*cos(gRotationFlare) ;
	outVS.texBlend.x = outVS.texBlend.x*cos(gRotationBlend) - outVS.texBlend.y*sin(gRotationBlend) ;
	outVS.texBlend.y = outVS.texBlend.x*sin(gRotationBlend) - outVS.texBlend.y*cos(gRotationBlend) ;
	

	outVS.texFlare.x += 0.5f ; outVS.texBlend.x += 0.5f ;
	outVS.texFlare.y -= 0.5f ; outVS.texFlare.y = -outVS.texFlare.y ;
	outVS.texBlend.y -= 0.5f ; outVS.texBlend.y = -outVS.texBlend.y ;

	//Done
	return outVS ;
}

//define the Pixel Shader
float4 FlarePS(float2 texFlare: TEXCOORD0, float2 texBlend : TEXCOORD1) : COLOR
{
	//Get the texl
	float3 blend = tex2D(FlareTex, texFlare).rgb;
	float3 flare = tex2D(BlendTex, texBlend).rgb;

	//Caculate the final color
	float3 color = blend * flare ;

	//Done
	return float4(color, 1.0f);
}

//define the technique
technique FlareTech
{
	pass P0
	{
		vertexShader = compile vs_2_0 FlareVS();
		pixelShader  = compile ps_2_0 FlarePS();
	}
}


But the same result . Here is the question of this demo :

In this chapter's demo directory there are two textures, as shown in the left and middle images of Figure 11.20. Use multi-texturing to combine them together to produce the image at the right in Figure 11.20. In addition, animate the flare by rotating it as a function of time (rotate the color and grayscale textures at different rates). Display the resultant texture on each face of a cube. (Hint: The center in texture coordinates is not the origin; it is (1/2, 1/2), and thus the rotation will be off because the rotation equations rotate about (0, 0). Therefore, you will need to first translate the texture coordinates so that the center is at the origin, apply the rotation transformation, and then translate back so that the center is back at (1/2, 1/2) for texturing.)

I follow the advice of the exercise , but i do not understand why is the same result as before .

Can you help me ?

To rotate and translate 2D points (cleanly), you'll need a 3x3 matrix. Not a 2x2. Just stop a moment. After you do that thing with a lot of cos and sin (which you could do in a single line with a single matrix multiply instruction) you cannot ad +0.5 like that because this +.5 value is in the original space. Not in the rotated space.

Why is this the same as the previous? To be honest, I'm surprised you ended up with the same thing, considering you now add .5 to only .x or .y components but if you track the various operations (use a sheet of paper!) you will see the signs propagate in the same way.

That thing with lots of cos and sin was previously in the pixel shader using mul instead. And after those two mul operations, you still offset by an untransformed (.5, .5) value. Now those operations are gone, replaced with other blind additions having the same problem: they are in the untransformed coordinate system!

Previously "Krohm"

Thank you for your patience. Here is my new Flare.fx , and it works now , but I still have some questions.


//-------------------------------------------------------------------------------------
// declaration	: Copyright (c) , 2013 , XJ . All right reserved .
// brief	: This effect file make a flare effect .
// author	: XJ
// file		: Flare.fx
// data		: 2013 / 10 / 27
//--------------------------------------------------------------------------------------

//define the global variant
uniform extern float4x4 gWVP ;
uniform extern float	gRotationFlare ;
uniform extern float	gRotationBlend ;
uniform extern texture	gTexFlare ;
uniform extern texture  gTexBlend ;

//define the OutputVS
struct OutputVS
{
	float4 posH: POSITION0 ;
	float2 texFlare: TEXCOORD0 ;
	float2 texBlend: TEXCOORD1 ;
};

//define the sampler
sampler BlendTex = sampler_state
{
	Texture = <gTexBlend> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
	AddressV = WRAP ;
	AddressU = WRAP ;
};

sampler FlareTex = sampler_state
{
	Texture = <gTexFlare> ;
	MinFilter = LINEAR ;
	MagFilter = LINEAR ;
	MipFilter = LINEAR ;
	AddressV = WRAP ;
	AddressU = WRAP ;
};

//define the Vertex Shader
OutputVS FlareVS(float3 posL: POSITION0, float2 tex: TEXCOORD0)
{
	//Zero out the OutputVS
	OutputVS outVS = (OutputVS) 0 ;

	//Transform the local position to the homogenous clip space
	outVS.posH = mul(float4(posL, 1.0f), gWVP);
	outVS.texFlare = tex ;
	outVS.texBlend = tex ;

	outVS.texFlare -= 0.5 ;
	outVS.texBlend -= 0.5 ;
	
	float cFlare = cos(gRotationFlare);
	float sFlare = sin(gRotationFlare);
	float cBlend = cos(gRotationBlend);
	float sBlend = sin(gRotationBlend);

	outVS.texFlare = mul(outVS.texFlare, float2x2(cFlare,-sFlare,sFlare, cFlare));
	outVS.texBlend = mul(outVS.texBlend, float2x2(cBlend, -sBlend, sBlend, cBlend));
	
	outVS.texFlare += 0.5f ; 
	outVS.texBlend += 0.5f ;

	//Done
	return outVS ;
}

//define the Pixel Shader
float4 FlarePS(float2 texFlare: TEXCOORD0, float2 texBlend : TEXCOORD1) : COLOR
{
	//Get the texl
	float3 blend = tex2D(FlareTex, texFlare).rgb;
	float3 flare = tex2D(BlendTex, texBlend).rgb;

	//Caculate the final color
	float3 color = blend * flare ;

	//Done
	return float4(color, 1.0f);
}

//define the technique
technique FlareTech
{
	pass P0
	{
		vertexShader = compile vs_2_0 FlareVS();
		pixelShader  = compile ps_2_0 FlarePS();
	}
}

Here are my questions :

1. I did not use the 3x3 matrix , is there something wrong , or pitfall with the 2x2 ?

2. I still use the same theory as the first Flare.fx , which means I do the translate with - 0.5 and rotate the texture coordinate ,at the end I translate the texture coordinate with + 0.5 . I did not transform it in the rotation coordinate system as you metioned , is there something wrong with it ?

Thank you again !!!

This topic is closed to new replies.

Advertisement