饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

celshading搭配硬件蒙皮

Posted on 2012-11-15 10:45  饭后温柔  阅读(724)  评论(0编辑  收藏  举报

之前使用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
	}
}