Original Post
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. Here are the constants I used: 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]
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;
}
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 );