Can shaders interfere with each other?

jchmack

19-12-2008 06:12:07

I have 2 completely different meshes using 2 completely different shaders. When either is loaded separately the mesh looks fine. Lighting specularity everything. But once i load the other mesh the data becomes off. It looks as if it is changing the position of the light source.... Then when I delete the 2nd object from the scene everything is fine again.

I can provide both shaders if needed.

Without Character


With Character


If you look at the floor its gets a lot brighter. Its like it adds another light source or something.

Thanks for any help in advance guys.

Lioric

19-12-2008 18:55:30

Probably the order of rendering is being changed (within the same render queue) but this must not change the displayed result (only if the loaded object is changing some shader parameters)

Is the light count the same?

What kind of shaders, are they unified shaders?

jchmack

20-12-2008 02:08:29

I knew i should have just posted the all of the shaders in the first place. For the level I use the monster shader:

monster.material

material MonsterExample
{
receive_shadows off
transparency_casts_shadows off
technique Map #13
{
pass Map #14
{
ambient 0.698039 0.698039 0.698039 1
diffuse 0.698039 0.698039 0.698039 1
specular 0.898039 0.898039 0.898039 1 20
emissive 0 0 0 1
scene_blend one zero
depth_check on
depth_write on
depth_func less_equal
depth_bias 0 0
alpha_rejection always_pass 0
cull_hardware clockwise
cull_software back
lighting on
shading gouraud
polygon_mode solid
colour_write on
max_lights 8
start_light 0
iteration once

vertex_program_ref monster_vs
{
param_named_auto eyePosition camera_position_object_space
param_named_auto lightPosition0 light_position_object_space 0
//param_named scale float 2//orginal
param_named scale float 1
param_named_auto worldviewproj worldviewproj_matrix
}
fragment_program_ref monster_ps
{
param_named ambient float4 0 0 0 1
param_named_auto atten0 light_attenuation 0
param_named_auto lightDiffuse0 light_diffuse_colour 0

//param_named scaleBias float4 0.04 -0.02 1 0 //orginal
param_named scaleBias float4 0 0 0 1

//param_named exponent0 float 127
param_named exponent0 float 256

param_named_auto lightSpecular0 light_specular_colour 0
}

texture_unit Normal
{
texture Rockwall_NH.png 2d unlimited
binding_type fragment
tex_coord_set 0
tex_address_mode wrap wrap wrap
//tex_address_mode border border border
tex_border_colour 0 0 0 1
filtering trilinear
max_anisotropy 1
mipmap_bias 0
colour_op_ex modulate src_texture src_current 1 1 1 1 1 1 1
alpha_op_ex modulate src_texture src_current 1 1 1
colour_op_multipass_fallback one zero
env_map off

//scroll_anim 1 1
}

texture_unit Diffuse
{
texture Rockwall.png 2d unlimited
binding_type fragment
tex_coord_set 0
tex_address_mode wrap wrap wrap
//tex_address_mode border border border
tex_border_colour 0 0 0 1
filtering trilinear
max_anisotropy 1
mipmap_bias 0
colour_op_ex modulate src_texture src_current 1 1 1 1 1 1 1
alpha_op_ex modulate src_texture src_current 1 1 1
colour_op_multipass_fallback one zero
env_map off

//scroll_anim 1 1
}

}

}

}

material TestMonsterForge: MonsterExample
{
set_texture_alias Diffuse forge_diffuse.tga
set_texture_alias Normal forge_normal.tga
}


monster.program
vertex_program monster_vs cg
{
source monster.source

default_params
{
param_named_auto lightPosition0 light_position_object_space 0
param_named_auto lightPosition1 light_position_object_space 1
param_named_auto lightPosition2 light_position_object_space 2
param_named_auto eyePosition camera_position_object_space
param_named_auto worldviewproj worldviewproj_matrix
param_named scale float 2
}

entry_point monster_vs
profiles vs_1_1 arbvp1

//profiles vs_3_0 arbvp1
//includes_skeletal_animation true
}

