之前使用celshading实现简单的模型身上的阴影.现在因为要加入ogre的硬件蒙皮,导致阴影消失了.只有直接在shader里改里,一张shader里包含了celshading和硬件蒙皮.感觉不是太好,但硬件蒙皮+normal map也是得这么做,还没找到方法.全程使用的shader似乎不得不写在一起了.
把硬件蒙皮融合进自己的shader,一定要注意顶点程序中输出顶点的坐标,关注你自己的shader中position所在空间关系.笔者由于复制粘贴的低级错误排查了蛮久.
提升效率不是太明显.在普通的显卡上有15%-20%左右的提升,在特别低端(办公用集成显卡g41之类的)上,只有7%左右提升.
// Shadow caster vertex program. void casterVP( float4 position : POSITION, out float4 outPosition : POSITION, out float2 outDepth : TEXCOORD0, uniform float4x4 worldViewProj, uniform float4 texelOffsets //uniform float4 depthRange ) { outPosition = mul(worldViewProj, position); // fix pixel / texel alignment outPosition.xy += texelOffsets.zw * outPosition.w; // linear depth storage // offset / scale range output #if LINEAR_RANGE outDepth.x = (outPosition.z - depthRange.x) * depthRange.w; #else outDepth.x = outPosition.z; #endif outDepth.y = outPosition.w; } // Shadow caster fragment program for high-precision single-channel textures void casterFP( float2 depth : TEXCOORD0, out float4 result : COLOR ) { #if LINEAR_RANGE float finalDepth = depth.x; #else float finalDepth = depth.x / depth.y; #endif // just smear across all components // therefore this one needs high individual channel precision result = float4(finalDepth, finalDepth, finalDepth, 1); } void receiverVP( float4 position : POSITION, float3 normal : NORMAL, float2 uv : TEXCOORD0, out float4 outPosition : POSITION, out float2 outUV : TEXCOORD0, out float4 outShadowUV : TEXCOORD1, out float outDiffuse : TEXCOORD2, //out float outLightDir : TEXCOORD4, #if SPECULAR out float outSpecular : TEXCOORD3, uniform float4 eyePosition, uniform float shininess, #endif uniform float4x4 world, //uniform float4x4 worldViewProj, uniform float4x4 texViewProj, //uniform float4 shadowDepthRange, //uniform float4 lightPositionObjectSpace, uniform float4 lightPosition, uniform float3x4 worldMatrix3x4Array[64], uniform float4x4 viewProjectionMatrix, //uniform float4x4 inverseWorldMatrix, float4 blendIdx : BLENDINDICES, float4 blendWgt : BLENDWEIGHT //uniform float4 lightDiffuseColour, //uniform float4 ambient, //uniform float4 diffuse, //uniform float4 emissive, ) { //outPosition = mul(worldViewProj, position); outUV = uv; // calculate shadow map coords //outShadowUV = mul(texViewProj, position); // 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]; } float4 worldPos = mul(world, blendPos); outShadowUV = mul(texViewProj, worldPos); #if LINEAR_RANGE // adjust by fixed depth bias, rescale into range outShadowUV.z = (outShadowUV.z - shadowDepthRange.x) * shadowDepthRange.w; #endif // view / projection outPosition = mul(viewProjectionMatrix, blendPos); float3 N = float3(0,0,0); for (i = 0; i < 3; ++i) { N += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * blendWgt[i]; } //N = mul((float3x3)inverseWorldMatrix, N); N = normalize(N); float3 L = normalize( lightPosition.xyz - (blendPos.xyz * lightPosition.w)); // #if DIRECTIONAL // // used in directional light source // float3 L = normalize(lightPositionObjectSpace.xyz); // #else // // use this line if used in point light source // float3 L = normalize(lightPositionObjectSpace.xyz - position.xyz); // #endif // Calculate diffuse component outDiffuse = max(dot(N, L) , 0); #if SPECULAR // Calculate specular component float3 E = normalize(eyePosition.xyz - position.xyz); float3 H = normalize(L + E); outSpecular = pow(max(dot(N, H), 0), shininess); #endif } void receiverFP( float4 position : POSITION, float2 uv : TEXCOORD0, float4 shadowUV : TEXCOORD1, float diffuse : TEXCOORD2, #if SPECULAR float specular : TEXCOORD3, #endif //float4 lightColor : TEXCOORD4, uniform sampler2D myTexture : register(s0), uniform sampler2D shadowMap : register(s1), uniform sampler1D diffuseRamp : register(s2), #if SPECULAR uniform sampler1D specularRamp : register(s3), #endif uniform float inverseShadowmapSize, uniform float fixedDepthBias, uniform float gradientClamp, uniform float gradientScaleBias, //uniform float shadowFuzzyWidth, uniform float darken, #if SPECULAR uniform float lighten, #endif out float4 result : COLOR ) { // point on shadowmap #if LINEAR_RANGE shadowUV.xy = shadowUV.xy / shadowUV.w; #else shadowUV = shadowUV / shadowUV.w; #endif float centerdepth = tex2D(shadowMap, shadowUV.xy).x; // gradient calculation float pixeloffset = inverseShadowmapSize; float4 depths = float4( tex2D(shadowMap, shadowUV.xy + float2(-pixeloffset, 0)).x, tex2D(shadowMap, shadowUV.xy + float2(+pixeloffset, 0)).x, tex2D(shadowMap, shadowUV.xy + float2(0, -pixeloffset)).x, tex2D(shadowMap, shadowUV.xy + float2(0, +pixeloffset)).x); float2 differences = abs( depths.yw - depths.xz ); float gradient = min(gradientClamp, max(differences.x, differences.y)); float gradientFactor = gradient * gradientScaleBias; // visibility function float depthAdjust = gradientFactor + (fixedDepthBias * centerdepth); float finalCenterDepth = centerdepth + depthAdjust; // shadowUV.z contains lightspace position of current object float shadow; #if FUZZY_TEST // fuzzy test - introduces some ghosting in result and doesn't appear to be needed? //shadow = saturate(1 + delta_z / (gradient * shadowFuzzyWidth)); shadow = saturate(1 + (finalCenterDepth - shadowUV.z) * shadowFuzzyWidth * shadowUV.w); #else // hard test #if PCF // use depths from prev, calculate diff depths += depthAdjust.xxxx; shadow = (finalCenterDepth > shadowUV.z) ? 1.0f : 0.0f; shadow += (depths.x > shadowUV.z) ? 1.0f : 0.0f; shadow += (depths.y > shadowUV.z) ? 1.0f : 0.0f; shadow += (depths.z > shadowUV.z) ? 1.0f : 0.0f; shadow += (depths.w > shadowUV.z) ? 1.0f : 0.0f; shadow *= 0.2f; #else shadow = (finalCenterDepth > shadowUV.z) ? 1.0f : 0.0f; #endif #endif float4 vertexColour = tex2D(myTexture, uv); //result = float4(vertexColour.xyz * shadow, 1); diffuse = tex1D(diffuseRamp, diffuse).x; float darkness = (shadow > diffuse) ? diffuse : shadow; float final = (darkness - 1) * darken; #if SPECULAR // if there is already a shadow, no specular will be casted final += (shadow > 0.0f) ? tex1D(specularRamp, specular).x * lighten : 0; #endif // then darken the original texture. result = float4(vertexColour.xyz + float3(final), 1); }
vertex_program CelShading/CasterVP cg { source CelShadingShadow.cg entry_point casterVP profiles arbvp1 vs_2_0 compile_arguments -DLINEAR_RANGE=0 default_params { param_named_auto worldViewProj worldviewproj_matrix param_named_auto texelOffsets texel_offsets //param_named_auto depthRange scene_depth_range } } fragment_program CelShading/CasterFP cg { source CelShadingShadow.cg entry_point casterFP profiles arbfp1 ps_2_0 fp20 compile_arguments -DLINEAR_RANGE=0 default_params { } } vertex_program CelShading/ReceiverVP cg { source CelShadingShadow.cg entry_point receiverVP profiles arbvp1 vs_2_0 includes_skeletal_animation true // set DDIRECTIONAL=1 if used with directional light compile_arguments -DDIRECTIONAL=1 -DLINEAR_RANGE=0 -DSPECULAR=0 default_params { param_named_auto world world_matrix param_named_auto worldViewProj worldviewproj_matrix param_named_auto texViewProj texture_viewproj_matrix param_named_auto lightPosition light_position 0 //param_named_auto shadowDepthRange shadow_scene_depth_range 0 //param_named_auto lightPositionObjectSpace light_position_object_space 0 //param_named_auto inverseWorldMatrix inverse_world_matrix param_named_auto worldMatrix3x4Array world_matrix_array_3x4 //param_named_auto viewProjectionMatrix viewproj_matrix //param_named_auto lightDiffuseColour light_diffuse_colour 0 //param_named_auto ambient ambient_light_colour //param_named_auto diffuse surface_diffuse_colour //param_named_auto emissive surface_emissive_colour } } fragment_program CelShading/ReceiverFP cg { source CelShadingShadow.cg entry_point receiverFP profiles arbfp1 ps_2_0 fp20 compile_arguments -DLINEAR_RANGE=0 -DSPECULAR=0 -DFUZZY_TEST=0 -DPCF=0 default_params { param_named inverseShadowmapSize float 0.0009765625 param_named fixedDepthBias float 0.01 param_named gradientClamp float 0.0098 param_named gradientScaleBias float 1 //param_named shadowFuzzyWidth float 0.3 param_named darken float 0.15 } }