Skip to main content
GameDev.net gamedev.net
🔒 Locked

Porting assembly to HLSL help

Started by helix Dec 18, 2004 at 6:06 PM 6 replies 3.7k views
Original Post
helix
helix
A few months ago I ported the shaders in ATI's grass sample (http://mirror.ati.com/developer/samples/grass.html) from their assembly implementation to HLSL (using a DX effect). I got it working perfectly and was very happy with it. But now I lost that effect file somehow (I've scoured EVERYWHERE!). :( I have re-ported it over but it doesn't seem to work right now and I can't find a problem. Instead of the nice looking windblown sinusoidal motion like in ATI's demo (that my original port also showed), the grass quads now cycle about 180 degrees and stretch out at the extents of the motion. Can someone look over my code and see if they can find a flaw? Any possible optimizations are welcomed as well. Thanks in advance. I have the original assembly commented out above my port of that section.

void RenderGrassVS( float4 vPos	: POSITION,
		    float3 vTex	: TEXCOORD0,
			out float4 oPos	: POSITION,
			out float4 oColor : COLOR0,
			out float3 oTex	: TEXCOORD0 )
{
	// use vertex pos x and y as inputs to sinusoidal warp 
//	mul r0, c14, v0.x	//float4 r0 = g_vWaveDirX * vPos.x;
//	mad r0, c15, v0.y, r0	//r0 = (g_vWaveDirY * vPos.y) + r0;
	float4 vWaveVec = (g_vWaveDirX * vPos.x) + (g_vWaveDirY * vPos.y);

//	mov r1, c1.x		// get current time

	// add scaled time to move bumps according to speed
//	mad r0, r1, c16, r0	//r0 = (g_fTime * g_vWaveSpeed) + r0;
	vWaveVec += g_fTime * g_vWaveSpeed;

	// take frac of all 4 components
//	frc r0.xy, r0		//r0.xy = frac( r0 );
//	frc r1.xy, r0.zwzw	//float4 r1; r1.xy = frac( r0.zwzw );
//	mov r0.zw, r1.xyxy	//r0.zw = r1.xyxy;
	vWaveVec = frac( vWaveVec );

	// multiply by fixup factor (due to inaccuracy of taylor series) and subtract by 0.5
//	mul r0, r0, c10.x	//r0 = r0 * g_fFixupFactor;
//	sub r0, r0, c0.y	//r0 = r0 - 0.5f;
	vWaveVec *= g_fFixupFactor;
	vWaveVec -= 0.5f;

	// *=2pi coords range from (-pi to pi)
//	mul r1, r0, c17.w	//r1 = r0 * g_fPIx2;
	vWaveVec *= g_fPIx2;	// pi * 2.0

	// Find the following powers of the wave vec
//	mul r2, r1, r1        // (wave vec)^2	//float4 r2 = r1 * r1;
	float4 vWaveVecPow2 = vWaveVec * vWaveVec;
//	mul r3, r2, r1        // (wave vec)^3	//float4 r3 = r2 * r1;
	float4 vWaveVecPow3 = vWaveVecPow2 * vWaveVec;
//	mul r5, r3, r2        // (wave vec)^5	//float4 r5 = r3 * r2;
	float4 vWaveVecPow5 = vWaveVecPow3 * vWaveVecPow2;
//	mul r7, r5, r2        // (wave vec)^7 	//float4 r7 = r5 * r2;
	float4 vWaveVecPow7 = vWaveVecPow5 * vWaveVecPow2;
//	mul r9, r7, r2        // (wave vec)^9	//float4 r9 = r7 * r2;
	float4 vWaveVecPow9 = vWaveVecPow7 * vWaveVecPow2;

	// Do the following operations	   
//	mad r0, r3, c8.x, r1  //(wave vec) - ((wave vec)^3)/3!	//r0 = (r3 * g_vSine9.x) + r1;
//	mad r0, r5, c8.y, r0  //  + ((wave vec)^5)/5!	//r0 = (r5 * g_vSine9.y) + r0;
//	mad r0, r7, c8.z, r0  //  - ((wave vec)^7)/7!	//r0 = (r7 * g_vSine9.z) + r0;
//	mad r0, r9, c8.w, r0  //  - ((wave vec)^9)/9!	//r0 = (r9 * g_vSine9.w) + r0;
	vWaveVec += vWaveVecPow3 * g_vSine9.x;
	vWaveVec += vWaveVecPow5 * g_vSine9.y;
	vWaveVec += vWaveVecPow7 * g_vSine9.z;
	vWaveVec += vWaveVecPow9 * g_vSine9.w;

	// Find the wave distortions
//	dp4 r3.x, r0, c11	//r3.x = dot( r0, g_vWaveDistortX );
//	dp4 r3.y, r0, c12	//r3.y = dot( r0, g_vWaveDistortY );
//	dp4 r3.zw, r0, c13	//r3.zw = dot( r0, g_vWaveDistortZ );
	float4 vWaveDistortion;
	vWaveDistortion.x = dot( vWaveVec, g_vWaveDistortX );
	vWaveDistortion.y = dot( vWaveVec, g_vWaveDistortY );
	vWaveDistortion.zw = dot( vWaveVec, g_vWaveDistortZ );

	// attenuate sinusoidal warping by (1-tex0.y)^2
//	sub r4, c0.z, v7.y	//float4 r4 = 1.0f - vTex.y;
//	mul r4, r4, r4		//r4 = r4 * r4;
//	mul r3, r3, r4		//r3 = r3 * r4;
	float fSinWarp = 1.0f - vTex.y;
	fSinWarp *= fSinWarp;
	vWaveDistortion *= fSinWarp;

	// Out position -- add sinusoidal warping to grass position
//	mov r2.w, v0		//r2.w = 1.0f;
//	add r2.xyz, r3, v0	//r2.xyz = r3 + vPos;
//	m4x4 oPos, r2, c4	//oPos = mul( r2, g_mWorldViewProjection );
	float4 vGrassPos;
	vGrassPos.xyz = vWaveDistortion + vPos;
	vGrassPos.w = 1.0f;
	oPos = mul( vGrassPos, g_mWorldViewProjection );

	// scale and add sin waves together
	// scale and bias color values (green is scaled more 
	// than red and blue)
//	dp4  r1.x, r0, c18	//r1.x = dot( r0, g_vLightingWaveScale );
//	mad  oD0, c19.xzxz, -r1.x, c19.y	//oColor = (g_vLightingScaleBias.xzxz * -r1.x) + g_vLightingScaleBias.y;
	float fScaled = dot( vWaveVec, g_vLightingWaveScale );
	oColor = (g_vLightingScaleBias.xzxz * -fScaled) + g_vLightingScaleBias.y;

	// Pass the tex coord through	
//	mov  oT0, v7
	oTex = vTex;
}

Here are the constants I used:

float4	g_vSine9 = float4( -0.16161616f, 0.0083333f, -0.00019841f, 0.000002755731f );
float4	g_fFixupFactor = 1.07f;
float4	g_vWaveDistortX = float4( 3.0f, 0.4f, 0.0f, 0.3f );
float4	g_vWaveDistortY = float4( 3.0f, 0.4f, 0.0f, 0.3f );
float4	g_vWaveDistortZ = float4( -1.0f, -0.133f, -0.333f, -0.10f );
float4	g_vWaveDirX = float4( -0.006f, -0.012f, 0.024f, 0.048f );
float4	g_vWaveDirY = float4( -0.003f, -0.006f, -0.012f, -0.048f );
float4	g_vWaveSpeed = float4( 0.3f, 0.6f, 0.7f, 1.4f );
float	g_fPIx2 = 6.28318530f;
float4	g_vLightingWaveScale = float4( 0.35f, 0.10f, 0.10f, 0.03f );
float4	g_vLightingScaleBias = float4( 0.6f, 0.7f, 0.2f, 0.0f );

Here is ATI's description of the shader: The waving motion of the grass can be accomplished in the vertex shader. Using a traditional method the grass is rendered with randomly placed intersecting quads stored in a single vertex buffer. The quads are texture mapped and rendered with an alpha test. In the vertex shader, the top two vertices of each quad are animated using a combination of four sinusoidal waves. The waves are approximated using a Taylor Series approach. This combination of sine waves using various different frequencies creates a natural waving that does not look like an animation or overly repetitious. [Edited by - beoch on December 18, 2004 6:32:41 PM]
Mastaba
Mastaba
Wouldn't it make more sense to just eliminate the taylor series approximation and use the sin function explicitly since HLSL supports it?
helix
helix
I don't doubt that would be the best approach but I don't understand the algorithm at all since it's got nothing more than a high level description. I can't really follow what's going on probably because I never learned about any Taylor series approximation business... I do understand (at least somewhat) how to port it. Can you give me an equation or something to run with? I'd love to try to implement it but I don't really know where to start. Thanks!
helix
helix
Ok, I think I sucessfully took out the Taylor approximation and replaced it with the sin intrinisic.

// Find the following powers of the wave vec//	mul r2, r1, r1        // (wave vec)^2		//float4 r2 = r1 * r1;	float4 vWaveVecPow2 = vWaveVec * vWaveVec;//	mul r3, r2, r1        // (wave vec)^3		//float4 r3 = r2 * r1;	float4 vWaveVecPow3 = vWaveVecPow2 * vWaveVec;//	mul r5, r3, r2        // (wave vec)^5		//float4 r5 = r3 * r2;	float4 vWaveVecPow5 = vWaveVecPow3 * vWaveVecPow2;//	mul r7, r5, r2        // (wave vec)^7 		//float4 r7 = r5 * r2;	float4 vWaveVecPow7 = vWaveVecPow5 * vWaveVecPow2;//	mul r9, r7, r2        // (wave vec)^9		//float4 r9 = r7 * r2;	float4 vWaveVecPow9 = vWaveVecPow7 * vWaveVecPow2;	// Do the following operations	   //	mad r0, r3, c8.x, r1  // (wave vec) - ((wave vec)^3)/3!		//r0 = (r3 * g_vSine9.x) + r1;//	mad r0, r5, c8.y, r0  //  + ((wave vec)^5)/5!		//r0 = (r5 * g_vSine9.y) + r0;//	mad r0, r7, c8.z, r0  //  - ((wave vec)^7)/7!		//r0 = (r7 * g_vSine9.z) + r0;//	mad r0, r9, c8.w, r0  //  - ((wave vec)^9)/9!		//r0 = (r9 * g_vSine9.w) + r0;	vWaveVec += vWaveVecPow3 * g_vSine9.x;	vWaveVec += vWaveVecPow5 * g_vSine9.y;	vWaveVec += vWaveVecPow7 * g_vSine9.z;	vWaveVec += vWaveVecPow9 * g_vSine9.w;//	vWaveVec = ((vWaveVecPow3 * g_vSine9.x) + vWavePi) + (vWaveVecPow5 * g_vSine9.y) + (vWaveVecPow7 * g_vSine9.z) + (vWaveVecPow9 * g_vSine9.w);


The above code was all replaced with:
vWaveVec = sin( vWaveVec );

But my original problem still remains. Instead of looking windblown, the quads cycle from a very stretched out extent to its mirrored equivalent. It travels from one extent to the other in a nice smooth and perterbed manner however...
Mastaba
Mastaba
How is each patch of grass being drawn? Are you using a single quad per patch of grass? If so, that could explain the problem.
helix
helix
Yes, each grass patch is a single quad. How would that be a problem? That's how ATI did it in their sample. What would you suggest as a better solution?
helix
helix
I swapped my shader code for another that has the correct "windblown" behavior and the problem persists. Furthermore, I put my shader in EffectEdit and it looks correct. Yet in my engine, it's very much not correct. So now I'm convinced my shader works so what could be my problem? What would cause it to not behave?

arrrgh!!
Mastaba
Mastaba
Each patch should be composed of multiple quads stacked on top of each other in the y direction so that the intermediate y coordinates get distorted less. The way you have it now sounds like the bottom vertices aren't distored at all and the top ones are, thus producing the shearing effect. You need intermediate y values so that intermediate values produce the bend by being distorted less than the top vertices.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.