fragment_program monster_ps cg
{
source monster.source

default_params
{
param_named_auto lightDiffuse0 light_diffuse_colour 0
param_named_auto lightDiffuse1 light_diffuse_colour 1
param_named_auto lightDiffuse2 light_diffuse_colour 2

param_named_auto lightSpecular0 light_specular_colour 0
param_named_auto lightSpecular1 light_specular_colour 1
param_named_auto lightSpecular2 light_specular_colour 2

param_named_auto atten0 light_attenuation 0
param_named_auto atten1 light_attenuation 1
param_named_auto atten2 light_attenuation 2

param_named exponent0 float 127
param_named scaleBias float4 0.04 -0.02 1 0
//param_named ambient float4 0.0 0.0 0.0 1.0
param_named ambient float4 0.0 0.0 0.0 0.0

}

entry_point monster_ps
profiles ps_2_0 arbfp1

//includes_skeletal_animation true
}



monster.source

//TWEAK HERE
#define FADING 0
//fading is buggy, experimental guarantees :)

#define ATTENUATION 0

#define LIGHT0_IS_DIRECTIONAL 0
//if u have directional light (suppose a healthy 1 only), it is always light0
//(regarding that you turn off lights in RECOMMENDED ORDER of 2,1,0)
//so do not attenuate it, but then we have power to attenuate light1, and light2
//even with offset mapping on !

#define ANY_TEXTURE 1
#define DIFFUSE_TEXTURE 1

#define AT_LEAST_PERPIXEL 1
#define AT_LEAST_NORMAL_MAPPING 1
#define OFFSET_MAPPING 0

#define AMBIENT 1
#define DIFFUSE 1
#define SPECULAR 1

#define LIGHT0 1
#define LIGHT1 1
#define LIGHT2 1

//#define Skinned 0

/////////////////////////////////////////////////////////////////////////////////////////////////
// VERT COMES
/////////////////////////////////////////////////////////////////////////////////////////////////


//quite chaotic form, maybe more logical arrangement possible
void monster_vs
(
float4 position : POSITION,
float3 normal : NORMAL,
out float4 oPosition : POSITION,

#if ANY_TEXTURE
float2 uv : TEXCOORD0,
out float2 oUv : TEXCOORD0,
uniform float scale,
#endif

#if AT_LEAST_NORMAL_MAPPING
float3 tangent : TEXCOORD1,
#elif AT_LEAST_PERPIXEL //just normal perpixel, use texcoord7 to transmit to frag (holds eyedir in offset case)
out float3 oNorm : TEXCOORD7,
#endif


// Still in frag shader!
// #if AMBIENT
// uniform float4 ambient,
// out float4 oColor : COLOR,
// #endif


#if LIGHT0
uniform float4 lightPosition0, // object space
#if DIFFUSE
out float3 oLightDir0 : TEXCOORD1,
#endif
#if SPECULAR
out float3 oHalfAngle0 : TEXCOORD4,
#endif
#endif

#if LIGHT1
uniform float4 lightPosition1, // object space
#if DIFFUSE
out float3 oLightDir1 : TEXCOORD2,
#endif
#if SPECULAR
out float3 oHalfAngle1 : TEXCOORD5,
#endif
#endif

#if LIGHT2
uniform float4 lightPosition2, // object space
#if DIFFUSE
out float3 oLightDir2 : TEXCOORD3,
#endif
#endif

#if ATTENUATION
out float4 dist : TEXCOORD6, // .x, .y, and .z is used for light distances
#elif SPECULAR
out float3 oHalfAngle2 : TEXCOORD6,
#endif

#if OFFSET_MAPPING //needs eye no matter specular
uniform float3 eyePosition, // object space
out float3 oEyeDir : TEXCOORD7,
#elif SPECULAR //no need to output eye, even if normal-mapping is on
uniform float3 eyePosition, // object space
#elif FADING
uniform float3 eyePosition, // object space
//Fading will modify alpha, and will be passed to frag in COLOR,
//though I could do it with dist.w, which is unmodified even with atten
//but I do not use dist without atten, anyway. Dunno which is faster.
#endif

#if FADING
out float4 oFadeColor : COLOR,
uniform float4 fadefirst,
uniform float4 fadesecond,
#endif

//#if Skinned
// float blendIdx : BLENDINDICES,
// uniform float3x4 worldMatrix3x4Array[24],
// uniform float4x4 viewProjectionMatrix,
//#endif

uniform float4x4 worldviewproj


)
{

//#if Skinned
// transform by indexed matrix
// float4 blendPos = float4(mul(worldMatrix3x4Array[blendIdx], position).xyz, 1.0);
// view / projection
// oPosition = mul(viewProjectionMatrix, blendPos);

// transform normal
// float3 norm = mul((float3x3)worldMatrix3x4Array[blendIdx], normal);
// Lighting - support point and directional
// float3 lightDir0 = normalize(
// lightPos[0].xyz - (blendPos.xyz * lightPos[0].w));
// float3 lightDir1 = normalize(
// lightPos[1].xyz - (blendPos.xyz * lightPos[1].w));

//#else
oPosition = mul(worldviewproj , position);
//#endif



#if ANY_TEXTURE
oUv = uv * scale;
#endif


#if AT_LEAST_NORMAL_MAPPING
float3 binormal = cross(tangent, normal);
float3x3 rotation = float3x3(tangent, binormal, normal);
#elif AT_LEAST_PERPIXEL
oNorm = normal;
#endif


#if OFFSET_MAPPING //no matter specular, I need eye for offsetting
float3 eyeDir = eyePosition - position.xyz;
eyeDir = normalize(mul(rotation, eyeDir));
oEyeDir = eyeDir;
#elif SPECULAR //I need eye only if specular other than offset, plus no eye output now
float3 eyeDir = normalize(eyePosition - position.xyz);
#if AT_LEAST_NORMAL_MAPPING //eye needs adjustment if normal-mapping
eyeDir = normalize(mul(rotation, eyeDir));
#endif
#endif

//if DIFFUSE is commented out, we only need temp_lightDirX for oHalfAngle
//and if both DIFFUSE and SPECULAR is out, we shall not calculate any lighting
#if LIGHT0
#if ATTENUATION
#if LIGHT0_IS_DIRECTIONAL
// light0 is directional, atten is on, but we do not atten light0
float3 temp_lightDir0 = normalize(lightPosition0.xyz - (position * lightPosition0.w));
dist.x = 0;
//I need dist.x even I do not use it now. Compiler blah-blah about continous oTex6.
#else
float3 temp_lightDir0 = lightPosition0.xyz - (position * lightPosition0.w);
dist.x = length(temp_lightDir0);
temp_lightDir0 = temp_lightDir0 / dist.x; //normalize it this way

// oatten.x = 1/(atten.y + dist0*atten.z + dist0*dist0*atten.w);
// Attenuation calc, could be even much faster if it could be done in vertex shader.
// Think about leaving kl component only, and calculating atten value here,
// instead doing only distance here, and calculating atten in frag shader.

#endif
#else
float3 temp_lightDir0 = normalize(lightPosition0.xyz - (position * lightPosition0.w));
#endif
#if AT_LEAST_NORMAL_MAPPING
temp_lightDir0 = normalize(mul(rotation, temp_lightDir0));
#if DIFFUSE
oLightDir0 = temp_lightDir0;
#endif
#elif DIFFUSE //just normal perpixel
oLightDir0 = temp_lightDir0;
#endif

#if SPECULAR
oHalfAngle0 = normalize(eyeDir + temp_lightDir0);
#endif

#endif

#if LIGHT1
#if ATTENUATION
float3 temp_lightDir1 = lightPosition1.xyz - (position * lightPosition1.w);
dist.y = length(temp_lightDir1);
temp_lightDir1 = temp_lightDir1 / dist.y; //normalize it this way
#else
float3 temp_lightDir1 = normalize(lightPosition1.xyz - (position * lightPosition1.w));
#endif
#if AT_LEAST_NORMAL_MAPPING
temp_lightDir1 = normalize(mul(rotation, temp_lightDir1));
#if DIFFUSE
oLightDir1 = temp_lightDir1;
#endif
#elif DIFFUSE //just normal perpixel
oLightDir1 = temp_lightDir1;
#endif

#if SPECULAR
oHalfAngle1 = normalize(eyeDir + temp_lightDir1);
#endif

#endif

#if LIGHT2
#if ATTENUATION
float3 temp_lightDir2 = lightPosition2.xyz - (position * lightPosition2.w);
dist.z = length(temp_lightDir2);
temp_lightDir2 = temp_lightDir2 / dist.z; //normalize it this way
#else
float3 temp_lightDir2 = normalize(lightPosition2.xyz - (position * lightPosition2.w));
#if SPECULAR
oHalfAngle2 = normalize(eyeDir + temp_lightDir2);
#endif
#endif
#if AT_LEAST_NORMAL_MAPPING
temp_lightDir2 = normalize(mul(rotation, temp_lightDir2));
#if DIFFUSE
oLightDir2 = temp_lightDir2;
#endif
#elif DIFFUSE //just normal perpixel
oLightDir2 = temp_lightDir2;
#endif
#endif


#if FADING
float ratio = saturate(1-(distance(eyePosition, position.xyz)-fadefirst) / fadesecond);
oFadeColor = float4(0,0,0,ratio);
#endif

}



// Helper: Expand a range-compressed vector
float3 expand(float3 v)
{
return (v - 0.5) * 2;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// FRAG COMES
/////////////////////////////////////////////////////////////////////////////////////////////////



void monster_ps(

#if DIFFUSE_TEXTURE
uniform sampler2D diffuseMap : register(s1),
float2 uv : TEXCOORD0,
#elif ANY_TEXTURE
float2 uv : TEXCOORD0,
#endif

#if LIGHT0
#if DIFFUSE
float3 LightDir0 : TEXCOORD1,
uniform float4 lightDiffuse0,
#endif
#if SPECULAR
float3 HalfAngle0 : TEXCOORD4,
uniform float4 lightSpecular0,
#endif
#endif

#if LIGHT1
#if DIFFUSE
float3 LightDir1 : TEXCOORD2,
uniform float4 lightDiffuse1,
#endif
#if SPECULAR
float3 HalfAngle1 : TEXCOORD5,
uniform float4 lightSpecular1,
#endif
#endif

#if LIGHT2
#if DIFFUSE
float3 LightDir2 : TEXCOORD3,
uniform float4 lightDiffuse2,
#endif
#endif

#if OFFSET_MAPPING
float3 EyeDir : TEXCOORD7,
uniform float4 scaleBias,
uniform sampler2D normalHeightMap : register(s0),
#elif AT_LEAST_NORMAL_MAPPING
uniform sampler2D normalHeightMap : register(s0),
#elif AT_LEAST_PERPIXEL //no normal-mapping, use standard normal, in eyedir's place
float3 normalvec : TEXCOORD7,
#endif

#if SPECULAR
uniform float exponent0,
// uniform float exponent1,
// uniform float exponent2,
#endif

#if AMBIENT
uniform float4 ambient,
#endif

#if ATTENUATION //if on, supposed to have light0 on as well, OR light0_directional!
float4 dist : TEXCOORD6,
#if !LIGHT0_IS_DIRECTIONAL
uniform float4 atten0,
#endif
#if LIGHT1
uniform float4 atten1,
#endif
#if LIGHT2
uniform float4 atten2,
#endif
#elif SPECULAR
#if LIGHT2
float3 HalfAngle2 : TEXCOORD6,
uniform float4 lightSpecular2,
#endif
#endif


#if FADING
float4 inFadeColor : COLOR,
#endif

out float4 oColor : COLOR
)
{
#if OFFSET_MAPPING
float height = tex2D(normalHeightMap, uv).a;
float scale = scaleBias.x;
float bias = scaleBias.y;
float displacement = (height * scale) + bias;
float3 uv2 = float3(uv, 1);
float2 newTexCoord = ((EyeDir * displacement) + uv2).xy;
float3 bumpVec = expand(tex2D(normalHeightMap, newTexCoord ).xyz);
// float3 bumpVec = tex2D(normalHeightMap, newTexCoord ).xyz;
float3 N = normalize(bumpVec);
#if DIFFUSE_TEXTURE
float3 diffusetex = tex2D(diffuseMap, newTexCoord).xyz;
#endif
#elif AT_LEAST_NORMAL_MAPPING
float3 bumpVec = expand(tex2D(normalHeightMap, uv).xyz);
// float3 N = tex2D(normalHeightMap, uv).xyz;
float3 N = normalize(bumpVec);
#if DIFFUSE_TEXTURE
float3 diffusetex = tex2D(diffuseMap, uv).xyz;
#endif
#elif AT_LEAST_PERPIXEL
float3 N = normalize(normalvec);
#if DIFFUSE_TEXTURE
float3 diffusetex = tex2D(diffuseMap, uv).xyz;
#endif
#elif DIFFUSE_TEXTURE
float3 diffusetex = tex2D(diffuseMap, uv).xyz;
#endif


//If different exponents for different specular-lights, change 3 places here!

#if LIGHT0
#if DIFFUSE
float NdotL0 = dot(normalize(LightDir0), N);
#if SPECULAR //both
float NdotH0 = dot(normalize(HalfAngle0), N);
float4 Lit0 = lit(NdotL0,NdotH0,exponent0);
#else //just diffuse
float4 Lit0;
Lit0.y = saturate(NdotL0);
#endif
#elif SPECULAR //just specular
float NdotH0 = dot(normalize(HalfAngle0), N);
float4 Lit0;
Lit0.z = pow(saturate(NdotH0),exponent0);
#endif
#endif

#if LIGHT1
#if DIFFUSE
float NdotL1 = dot(normalize(LightDir1), N);
#if SPECULAR //both
float NdotH1 = dot(normalize(HalfAngle1), N);
float4 Lit1 = lit(NdotL1,NdotH1,exponent0);
#else //just diffuse
float4 Lit1;
Lit1.y = saturate(NdotL1);
#endif
#elif SPECULAR //just specular
float NdotH1 = dot(normalize(HalfAngle1), N);
float4 Lit1;
Lit1.z = pow(saturate(NdotH1),exponent0);
#endif
#endif

#if LIGHT2
#if DIFFUSE
float NdotL2 = dot(normalize(LightDir2), N);
#if SPECULAR //both
#if !ATTENUATION
float NdotH2 = dot(normalize(HalfAngle2), N);
float4 Lit2 = lit(NdotL2,NdotH2,exponent0);
#else
float4 Lit2;
Lit2.y = saturate(NdotL2);
#endif
#else //just diffuse
float4 Lit2;
Lit2.y = saturate(NdotL2);
#endif
#elif SPECULAR //just specular
#if !ATTENUATION
float NdotH2 = dot(normalize(HalfAngle2), N);
float4 Lit2;
Lit2.z = pow(saturate(NdotH2),exponent0);
#else
float4 Lit2;
Lit2 = float4(1,0,0,1);
#endif
#endif
#endif

oColor =

#if ATTENUATION //since usage rules specify it, we have at least light0 on with at least either
//diffuse or specular also on !
// - if you want no lighting, just textures, turn attenuation off!
//But yes, you can have diffusetex with just specular :)
//Note that you can't have specular of light2 with attenuation on. See docs.

// Final color formula with atten
// oColor = atten0 * (diffusetex * lightDiffuse0 * Lit0.y + lightSpecular0 * Lit0.z)
// atten1 * (diffusetex * lightDiffuse1 * Lit1.y + lightSpecular1 * Lit1.z)
// atten2 * (diffusetex * lightDiffuse2 * Lit2.y + lightSpecular2 * Lit2.z)
// + ambient;

#if !DIFFUSE //we start with the no diffuse just diffusetex case, here only spec is attenuated
#if DIFFUSE_TEXTURE
float4(diffusetex,1) +
#endif
#endif

// 1/(atten0.y + atten0.z*dist.x + atten0.w*dist.x*dist.x)* (
// use simpler formular instead: counts much in FPS!
#if !LIGHT0_IS_DIRECTIONAL
1/(1 + atten0.z*dist.x)* (
#else
( //for syntax
#endif
//we always have light0 on here, and spec0 or diffuse0 with it
#if SPECULAR
lightSpecular0 * Lit0.z
#if DIFFUSE
+
#else //light0 has only spec, light0 done
)
#endif
#endif
#if DIFFUSE
lightDiffuse0 * Lit0.y //without + sign, we are good at no specular case as well
#if DIFFUSE_TEXTURE
* float4(diffusetex,1)) //light0 done
#else
) //light0 done
#endif
#endif

#if LIGHT1 //optional, but if we have it, we have either diff1 or spec1, difftex can be 0/1
// + 1/(atten1.y + atten1.z*dist.y + atten1.w*dist.y*dist.y) * (
// use simpler formula instead
+ 1/(1 + atten1.z*dist.y) * (
#if SPECULAR
lightSpecular1 * Lit1.z
#if DIFFUSE
+
#else //light1 has only spec, light1 done
)
#endif
#endif

#if DIFFUSE
lightDiffuse1 * Lit1.y //without + sign here, we are good at no specular case as well
#if DIFFUSE_TEXTURE
* float4(diffusetex,1)) //light1 done
#else
) //light1 done
#endif
#endif
#endif

#if LIGHT2 //ditto goes for diff2, and difftex (no specular here)
// + 1/(atten2.y + atten2.z*dist.z + atten2.w*dist.z*dist.z) * (
// use simpler formula instead
+ 1/(1 + atten2.z*dist.z) * (
#if DIFFUSE
lightDiffuse2 * Lit2.y //without + sign here, we are good at no specular case as well
#if DIFFUSE_TEXTURE
* float4(diffusetex,1)) //light2 done
#else
) //light2 done
#endif
#endif
#endif

#else

// And wo. atten
// oColor = diffusetex
// * (lightDiffuse0 * Lit0.y + lightDiffuse1 * Lit1.y + lightDiffuse2 * Lit2.y)
// + lightSpecular0 * Lit0.z + lightSpecular1 * Lit1.z + lightSpecular2 * Lit2.z
// + ambient;

float4(0,0,0,0) //this is needed to simplify preprocessor stuff, no FPS cost :)

#if DIFFUSE_TEXTURE //at least diffuse texture, no lighting yet
+ float4(diffusetex,1)
#if DIFFUSE //modulate texture with lighting
*(
#if LIGHT0
lightDiffuse0 * Lit0.y
#endif
#if LIGHT1
+ lightDiffuse1 * Lit1.y
#endif
#if LIGHT2
+ lightDiffuse2 * Lit2.y
#endif
)
#endif
#elif DIFFUSE //just diffuse lighting, no modulation
#if LIGHT0
+ lightDiffuse0 * Lit0.y
#endif
#if LIGHT1
+ lightDiffuse1 * Lit1.y
#endif
#if LIGHT2
+ lightDiffuse2 * Lit2.y
#endif
#endif

#if SPECULAR
#if LIGHT0
+ lightSpecular0 * Lit0.z
#endif
#if LIGHT1
+ lightSpecular1 * Lit1.z
#endif
#if LIGHT2
+ lightSpecular2 * Lit2.z
#endif
#endif
#endif

#if AMBIENT
+ ambient
#endif
;


#if FADING
//WARNING: this will eat up all original/computed alpha!
oColor = float4(oColor.x, oColor.y, oColor.z, inFadeColor.w);
#endif
}

jchmack

20-12-2008 02:13:34

And for the Character i use this shader:
animatedNormalSpecular.material
vertex_program AnimatedNormalSpecular_VP hlsl
{
source animatedNormalSpecular.hlsl
entry_point main_vp
target vs_2_0
//target vs_2_x
//target vs_3_0
// target vs_2_a

column_major_matrices false //required for hlsl skinning

includes_skeletal_animation true

default_params
{
param_named_auto worldviewprojmatrix worldviewproj_matrix
param_named_auto light_position light_position_object_space 0
param_named_auto eye_position camera_position_object_space

param_named_auto worldMatrix3x4Array world_matrix_array_3x4
param_named_auto viewProjectionMatrix viewproj_matrix
param_named_auto invworldmatrix inverse_world_matrix
}
}

fragment_program AnimatedNormalSpecular_FP hlsl
{
source animatedNormalSpecular.hlsl
entry_point main_fp
target ps_2_0

default_params
{
param_named_auto lightDiffuse light_diffuse_colour 0
param_named_auto ambientLight ambient_light_colour
param_named_auto specularLight light_specular_colour 0
param_named specular_power float 64
param_named bumpiness float 1
}
}

vertex_program Ogre/HardwareSkinningTwoWeightsShadowCasterCg cg
{
source animatedNormalSpecular.cg
entry_point hardwareSkinningTwoWeightsCaster_vp
//profiles vs_1_1 arbvp1
profiles vs_2_0 arbvp1
includes_skeletal_animation true
}

vertex_program Ogre/HardwareSkinningTwoWeightsShadowCasterGLSL glsl
{
source animatedNormalSpecular.glsl
includes_skeletal_animation true
}

material animatedNormalSpecular
{
technique
{
pass Single Pass
{
vertex_program_ref AnimatedNormalSpecular_VP
{
}

fragment_program_ref AnimatedNormalSpecular_FP
{
}


//shadow_caster_vertex_program_ref HardwareSkinningFourShadow //this part is in the ogre samples somewhere
shadow_caster_vertex_program_ref Ogre/HardwareSkinningTwoWeightsShadowCasterCg
//shadow_caster_vertex_program_ref Ogre/HardwareSkinningTwoWeightsShadowCasterGLSL
{
param_named_auto worldMatrix3x4Array world_matrix_array_3x4
param_named_auto viewProjectionMatrix viewproj_matrix
param_named_auto ambient ambient_light_colour
}

//diffuse map
texture_unit
{
texture_alias DiffuseMap
texture diffuse.tga
filtering linear linear linear
}

//normal map
texture_unit
{
texture_alias NormalMap
texture diffuse_normal.tga
filtering linear linear linear
}

// specular map
texture_unit
{
texture_alias SpecularMap
texture specular.png
}

}

}
}

