Bump mapping in skinned shaders

Started by
4 comments, last by DrGUI 18 years ago
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!
Advertisement
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...
Hey

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):
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:
//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