Bump mapping in skinned shaders
Hi
I was trying to implement the unified bump mapping described in the paper below, whereby the normal map normal is multiplied by the inverse of the tangent space matrix, then by the world matrix.
The trouble is, in skinned shaders the world matrix is not constant; I'm not convinced that reskinning every single pixel to get its world matrix is a good solution.
http://www.gamasutra.com/features/20050729/lacroix_pfv.htm
Really what I want to end up with is the world space normal so I can do lighting and reflection.
Thank you!
btw I found this way of offsetting the normal along the tangent and binormal, but I don't think that is proper bump mapping.
...but if it looks good...I give it a go...
...but if it looks good...I give it a go...
Hey
I think this (NVidia's BumpReflectHLSL.fx in their SDK) is what I'm looking for:
I think this (NVidia's BumpReflectHLSL.fx in their SDK) is what I'm looking for:
///////////////// vertex shader //////////////////v2f BumpReflectVS(a2v IN, uniform float4x4 WorldViewProj, uniform float4x4 World, uniform float4x4 ViewIT){ v2f OUT; // Position in screen space. OUT.Position = mul(IN.Position, WorldViewProj); // pass texture coordinates for fetching the normal map OUT.TexCoord.xyz = IN.TexCoord; OUT.TexCoord.w = 1.0; // compute the 4x4 tranform from tangent space to object space float3x3 TangentToObjSpace; // first rows are the tangent and binormal scaled by the bump scale TangentToObjSpace[0] = float3(IN.Tangent.x, IN.Binormal.x, IN.Normal.x); TangentToObjSpace[1] = float3(IN.Tangent.y, IN.Binormal.y, IN.Normal.y); TangentToObjSpace[2] = float3(IN.Tangent.z, IN.Binormal.z, IN.Normal.z); OUT.TexCoord1.x = dot(World[0].xyz, TangentToObjSpace[0]); OUT.TexCoord1.y = dot(World[1].xyz, TangentToObjSpace[0]); OUT.TexCoord1.z = dot(World[2].xyz, TangentToObjSpace[0]); OUT.TexCoord2.x = dot(World[0].xyz, TangentToObjSpace[1]); OUT.TexCoord2.y = dot(World[1].xyz, TangentToObjSpace[1]); OUT.TexCoord2.z = dot(World[2].xyz, TangentToObjSpace[1]); OUT.TexCoord3.x = dot(World[0].xyz, TangentToObjSpace[2]); OUT.TexCoord3.y = dot(World[1].xyz, TangentToObjSpace[2]); OUT.TexCoord3.z = dot(World[2].xyz, TangentToObjSpace[2]); float4 worldPos = mul(IN.Position, World); // compute the eye vector (going from shaded point to eye) in cube space float4 eyeVector = worldPos - ViewIT[3]; // view inv. transpose contains eye position in world space in last row. OUT.TexCoord1.w = eyeVector.x; OUT.TexCoord2.w = eyeVector.y; OUT.TexCoord3.w = eyeVector.z; return OUT;}///////////////// pixel shader //////////////////float4 BumpReflectPS(v2f IN, uniform sampler2D NormalMap, uniform samplerCUBE EnvironmentMap, uniform float BumpScale) : COLOR{ // fetch the bump normal from the normal map float3 normal = tex2D(NormalMap, IN.TexCoord.xy).xyz * 2.0 - 1.0; normal = normalize(float3(normal.x * BumpScale, normal.y * BumpScale, normal.z)); // transform the bump normal into cube space // then use the transformed normal and eye vector to compute a reflection vector // used to fetch the cube map // (we multiply by 2 only to increase brightness) float3 eyevec = float3(IN.TexCoord1.w, IN.TexCoord2.w, IN.TexCoord3.w); float3 worldNorm; worldNorm.x = dot(IN.TexCoord1.xyz,normal); worldNorm.y = dot(IN.TexCoord2.xyz,normal); worldNorm.z = dot(IN.TexCoord3.xyz,normal); float3 lookup = reflect(eyevec, worldNorm); return texCUBE(EnvironmentMap, lookup);}
I hardcoded the normal from the bump map to be (0,1,0) and rendered the normal as color, expecting to get my original normal. However, I didn't :(
Can some genius work out what's going wrong please; here's my shader code (simplified):
Thank you ever so much!
[Edited by - DrGUI on April 16, 2006 11:25:43 AM]
Can some genius work out what's going wrong please; here's my shader code (simplified):
Pixel_VSOutput TnLPixelVS(const in a2v IN PARAM_NUMBERBONES){ Pixel_VSOutput Out; //Skin inputs float4x3 worldMatrix; SKIN_MATRIX(worldMatrix) // compute the tranform from tangent space to object space float3x3 TangentToObjSpace; float3 binormal = cross(IN.Tan, IN.Nor); TangentToObjSpace[0] = float3(IN.Tan.x, binormal.x, IN.Nor.x); TangentToObjSpace[1] = float3(IN.Tan.y, binormal.y, IN.Nor.y); TangentToObjSpace[2] = float3(IN.Tan.z, binormal.z, IN.Nor.z); Out.TexCoord1.x = dot(worldMatrix[0].xyz, TangentToObjSpace[0]); Out.TexCoord1.y = dot(worldMatrix[1].xyz, TangentToObjSpace[0]); Out.TexCoord1.z = dot(worldMatrix[2].xyz, TangentToObjSpace[0]); Out.TexCoord2.x = dot(worldMatrix[0].xyz, TangentToObjSpace[1]); Out.TexCoord2.y = dot(worldMatrix[1].xyz, TangentToObjSpace[1]); Out.TexCoord2.z = dot(worldMatrix[2].xyz, TangentToObjSpace[1]); Out.TexCoord3.x = dot(worldMatrix[0].xyz, TangentToObjSpace[2]); Out.TexCoord3.y = dot(worldMatrix[1].xyz, TangentToObjSpace[2]); Out.TexCoord3.z = dot(worldMatrix[2].xyz, TangentToObjSpace[2]); float3 worldPos = mul(float4(IN.Pos,1), worldMatrix); // compute the eye vector (going from shaded point to eye) in world space float3 eyeVector = Eye - worldPos; Out.TexCoord1.w = eyeVector.x; Out.TexCoord2.w = eyeVector.y; Out.TexCoord3.w = eyeVector.z; Out.Pos = mul(float4(worldPos, 1), ViewProjection); Out.Tex0 = IN.Tex0; return Out;}float4 TnLPixelPS(const in float2 tex0 : TEXCOORD0, const in float4 tex1 : TEXCOORD1, const in float4 tex2 : TEXCOORD2, const in float4 tex3 : TEXCOORD3, uniform bool includeEnvironmentHigh) : COLOR{ //Get the bumped normal //float3 bumpN = tex2D(BumpSampler, tex0).xyz * 2.0 - 1.0; float3 bumpN = float3(0,1,0); //bumpN = normalize(float3(bumpN.x * BumpScale, bumpN.y * BumpScale, bumpN.z)); //transform the bump normal into world space float3 worldNorm; worldNorm.x = dot(tex1.xyz, bumpN); worldNorm.y = dot(tex2.xyz, bumpN); worldNorm.z = dot(tex3.xyz, bumpN); //get the packed VtoE vector out - snip, that's fine worldNorm = normalize(worldNorm); return float4(worldNorm, 1);}
Thank you ever so much!
[Edited by - DrGUI on April 16, 2006 11:25:43 AM]
This works:
but it does use more instructions
//Uses interpolated vertexToEye vector as this does not change much over verticesfloat4 TnLPixelPS(const in float2 tex0 : TEXCOORD0, const in float3 nor : TEXCOORD1, const in float3 tan : TEXCOORD2, const in float3 vertexToEye : TEXCOORD3, uniform bool includeEnvironmentHigh) : COLOR{ //Normalize interpolated float3 N = normalize(nor); float3 T = normalize(tan); float3 VtoE = normalize(vertexToEye); //Get the bumped normal float3 bumpN = tex2D(BumpSampler, tex0).xyz * 2.0 - 1.0; bumpN = float3(bumpN.x * BumpScale, bumpN.y * BumpScale, bumpN.z); //Construct binormal float3 B = cross(T, N); //transform the bump normal into world space float3 worldNorm = normalize(T * bumpN.x + B * bumpN.y + N * bumpN.z); float3 reflection = reflect(-VtoE, worldNorm); float4 envReflection = GetEnvironmentReflection(reflection, includeEnvironmentHigh); //Calculate the lighting float4 diffuse; float4 specular; ComputeColorDS(worldNorm, VtoE, diffuse, specular); //Apply the diffuse map float4 color = lerp(float4(SampleBaseTexture(tex0).rgb, 1) * diffuse + specular, envReflection, Reflectance); color.a = Visibility; return color;}
but it does use more instructions
I constructed the matrix differently in the VS and yay it works!
Pixel_VSOutput TnLPixelVS(const in a2v IN PARAM_NUMBERBONES){ Pixel_VSOutput Out; //Skin inputs float3 P; float3 N; float3 T; SKIN_POINT_2VEC(float4(IN.Pos, 1), IN.Nor, IN.Tan, P, N, T) N = normalize(N); T = normalize(T); float3 B = cross(T, N); float3 VtoE = Eye - P; //normalize this in PS Out.TexCoord1 = float4(T.x, B.x, N.x, VtoE.x); Out.TexCoord2 = float4(T.y, B.y, N.y, VtoE.y); Out.TexCoord3 = float4(T.z, B.z, N.z, VtoE.z); Out.Pos = mul(float4(P, 1), ViewProjection); Out.Tex0 = IN.Tex0; return Out;}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement