SongOfTheWeave
08-04-2008 11:32:52
Okay, I've gotten some decent looking normal mapping working on the terrain.
While it works, some of it is stupid. However, I'm not entirely sure how to go about improving it. I would very much appreciate a code review on these shaders.
I've diverged significantly from the Dot3Bump example on the wiki because... well, it seemed ridiculous. It had some cubic texture that was strange gradients and I didn't see what that had to do with me, so I dropped it entirely and did it this way. And, as I mentioned, it works, but I am highly suspicious that I'm doing (a lot?) more work than is neccessary in certain spots.
I also suspect that a good number of the calculations could be moved into the vertex shader with negligible impact on the perceived effect, however, it seems that whenever I move one thing, I end up having to move everything else.
I'm looking for input and critique here.
Oh! And feel free to use my shaders (though you might want to wait until we get some good input to improve them a touch first hehe.)
Thanks guys!
[edit] P.S. I've added code to ETM to generate tangents and binormals in case you're wondering where those came from. In interests of full disclosure, I will post my additions to ETM at a later date, and in another thread. [/edit]
Vertex Shader:
Pixel Shader:
Declarations:
Material (omitting fallback technique as this post is TMI already):
While it works, some of it is stupid. However, I'm not entirely sure how to go about improving it. I would very much appreciate a code review on these shaders.
I've diverged significantly from the Dot3Bump example on the wiki because... well, it seemed ridiculous. It had some cubic texture that was strange gradients and I didn't see what that had to do with me, so I dropped it entirely and did it this way. And, as I mentioned, it works, but I am highly suspicious that I'm doing (a lot?) more work than is neccessary in certain spots.
I also suspect that a good number of the calculations could be moved into the vertex shader with negligible impact on the perceived effect, however, it seems that whenever I move one thing, I end up having to move everything else.
I'm looking for input and critique here.
Oh! And feel free to use my shaders (though you might want to wait until we get some good input to improve them a touch first hehe.)
Thanks guys!
[edit] P.S. I've added code to ETM to generate tangents and binormals in case you're wondering where those came from. In interests of full disclosure, I will post my additions to ETM at a later date, and in another thread. [/edit]
Vertex Shader:
void ETDynLighting_vp
(
float4 position : POSITION,
float3 normal : NORMAL,
float3 tangent : TANGENT,
float2 uv : TEXCOORD0,
float delta : BLENDWEIGHT,
uniform float4 lightPosition,
uniform float3 eyePosition,
uniform float4x4 worldviewproj,
uniform float morphFactor,
out float4 oWorldPos : POSITION,
out float2 oUV : TEXCOORD0,
out float4 oPos : TEXCOORD1,
out float3 oNorm : TEXCOORD2,
out float4 oLightPos : TEXCOORD3,
out float3 oEyePos : TEXCOORD4,
out float3 oTangent : TEXCOORD5
)
{
position.y = position.y + (delta.x * morphFactor);
oPos = position;
oWorldPos = mul(worldviewproj, position);
oUV = uv;
oNorm = normal;
oLightPos = lightPosition;
oEyePos = eyePosition;
oTangent = tangent;
}
Pixel Shader:
void ETDynLighting_fp
(
float2 uv : TEXCOORD0,
float4 position : TEXCOORD1,
float3 normal : TEXCOORD2,
float4 lightPos : TEXCOORD3,
float3 eyePos : TEXCOORD4,
float3 tangent : TEXCOORD5,
uniform sampler2D covMap1,
uniform sampler2D covMap2,
uniform sampler2D splat1,
uniform sampler2D splat2,
uniform sampler2D splat3,
uniform sampler2D splat4,
uniform sampler2D splat5,
uniform sampler2D splat6,
uniform float splatScaleX,
uniform float splatScaleZ,
uniform float4 lightDiffuse,
uniform float4 lightSpecular,
uniform float exponent,
uniform float4 ambient,
out float4 oColor : COLOR
)
{
float3 cov1 = tex2D(covMap1, uv).rgb;
float3 cov2 = tex2D(covMap2, uv).rgb;
uv.x *= splatScaleX;
uv.y *= splatScaleZ;
float3 normModifier = tex2D(splat1, uv) * cov1.x
+ tex2D(splat2, uv) * cov1.y
+ tex2D(splat3, uv) * cov1.z
+ tex2D(splat4, uv) * cov2.x
+ tex2D(splat5, uv) * cov2.y
+ tex2D(splat6, uv) * cov2.z;
normModifier = normModifier.xzy;
float3 binormal = cross(tangent, normal);
// Form a rotation matrix out of the vectors
float3x3 rotation = float3x3(tangent, binormal, normal);
normModifier = mul(rotation, normModifier);
normModifier = normalize(normModifier);
float3 EyeDir = normalize(eyePos - position.xyz);
float3 LightDir = lightPos.xyz - (position * lightPos.w);
float dist = length(LightDir);
// Normalize this way since we already found the magnitude
LightDir = LightDir / dist;
float3 HalfAngle = normalize(LightDir + EyeDir);
normal = normalize(normal);
normal = normal + normModifier;
normal = normalize(normal);
float NdotL = max(dot(LightDir, normal), 0.0);
float NdotH = max(dot(HalfAngle, normal), 0.0);
//float NdotL = max(dot(LightDir, normModifier), 0.0);
//float NdotH = max(dot(HalfAngle, normModifier), 0.0);
float4 Lit = lit(NdotL, NdotH, exponent);
oColor = lightDiffuse * Lit.y + lightSpecular * Lit.z + ambient;
// Taking the ambient component out here and doing an ambient pass first,
// then doing additive lighting passes looks like shit for some reason.
// Look into this later... this method only looks good with only 1 light.
//oColor = lightDiffuse * Lit.y + lightSpecular * Lit.z;
// Attenuation stuff. Probably put this in the vp if I ever go back to it
//float fLuminence = 1 / (atten.y + atten.z * dist + atten.w * dist * dist);
//oColor = ambient + (fLuminence * (lightDiffuse * Lit.y + lightSpecular * Lit.z));
//oColor = ambient + (fLuminence * (lightDiffuse * NdotL + lightSpecular * NdotH));
}
Declarations:
vertex_program ET/Programs/VSDynLighting cg
{
source ETDynLighting.cg
entry_point ETDynLighting_vp
profiles vs_1_1 arbvp1
default_params
{
param_named_auto lightPosition light_position_object_space 0
param_named_auto eyePosition camera_position_object_space
param_named_auto worldviewproj worldviewproj_matrix
param_named_auto morphFactor custom 77
}
}
fragment_program ET/Programs/PSDynLighting cg
{
source ETDynLighting.cg
entry_point ETDynLighting_fp
profiles ps_1_1 arbfp1
default_params
{
param_named_auto lightDiffuse light_diffuse_colour 0
param_named_auto lightSpecular light_specular_colour 0
param_named exponent float 33
param_named_auto ambient ambient_light_colour 0
//param_named_auto atten light_attenuation
}
}
Material (omitting fallback technique as this post is TMI already):
material ETTerrainMaterial
{
technique
{
// primary splatting technique, requires PS 2.0
pass Splatting
{
lighting off
vertex_program_ref ET/Programs/VSLodMorph2
{
}
fragment_program_ref ET/Programs/PSSplat2
{
param_named splatScaleX float 20
param_named splatScaleZ float 20
}
}
pass Lighting
{
scene_blend modulate
iteration once_per_light
vertex_program_ref ET/Programs/VSDynLighting
{
}
fragment_program_ref ET/Programs/PSDynLighting
{
param_named splatScaleX float 20
param_named splatScaleZ float 20
}
}
//Decal pass
pass Decal
{
lighting off
depth_bias 0.6 0.3
scene_blend alpha_blend
texture_unit
{
texture decalBase.png
}
}
}
}