material ForgeHighQuality: animatedNormalSpecular
{
set_texture_alias DiffuseMap forge_diffuse.tga
set_texture_alias NormalMap forge_normal.tga
set_texture_alias SpecularMap forge_spec.tga
}


animatedNormalSpecular.hlsl

void main_vp(
float4 position : POSITION,
float2 uv : TEXCOORD0,
float3 normal : NORMAL,
float3 tangent : TANGENT0,

float4 blendIdx : BLENDINDICES,
float4 blendWgt : BLENDWEIGHT,

out float4 oPosition : POSITION,
out float2 oUV : TEXCOORD0,
out float3 oLightVector : TEXCOORD1,
out float3 oHalfAngle : TEXCOORD2,

uniform float4x4 worldviewprojmatrix,
uniform float4 light_position,
uniform float4 eye_position,
uniform float3x4 worldMatrix3x4Array[61],
uniform float4x4 viewProjectionMatrix,
uniform float4x4 invworldmatrix
) {
// Calculate the pixel position using the perspective matrix.
oUV = uv;

// transform by indexed matrix
float4 blendPos = float4(0,0,0,0);
int i;
for (i = 0; i < 3; ++i)
{
blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
}
// view / projection
oPosition = mul(viewProjectionMatrix, blendPos);


// transform normal
float3 newnormal = float3(0,0,0);
for (i = 0; i < 3; ++i)
{
newnormal += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * blendWgt[i];
}
newnormal = mul((float3x3)invworldmatrix, newnormal);
newnormal = normalize(newnormal);

// transform tangent
float3 newtangent = float3(0,0,0);
for (i = 0; i < 3; ++i)
{
newtangent += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], tangent) * blendWgt[i];
}
newtangent = mul((float3x3)invworldmatrix, newtangent);
newtangent = normalize(newtangent);




float3 binormal = cross(newtangent, newnormal);
float3x3 rotation = float3x3(newtangent, binormal, newnormal);

// Calculate the light vector in object space,
// and then transform it into texture space.
float3 temp_lightDir0 = normalize(light_position.xyz - (blendPos * light_position.w));
temp_lightDir0 = normalize(mul(rotation, temp_lightDir0));
oLightVector = temp_lightDir0;


// Calculate the view vector in object space,
// and then transform it into texture space.
float3 eyeDir = normalize(eye_position - blendPos);
eyeDir = normalize(mul(rotation, eyeDir.xyz));

// Calculate the half angle
oHalfAngle = oLightVector + eyeDir;

}





float4 lightDiffuse ;
float4 ambientLight;
float4 specularLight;
float specular_power;
float bumpiness;
sampler base_map;
sampler bump_map;
sampler specular_map;

struct PS_INPUT_STRUCT
{
float2 uv: TEXCOORD0;
float3 light_vector: TEXCOORD1;
float3 half_angle: TEXCOORD2;
};

struct PS_OUTPUT_STRUCT
{
float4 color0: COLOR0;
};

PS_OUTPUT_STRUCT main_fp( PS_INPUT_STRUCT psInStruct )
{
PS_OUTPUT_STRUCT psOutStruct;

float3 base = tex2D( base_map, psInStruct.uv );
float3 bump = tex2D( bump_map, psInStruct.uv );
float specularLevel = tex2D(specular_map, psInStruct.uv).r;

//normalise
float3 normalized_light_vector = normalize( psInStruct.light_vector );
float3 normalized_half_angle = normalize( psInStruct.half_angle );

// "Smooth out" the bump based on the bumpiness parameter.
// This is simply a linear interpolation between a "flat"
// normal and a "bumped" normal. Note that this "flat"
// normal is based on the texture space coordinate basis.
float3 smooth = { 0.5f, 0.5f, 1.0f };
bump = lerp( smooth, bump, bumpiness );
bump = normalize( ( bump * 2.0f ) - 1.0f );

// These dot products are used for the lighting model
// equations. The surface normal dotted with the light
// vector is denoted by n_dot_l. The normal vector
// dotted with the half angle vector is denoted by n_dot_h.
float4 n_dot_l = dot( bump, normalized_light_vector );
float4 n_dot_h = dot( bump, normalized_half_angle );

// Calculate the resulting pixel color,
// based on our lighting model.
// Ambient + Diffuse + Specular
psOutStruct.color0.rgb =
( base * ambientLight) +
( base * lightDiffuse * max( 0, n_dot_l ) ) +
( specularLight * specularLevel * pow( max( 0, n_dot_h ), specular_power ) );
psOutStruct.color0.a = 1.0f; //** Set the alpha component manually

return psOutStruct;
}


