1226 lines
46 KiB
PHP
1226 lines
46 KiB
PHP
|
|
/*
|
|
==================================================================================
|
|
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
|
|
|