/* ================================================================================== INTERACTION_VERTEX output: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyz is the normal transform 3 texcoord 6.xyzw is the shadow buffer coordinates ================================================================================== */ #template INTERACTION_VERTEX() { // texture 0 has four texgens for light projection and falloff result.texcoord0.x = dot4( position, $lightProjectionS ); result.texcoord0.y = dot4( position, $lightProjectionT ); result.texcoord0.z = dot4( position, $lightProjectionR ); result.texcoord0.w = dot4( position, $lightProjectionQ ); // Convert back from 16 bit vertex elements. float4 texcoord0 = ( vertex.texcoord0.xyxy * $vertexStScaleBias.xyxy + $vertexStScaleBias.zwzw ) + skinOffsets.xyzw; // texture 1 takes the base texture coordinates result.texcoord1 = texcoord0; float4 worldPosition; worldPosition.x = dot4( position, $modelMatrixX ); worldPosition.y = dot4( position, $modelMatrixY ); worldPosition.z = dot4( position, $modelMatrixZ ); worldPosition.w = dot4( position, $modelMatrixW ); // texture 2 takes the global position result.texcoord2.x = worldPosition.x; result.texcoord2.y = worldPosition.y; result.texcoord2.z = worldPosition.z; result.texcoord2.w = - dot4( worldPosition, $viewMatrixZ ); //transform the local space vectors to world space result.texcoord3.x = dot3( tangent, $modelMatrixX ); result.texcoord3.y = dot3( bitangent, $modelMatrixX ); result.texcoord3.z = dot3( normal, $modelMatrixX ); result.texcoord3.w = 1.0; result.texcoord4.x = dot3( tangent, $modelMatrixY ); result.texcoord4.y = dot3( bitangent, $modelMatrixY ); result.texcoord4.z = dot3( normal, $modelMatrixY ); result.texcoord4.w = 1.0; result.texcoord6.x = dot3( tangent, $modelMatrixZ ); result.texcoord6.y = dot3( bitangent, $modelMatrixZ ); result.texcoord6.z = dot3( normal, $modelMatrixZ ); result.texcoord6.w = 1.0; #ifndef NOSHADOW // texcoord 5 has the shadow buffer texcoords // transform local space xyz into light space result.texcoord5.x = dot4( position, $localToLightS ); result.texcoord5.y = dot4( position, $localToLightT ); result.texcoord5.z = dot4( position, $localToLightR ); result.texcoord5.w = dot4( position, $localToLightQ ); #endif // position result.position.x = dot4( position, $mvpMatrixX ); result.position.y = dot4( position, $mvpMatrixY ); result.position.z = dot4( position, $mvpMatrixZ ); result.position.w = dot4( position, $mvpMatrixW ); } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_BASIC Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_BASIC( shadow ) { //-------- non-wrapping virtual texture lookup ------------ float2 texcoord = fragment.texcoord1.xy; BRANCH if ( $useVirtualMapping.x > 0 ) { // this is basically only for non pre-lit levels, and shouldn't be used often. // this doesn't attempt to get the derivative correct at the frac crossing point texcoord = frac( texcoord ) * $virtualMapping.xy + $virtualMapping.zw; } float3 physCoord = VmtrVirtualToPhysical( texcoord ); //--------------------------------------------------------------- // load the virtual textures //--------------------------------------------------------------- #ifdef USE_VIRTUAL_ANISO_FOOTPRINT float2 dx = ddx( texcoord.xy ) * physCoord.z; float2 dy = ddy( texcoord.xy ) * physCoord.z; half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy ); #else half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy ); #endif specularPage.xyz = ScaleSpecular( specularPage.xyz, bumpPage.z ); bumpPage.z = 0; //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- float3 localNormal = float3( ( bumpPage.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- float3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); float3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { float3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, float2( lightTexCoord.z, 0.5 ) ); light = _float3( dot3( toLight, globalNormal ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } half3 specular; { #if 0 //--------------------------------------------------------------- // calculate the static specular at this point //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half3 reflection; reflection = ( 2.0 * globalNormal * dot3( globalNormal, toLight ) ) - toLight; // Use the absolute value of the dot, so we get static // highlights on both sides of objects. Oh, the horror! :-) float specularD = abs( dot3( reflection, $staticSpecularVector ) ); // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 to 64 scale float power = bumpPage.x * 64; float specularStrength = $staticSpecularScale.x * pow( specularD, power ); specular = specularStrength; #else //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - bumpPage.x ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * specularPage.xyz * $newSpecularScale.xyz; #endif } //--------------------------------------------------------------- // covert the diffuse from YCoCg //--------------------------------------------------------------- half4 diffuse; { YCoCg.z = ( YCoCg.z * 31.875 ) + 1.0; //z = z * 255.0/8.0 + 1.0 YCoCg.z = 1.0 / YCoCg.z; YCoCg.xy *= YCoCg.z; diffuse.x = dot4( YCoCg, matrixCoCg1YtoRGB1X ); diffuse.y = dot4( YCoCg, matrixCoCg1YtoRGB1Y ); diffuse.z = dot4( YCoCg, matrixCoCg1YtoRGB1Z ); diffuse.w = 1.0; diffuse.xyz *= $newDiffuseScale.xyz * 2.0; } //--------------------------------------------------------------- // sum everything up //--------------------------------------------------------------- half3 color = light * ( specular + diffuse.xyz ); result.color.rgb = color; result.color.a = 1; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_GRAZING Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_GRAZING( shadow ) { //-------- non-wrapping virtual texture lookup ------------ float2 texcoord = fragment.texcoord1.xy; BRANCH if ( $useVirtualMapping.x > 0 ) { // this is basically only for non pre-lit levels, and shouldn't be used often. // this doesn't attempt to get the derivative correct at the frac crossing point texcoord = frac( texcoord ) * $virtualMapping.xy + $virtualMapping.zw; } float3 physCoord = VmtrVirtualToPhysical( texcoord ); //--------------------------------------------------------------- // load the virtual textures //--------------------------------------------------------------- #ifdef USE_VIRTUAL_ANISO_FOOTPRINT float2 dx = ddx( texcoord.xy ) * physCoord.z; float2 dy = ddy( texcoord.xy ) * physCoord.z; half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy ); #else half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy ); #endif specularPage.xyz = ScaleSpecular( specularPage.xyz, bumpPage.z ); bumpPage.z = 0; //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- float3 localNormal = float3( ( bumpPage.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- float3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); float3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { float3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, float2( lightTexCoord.z, 0.5 ) ); light = _float3( dot3( toLight, globalNormal ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } half3 specular; { #if 0 //--------------------------------------------------------------- // calculate the static specular //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half3 reflection; reflection = ( 2.0 * globalNormal * dot3( globalNormal, toLight ) ) - toLight; // Use the absolute value of the dot, so we get static // highlights on both sides of objects. Oh, the horror! :-) float specularD = abs( dot3( reflection, $staticSpecularVector ) ); // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 to 64 scale float power = bumpPage.x * 64; float specularStrength = $staticSpecularScale.x * pow( specularD, power ); specular = specularStrength; #else //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - bumpPage.x ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * $newSpecularScale.xyz; #endif } //--------------------------------------------------------------- // covert the diffuse from YCoCg //--------------------------------------------------------------- half4 diffuse; { YCoCg.z = ( YCoCg.z * 31.875 ) + 1.0; //z = z * 255.0/8.0 + 1.0 YCoCg.z = 1.0 / YCoCg.z; YCoCg.xy *= YCoCg.z; diffuse.x = dot4( YCoCg, matrixCoCg1YtoRGB1X ); diffuse.y = dot4( YCoCg, matrixCoCg1YtoRGB1Y ); diffuse.z = dot4( YCoCg, matrixCoCg1YtoRGB1Z ); diffuse.w = 1.0; } //--------------------------------------------------------------- // Calculate the light grazing fraction //--------------------------------------------------------------- float graze = dot3( toViewer, globalNormal ); graze = saturate( ( $viewGraze.x - graze ) / ( $viewGraze.x + 0.0001 ) ); // The diffuse color will be a lerp between the diffuseMap and grazingDiffuseColor // and a modulate by the constant diffuse factor ( automatically scale newDiffuseScale // by 2.0 to match the baked-in behavior ) half3 grazingDiffuse = lerp( diffuse.xyz, $grazingDiffuseColor.xyz, graze ); half3 grazingSpecular = lerp( specularPage.xyz, $grazingSpecularColor.xyz, graze ); half3 color = light * ( specular * grazingSpecular + grazingDiffuse * $newDiffuseScale.xyz * 2.0 ); result.color.rgb = color; result.color.a = 1; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_SIMPLE Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_SIMPLE( shadow ) { //-------- non-wrapping virtual texture lookup ------------ float2 texcoord = fragment.texcoord1.xy; BRANCH if ( $useVirtualMapping.x > 0 ) { // this is basically only for non pre-lit levels, and shouldn't be used often. // this doesn't attempt to get the derivative correct at the frac crossing point texcoord = frac( texcoord ) * $virtualMapping.xy + $virtualMapping.zw; } float3 physCoord = VmtrVirtualToPhysical( texcoord ); //--------------------------------------------------------------- // load the virtual textures //--------------------------------------------------------------- #ifdef USE_VIRTUAL_ANISO_FOOTPRINT float2 dx = ddx( texcoord.xy ) * physCoord.z; float2 dy = ddy( texcoord.xy ) * physCoord.z; half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy ); #else half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy ); #endif specularPage.xyz = ScaleSpecular( specularPage.xyz, bumpPage.z ); bumpPage.z = 0; //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- float3 localNormal = float3( ( bumpPage.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- float3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); float3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { float3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, float2( lightTexCoord.z, 0.5 ) ); light = _float3( dot3( toLight, globalNormal ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- half3 specular; { // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shinny instead of dull, so invert it here reflection.w = floor( ( 1.0 - bumpPage.x ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * specularPage.xyz * $newSpecularScale.xyz; } half3 diffuse = _float3( 1.0f ); half3 color = light * ( specular + diffuse ); result.color.xyz = color; result.color.w = 1.0f; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_EYE For the cornea sclera we scale the diffuse towards black using the alpha so that the hole into the iris doesn't give off any diffuse color. We do keep the specular as is since we want the rounded glass shape the eye over the actual iris rendered underneath. Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_EYE( shadow ) { half power = 1.0; half4 sampleDiffuse = tex2D( $spareDiffuseMap, fragment.texcoord1.xy ); half4 sampleSpecular = tex2D( $spareSpecularMap, fragment.texcoord1.xy ); half4 sampleBump = tex2D( $spareBumpMap, fragment.texcoord1.xy ); //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- half3 localNormal = half3( ( sampleBump.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space half3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- half3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); half3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { half3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, half2( lightTexCoord.z, 0.5 ) ); light = _half3( saturate( dot3( toLight, globalNormal ) + 0.1 ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } half3 specular; { //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in ________ as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - power ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * sampleSpecular.xyz * $newSpecularScale.xyz; } { half3 toCameraLight = normalize( toViewer + half3( 0.0, 0.0, 6.5 ) ); half coss = saturate( dot3( globalNormal, toCameraLight ) ); specular += _half3( saturate( pow( coss, $eyeHighlightPowLevel.x ) * $eyeHighlightPowLevel.y ) ); } half3 diffuse = sampleDiffuse.xyz; // Scale diffuse so that we get black where the iris is supposed to be. diffuse *= _half3( saturate( ceil( sampleDiffuse.w - 0.5 ) ) ); half3 color = light * ( diffuse + specular ); result.color.xyz = color; result.color.w = 1; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_SKIN Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse-bump / diffuse / specular / ambient-occlusion texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_SKIN( shadow ) { //-------- non-wrapping virtual texture lookup ------------ half2 texcoord = fragment.texcoord1.xy; BRANCH if ( $useVirtualMapping.x > 0 ) { // this is basically only for non pre-lit levels, and shouldn't be used often. // this doesn't attempt to get the derivative correct at the frac crossing point texcoord = frac( texcoord ) * $virtualMapping.xy + $virtualMapping.zw; } half3 physCoord = VmtrVirtualToPhysical( texcoord ); //--------------------------------------------------------------- // load the virtual textures //--------------------------------------------------------------- #ifdef USE_VIRTUAL_ANISO_FOOTPRINT half2 dx = ddx( texcoord.xy ) * physCoord.z; half2 dy = ddy( texcoord.xy ) * physCoord.z; half4 sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy ); half4 sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy ); half4 sampleSpecularNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy ); #else half4 sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy ); half4 sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy ); half4 sampleSpecularNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy ); #endif //--------------------------------------------------------------- // load the diffuse normal and ambient occlusion //--------------------------------------------------------------- half4 sampleDiffuseNormal = tex2D( $spareBumpMap, fragment.texcoord1.xy ); half4 sampleAmbientOcclusion = tex2D( $transMap, fragment.texcoord1.xy ); float occlusionRes; half4 bumpRes; #ifdef INTERWRINKLE SAMPLE_WRINKLEMAPS( occlusionRes, bumpRes, sampleAmbientOcclusion, sampleDiffuseNormal, fragment.texcoord1 ); #else //INTERWRINKLE occlusionRes = sampleAmbientOcclusion.g; bumpRes = sampleDiffuseNormal; #endif //INTERWRINKLE //--------------------------------------------------------------- // convert the diffuse from YCoCg //--------------------------------------------------------------- half4 surfaceDiffuse; { sampleYCoCg.z = ( sampleYCoCg.z * 31.875 ) + 1.0; //z = z * 255.0/8.0 + 1.0 sampleYCoCg.z = 1.0 / sampleYCoCg.z; sampleYCoCg.xy *= sampleYCoCg.z; surfaceDiffuse.x = dot4( sampleYCoCg, matrixCoCg1YtoRGB1X ); surfaceDiffuse.y = dot4( sampleYCoCg, matrixCoCg1YtoRGB1Y ); surfaceDiffuse.z = dot4( sampleYCoCg, matrixCoCg1YtoRGB1Z ); surfaceDiffuse.w = 1.0; } //--------------------------------------------------------------- // scale specular //--------------------------------------------------------------- half3 surfaceSpecular; { surfaceSpecular.xyz = ScaleSpecular( sampleSpecular.xyz, sampleSpecularNormal.z ); sampleSpecularNormal.z = 0; } //--------------------------------------------------------------- // calculate global diffuse normal //--------------------------------------------------------------- half3 globalDiffuseNormal; { half3 localNormal = half3( ( bumpRes.wy * 2.0 ) - 1.0, 0.0 ); localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); globalDiffuseNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalDiffuseNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalDiffuseNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalDiffuseNormal = normalize( globalDiffuseNormal ); } //--------------------------------------------------------------- // calculate global specular normal //--------------------------------------------------------------- half3 globalSpecularNormal; { half3 localNormal = half3( ( sampleSpecularNormal.wy * 2.0 ) - 1.0, 0.0 ); localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); globalSpecularNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalSpecularNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalSpecularNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalSpecularNormal = normalize( globalSpecularNormal ); } //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- half3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); half3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // calculate and apply the diffuse light grazing //--------------------------------------------------------------- { half grazeDiffuse = dot3( toViewer, globalDiffuseNormal ); grazeDiffuse = saturate( ( $viewGraze.x - max( grazeDiffuse, -grazeDiffuse ) ) / max( $viewGraze.x, 0.0001 ) ); surfaceDiffuse.xyz = lerp( surfaceDiffuse.xyz, $grazingDiffuseColor.xyz, grazeDiffuse ); } //--------------------------------------------------------------- // calculate and apply the specular light grazing //--------------------------------------------------------------- { half grazeSpecular = dot3( toViewer, globalSpecularNormal ); grazeSpecular = saturate( ( $viewGraze.x - max( grazeSpecular, -grazeSpecular ) ) / max( $viewGraze.x, 0.0001 ) ); surfaceSpecular.xyz = lerp( surfaceSpecular.xyz, $grazingSpecularColor.xyz, grazeSpecular ); } //--------------------------------------------------------------- // apply specular reflection //--------------------------------------------------------------- { // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalSpecularNormal * dot3( globalSpecularNormal, toViewer ) ) - toViewer; // power factor is stored in sampleSpecularNormal.x as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - sampleSpecularNormal.x ) * 4.0 + $newPowerScale.x ); // sample envColor from the environment map half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; // apply surfaceSpecular *= envColor; } //--------------------------------------------------------------- // diffuse light is the dot between the diffuse surface normal and the light, // this is then used to lookup a warp value in a texture //--------------------------------------------------------------- half3 diffuseLight; { // pw-note: I get super weird artifacts on edges if I don't clamp them down, probably texture filtering? :( // it's weird I don't get them in the skinVmtr programs though (?) half cosd = max( min( dot3( toLight, globalDiffuseNormal ) * 0.5 + 0.5, 0.99 ), 0.01 ); half3 diffuseWarp = tex2D( $textureMap, half2( cosd, 0.0 ) ).xyz; diffuseLight = diffuseWarp; } //--------------------------------------------------------------- // specular light is the dot between the specular surface normal and the light //--------------------------------------------------------------- half3 specularLight; { half coss = saturate( dot3( toLight, globalSpecularNormal ) ); specularLight = _half3( coss ); } //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 lightColor; { half3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, half2( lightTexCoord.z, 0.5 ) ); // Modulate with ambient occlusion (this is not really correct) lightColor = _float3( occlusionRes ); // modulate by the light projection and falloff lightColor *= lpm.xyz * lfm.xyz; // modulate by the light color lightColor *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade lightColor *= ( shadow * $shadowFade.x ) + $shadowFade.y; } //--------------------------------------------------------------- // apply light scale on diffuse and specular //--------------------------------------------------------------- { diffuseLight *= lightColor; specularLight *= lightColor; } //--------------------------------------------------------------- // apply diffuse and specular scales //--------------------------------------------------------------- { surfaceDiffuse.xyz *= $newDiffuseScale.xyz * 2.0; surfaceSpecular.xyz *= $newSpecularScale.xyz; } //--------------------------------------------------------------- // sum everything up //--------------------------------------------------------------- half3 color = _half3( 0.0 ); color += specularLight * surfaceSpecular.xyz; color += diffuseLight * surfaceDiffuse.xyz; result.color.rgb = color; result.color.a = 1; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_HAIR Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_HAIR( shadow ) { float2 texcoord2 = fragment.texcoord7.xy; //--------------------------------------------------------------- // load the coverage and clip pixel if not visible //--------------------------------------------------------------- half4 coverage; { coverage = tex2D( $transMap, texcoord2 ); } clip( coverage.w - 0.25 ); //-------- non-wrapping virtual texture lookup ------------ float2 texcoord = fragment.texcoord1.xy; BRANCH if ( $useVirtualMapping.x > 0 ) { // this is basically only for non pre-lit levels, and shouldn't be used often. // this doesn't attempt to get the derivative correct at the frac crossing point texcoord = frac( texcoord ) * $virtualMapping.xy + $virtualMapping.zw; } float3 physCoord = VmtrVirtualToPhysical( texcoord ); //--------------------------------------------------------------- // load the virtual textures //--------------------------------------------------------------- #ifdef USE_VIRTUAL_ANISO_FOOTPRINT float2 dx = ddx( texcoord.xy ) * physCoord.z; float2 dy = ddy( texcoord.xy ) * physCoord.z; half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy ); #else half4 specularPage = texPhys( $physicalVmtrPagesMap0, physCoord.xy ); half4 YCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy ); half4 bumpPage = texPhys( $physicalVmtrPagesMap2, physCoord.xy ); #endif specularPage.xyz = ScaleSpecular( specularPage.xyz, bumpPage.z ); bumpPage.z = 0; //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- float3 localNormal = float3( ( bumpPage.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- float3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); float3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { float3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, float2( lightTexCoord.z, 0.5 ) ); light = _float3( dot3( toLight, globalNormal ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } half3 specular; { //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in bumpPage.x as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - bumpPage.x ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * specularPage.xyz * $newSpecularScale.xyz; } //--------------------------------------------------------------- // covert the diffuse from YCoCg //--------------------------------------------------------------- half4 diffuse; { YCoCg.z = ( YCoCg.z * 31.875 ) + 1.0; //z = z * 255.0/8.0 + 1.0 YCoCg.z = 1.0 / YCoCg.z; YCoCg.xy *= YCoCg.z; diffuse.x = dot4( YCoCg, matrixCoCg1YtoRGB1X ); diffuse.y = dot4( YCoCg, matrixCoCg1YtoRGB1Y ); diffuse.z = dot4( YCoCg, matrixCoCg1YtoRGB1Z ); diffuse.w = 1.0; diffuse.xyz *= $newDiffuseScale.xyz * 2.0; } //--------------------------------------------------------------- // sum everything up //--------------------------------------------------------------- half3 color = light * ( specular + diffuse.xyz ); result.color.rgb = color; result.color.a = 1; } #endtemplate /* ================================================================================== INTERACTION_FRAGMENT_BASIC_NOVMTR Should the color of the light influence the environment color? probably. vertex input: texcoord 0.xyzw is the light projection / falloff texture coordinates texcoord 1.xy is the bump / diffuse / specular texture coordinate texcoord 2.xyz is the global vertex position after model matrix transform texcoord 3.xyz is the normal transform 1 texcoord 4.xyz is the normal transform 2 texcoord 5.xyzw is the shadow buffer coordinates texcoord 6.xyz is the normal transform 3 in float shadow; render parms: globalViewOrigin globalLightOrigin ================================================================================== */ #template INTERACTION_FRAGMENT_BASIC_NOVMTR( shadow ) { float2 texcoord = fragment.texcoord1.xy; //--------------------------------------------------------------- // sample diffuse, bump, specular textures //--------------------------------------------------------------- half4 sampleDiffuse = tex2D( $spareDiffuseMap, texcoord ); half4 sampleSpecular = tex2D( $spareSpecularMap, texcoord ); half4 sampleBump = tex2D( $spareBumpMap, texcoord ); //--------------------------------------------------------------- // sample morph diffuse, bump, specular textures and interpolate //--------------------------------------------------------------- BRANCH if ( $useSkinBlending.x > 0.0 ) { // fragment.htexcoord3.w > 0.0 half4 sampleDiffuse2 = tex2D( $spareDiffuseMap2, texcoord ); half4 sampleSpecular2 = tex2D( $spareSpecularMap2, texcoord ); half4 sampleBump2 = tex2D( $spareBumpMap2, texcoord ); half morphScale = fragment.htexcoord3.w; sampleDiffuse = lerp( sampleDiffuse, sampleDiffuse2, morphScale ); sampleSpecular = lerp( sampleSpecular, sampleSpecular2, morphScale ); sampleBump = lerp( sampleBump, sampleBump2, morphScale ); } //--------------------------------------------------------------- // derive localNormal, then transform to a global normal //--------------------------------------------------------------- float3 localNormal = float3( ( sampleBump.wy * 2.0 ) - 1.0, 0.0 ); // derive the localNormal.z component localNormal.z = sqrt( abs( 1.0 - dot3( localNormal, localNormal ) ) ); // transform into global space float3 globalNormal; globalNormal.x = dot3( localNormal, fragment.htexcoord3 ); globalNormal.y = dot3( localNormal, fragment.htexcoord4 ); globalNormal.z = dot3( localNormal, fragment.htexcoord6 ); globalNormal = normalize( globalNormal ); //--------------------------------------------------------------- // normalize the directions to the light and viewer //--------------------------------------------------------------- float3 toLight = normalize( $globalLightOrigin.xyz - fragment.texcoord2.xyz ); float3 toViewer = normalize( $globalViewOrigin.xyz - fragment.texcoord2.xyz ); //--------------------------------------------------------------- // Incoming light color is the product of two light projection // texture maps, the light color parameter, the dor with the surface // normal, and the faded shadow factor // optimize: if we assumed one or both of the light maps are monochrome, // we could save some math. //--------------------------------------------------------------- half3 light; { float3 lightTexCoord = fragment.htexcoord0.xyz / fragment.htexcoord0.w; half4 lpm = h4tex2D( $lightProjectMap, lightTexCoord.xy ); half4 lfm = h4tex2D( $lightFalloffMap, float2( lightTexCoord.z, 0.5 ) ); light = _float3( dot3( toLight, globalNormal ) ); // modulate by the light projection and falloff light *= lpm.xyz * lfm.xyz; // modulate by the light color light *= $lightColor.xyz; // modulate by the shadow factor adjusted by the shadow fade light *= ( shadow * $shadowFade.x ) + $shadowFade.y; } half3 specular; half power = 1.0; { #if 0 //--------------------------------------------------------------- // calculate the static specular at this point //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half3 reflection; reflection = ( 2.0 * globalNormal * dot3( globalNormal, toLight ) ) - toLight; // Use the absolute value of the dot, so we get static // highlights on both sides of objects. Oh, the horror! :-) float specularD = abs( dot3( reflection, $staticSpecularVector ) ); // power factor is stored in __________ as 0.0 - 1.0, we want a 0 to 64 scale float factor = power * 64; float specularStrength = $staticSpecularScale.x * pow( specularD, factor ); specular = specularStrength; #else //--------------------------------------------------------------- // sample envColor from the environment map //--------------------------------------------------------------- // reflection vector = 2 * N * ( N . V ) - V half4 reflection; reflection.xyz = ( 2.0 * globalNormal * dot3( globalNormal, toViewer ) ) - toViewer; // power factor is stored in __________ as 0.0 - 1.0, we want a 0 | 1 | 2 | 3 mip value // we could probably skip the floor, but I am wary of hardware / api rounding // the artists really prefer white to be shiny instead of dull, so invert it here reflection.w = floor( ( 1.0 - power ) * 4.0 + $newPowerScale.x ); half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz; specular = envColor * sampleSpecular.xyz * $newSpecularScale.xyz; #endif } //--------------------------------------------------------------- // scale the diffuse from texture sample //--------------------------------------------------------------- half4 diffuse; { diffuse.xyz = sampleDiffuse.xyz * $newDiffuseScale.xyz * 2.0; diffuse.w = 1.0; } //--------------------------------------------------------------- // sum everything up //--------------------------------------------------------------- half3 color = light * ( specular + diffuse.xyz ); result.color.rgb = color; result.color.a = 1; } #endtemplate