animatedNormalSpecular.cg

/*
Two-weight-per-vertex hardware skinning, shadow caster pass
*/
void hardwareSkinningTwoWeightsCaster_vp(
float4 position : POSITION,
float3 normal : NORMAL,
float2 uv : TEXCOORD0,
float4 blendIdx : BLENDINDICES,
float4 blendWgt : BLENDWEIGHT,


out float4 oPosition : POSITION,
out float4 colour : COLOR,
// Support up to 24 bones of float3x4
// vs_1_1 only supports 96 params so more than this is not feasible
uniform float3x4 worldMatrix3x4Array[24],
uniform float4x4 viewProjectionMatrix,
uniform float4 ambient)
{
// transform by indexed matrix
float4 blendPos = float4(0,0,0,0);
int i;
for (i = 0; i < 2; ++i)
{
blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
}
// view / projection
oPosition = mul(viewProjectionMatrix, blendPos);


colour = ambient;
}


animatedNormalSpecular.glsl
// Example GLSL program for skinning with two bone weights per vertex

attribute vec4 vertex;
attribute vec4 uv0;
attribute vec4 blendIndices;
attribute vec4 blendWeights;

// 3x4 matrix, passed as vec4's for compatibility with GL 2.0
// GL 2.0 supports 3x4 matrices
// Support 24 bones ie 24*3, but use 72 since our parser can pick that out for sizing
uniform vec4 worldMatrix3x4Array[72];
uniform mat4 viewProjectionMatrix;
uniform vec4 ambient;

void main()
{
vec3 blendPos = vec3(0,0,0);

for (int bone = 0; bone < 2; ++bone)
{
// perform matrix multiplication manually since no 3x4 matrices
// ATI GLSL compiler can't handle indexing an array within an array so calculate the inner index first
int idx = int(blendIndices[bone]) * 3;
// ATI GLSL compiler can't handle unrolling the loop so do it manually
// ATI GLSL has better performance when mat4 is used rather than using individual dot product
// There is a bug in ATI mat4 constructor (Cat 7.2) when indexed uniform array elements are used as vec4 parameter so manually assign
mat4 worldMatrix;
worldMatrix[0] = worldMatrix3x4Array[idx];
worldMatrix[1] = worldMatrix3x4Array[idx + 1];
worldMatrix[2] = worldMatrix3x4Array[idx + 2];
worldMatrix[3] = vec4(0);
// now weight this into final
blendPos += (vertex * worldMatrix).xyz * blendWeights[bone];
}

// apply view / projection to position
gl_Position = viewProjectionMatrix * vec4(blendPos, 1);

gl_FrontSecondaryColor = vec4(0,0,0,0);
gl_FrontColor = ambient;
gl_TexCoord[0] = uv0;
}


hlsl for the vp/fp and cg for the shadows. As you can see i tried changing the shadows to glsl but I get the same results.

Lioric

23-12-2008 01:28:50

It seems you are using light iteration for the level shaders (with 8 lights), have you tested the material without this, and with a single light only?

Are the same 8 lights affecting the level at all times?

jchmack

05-01-2009 20:20:05

Thank you for your reply lioric. I didn't read it til i got back after the holidays and i didn't have a chance to reply.

It seems you are using light iteration for the level shaders (with 8 lights), have you tested the material without this, and with a single light only?

Are the same 8 lights affecting the level at all times?


I only have 1 light in the scene and just in case i tried to tweak the settings(max_lights 8 -> max_lights 1,etc) and the problems are still there.

I am starting to believe that this might be an issue with normals/tangents and scaling or a combination of both. The shader works perfectly with an unscaled cube. It looks great even if i have the problematic characters loaded. But if i try to apply the same shader to any complex geometry (my level, the ogre torus knot) it seems to fail.

I am no artist and my MAX skills are minimal.

I need to check the tangents vectors that my artists are using. How can i check the normals/tangents in max? and in ogre?
Does anyone know if ogre messes with the normals/tangents during scaling?

Lioric

07-01-2009 01:33:14

Normals are affected by node scale, depending on the Ogre engine version you might need to set "normalizeNormals" on the object or in the latest versions it might be normalized automatically

You can do a visual test of your normals using a "debug" shader, it will display in color (similar to the vertex colors) the tangents, binormals, normals and other vertex data you need (see the NVidia debug shader or the ATI debug shader part of RenderMonkey)