Files
2026-08-09 04:23:10 -07:00

971 lines
35 KiB
ObjectPascal

/*
==================================================================================
CALC_VMTR_TEXCOORD
uses fragment.texcoord0;
out half4 texCoord
==================================================================================
*/
#template CALC_VMTR_TEXCOORD( texCoord )
{
texCoord = fragment.texcoord0;
/*-------- non-wrapping virtual texture lookup ------------*/
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. */
#ifdef VMTR_TEXCOORD_SKIP_FRAC
texCoord = texCoord * $virtualMapping.xyxy + $virtualMapping.zwzw;
#else
texCoord = frac( texCoord ) * $virtualMapping.xyxy + $virtualMapping.zwzw;
#endif
}
}
#endtemplate
/*
==================================================================================
FETCH_VMTR
uses fragment.texcoord0;
out half4 sampleSpecular;
out half4 sampleYCoCg;
out half4 sampleNormal;
out half2 feedbackTexCoord;
==================================================================================
*/
#template FETCH_VMTR( sampleSpecular, sampleYCoCg, sampleNormal, feedbackTexCoord )
{
float4 texCoord;
CALC_VMTR_TEXCOORD( texCoord );
float3 physCoord = VmtrVirtualToPhysical( texCoord.xy );
#ifdef USE_VIRTUAL_ANISO_FOOTPRINT
float2 dx = ddx( texCoord.xy ) * physCoord.z;
float2 dy = ddy( texCoord.xy ) * physCoord.z;
sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy );
sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy );
sampleNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy );
#else
sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy );
sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy );
sampleNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy );
#endif
feedbackTexCoord = texCoord.xy;
}
#endtemplate
/*
==================================================================================
FETCH_VMTR_BLEND
uses fragment.texcoord0;
out half4 sampleSpecular;
out half4 sampleYCoCg;
out half4 sampleNormal;
out half2 feedbackTexCoord;
in half morphScale;
==================================================================================
*/
#template FETCH_VMTR_BLEND( sampleSpecular, sampleYCoCg, sampleNormal, feedbackTexCoord, morphScale )
{
float4 texCoord;
CALC_VMTR_TEXCOORD( texCoord );
float3 physCoord = VmtrVirtualToPhysical( texCoord.xy );
#ifdef USE_VIRTUAL_ANISO_FOOTPRINT
float2 dx = ddx( texCoord.xy ) * physCoord.z;
float2 dy = ddy( texCoord.xy ) * physCoord.z;
sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy );
sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy );
sampleNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy );
#else
sampleSpecular = texPhys( $physicalVmtrPagesMap0, physCoord.xy );
sampleYCoCg = texPhys( $physicalVmtrPagesMap1, physCoord.xy );
sampleNormal = texPhys( $physicalVmtrPagesMap2, physCoord.xy );
#endif
feedbackTexCoord = texCoord.xy;
/* blend in another texture based on the morph map */
BRANCH if ( $useSkinBlending.x > 0.0 ) {
float3 physCoord = VmtrVirtualToPhysical( texCoord.zw );
#ifdef USE_VIRTUAL_ANISO_FOOTPRINT
float2 dx = ddx( texCoord.zw ) * physCoord.z;
float2 dy = ddy( texCoord.zw ) * physCoord.z;
float4 sampleSpecular2 = texPhys( $physicalVmtrPagesMap0, physCoord.xy, dx, dy );
float4 sampleYCoCg2 = texPhys( $physicalVmtrPagesMap1, physCoord.xy, dx, dy );
float4 sampleNormal2 = texPhys( $physicalVmtrPagesMap2, physCoord.xy, dx, dy );
#else
float4 sampleSpecular2 = texPhys( $physicalVmtrPagesMap0, physCoord.xy );
float4 sampleYCoCg2 = texPhys( $physicalVmtrPagesMap1, physCoord.xy );
float4 sampleNormal2 = texPhys( $physicalVmtrPagesMap2, physCoord.xy );
#endif
sampleSpecular = lerp( sampleSpecular, sampleSpecular2, morphScale );
sampleYCoCg = lerp( sampleYCoCg, sampleYCoCg2, morphScale );
sampleNormal = lerp( sampleNormal, sampleNormal2, morphScale );
float2 fp = fragment.position.xy * $positionToFeedback.zw;
float2 xy = frac( fp ) - 0.5;
feedbackTexCoord = ( xy.x * xy.y < 0.0 ) ? texCoord.xy : texCoord.zw;
}
}
#endtemplate
/*
==================================================================================
CALC_VMTR_FEEDBACK
in half2 feedbackTexCoord;
out float4 feedback;
==================================================================================
*/
#template CALC_VMTR_FEEDBACK( feedback, feedbackTexCoord )
{
feedback = PackFeedback( CalculateFeedback( feedbackTexCoord, $virtualTextureFeedbackFloat, $physicalVmtrFilterParms ) );
}
#endtemplate
/*
==================================================================================
CALC_DIFFUSE_RGB
in half4 sampleYCoCg;
inout half4 diffuse;
==================================================================================
*/
#template CALC_DIFFUSE_RGB( diffuse, sampleYCoCg )
{
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;
diffuse.x = dot4( sampleYCoCg, matrixCoCg1YtoRGB1X );
diffuse.y = dot4( sampleYCoCg, matrixCoCg1YtoRGB1Y );
diffuse.z = dot4( sampleYCoCg, matrixCoCg1YtoRGB1Z );
}
#endtemplate
/*
==================================================================================
CALC_SPECULAR_RGB
==================================================================================
*/
#template CALC_SPECULAR_RGB( specular, sampleSpecular, specularScale )
{
specular = sampleSpecular.xyz * 8.0 / ( specularScale * 255.0 + 8.0 );
specular += 0.001;
}
#endtemplate
/*
==================================================================================
CALC_LOCAL_NORMAL
==================================================================================
*/
#template CALC_LOCAL_NORMAL( localNormal, sampleNormal )
{
/* Note that the optimized derivation of the localNormal below results */
/* in a vector that is half-unit length! */
localNormal = sampleNormal.wyz - 0.5;
localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );
}
#endtemplate
/*
==================================================================================
CALC_SMOOTH_NORMAL
==================================================================================
*/
#template CALC_SMOOTH_NORMAL( smoothNormal, localToGlobalX, localToGlobalY, localToGlobalZ )
{
smoothNormal.x = localToGlobalX.z;
smoothNormal.y = localToGlobalY.z;
smoothNormal.z = localToGlobalZ.z;
smoothNormal = normalize( smoothNormal );
}
#endtemplate
/*
==================================================================================
CALC_GLOBAL_NORMAL
==================================================================================
*/
#template CALC_GLOBAL_NORMAL( globalNormal, sampleNormal, localToGlobalX, localToGlobalY, localToGlobalZ )
{
/* Note that the optimized derivation of the localNormal below results */
/* in a vector that is half-unit length! */
half3 localNormal = sampleNormal.wyz - 0.5;
localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );
/* transform the normal into ambient map space */
globalNormal.x = dot3( localNormal, localToGlobalX );
globalNormal.y = dot3( localNormal, localToGlobalY );
globalNormal.z = dot3( localNormal, localToGlobalZ );
globalNormal = normalize( globalNormal );
}
#endtemplate
/*
==================================================================================
CALC_GLOBAL_NORMAL_TWOSIDED
==================================================================================
*/
#template CALC_GLOBAL_NORMAL_TWOSIDED( globalNormal, sampleNormal, localToGlobalX, localToGlobalY, localToGlobalZ )
{
/* Note that the optimized derivation of the localNormal below results */
/* in a vector that is half-unit length! */
half3 localNormal = sampleNormal.wyz - 0.5;
localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );
/* flip the normal around if looking at the back side */
#if defined( XBOX )
if ( fragment.facing > 0 ) {
localNormal.z = -localNormal.z;
}
#elif defined( PS3 )
if ( fragment.face < 0 ) {
localNormal.z = -localNormal.z;
}
#elif defined( GLSL )
if ( !gl_FrontFacing ) {
localNormal.z = -localNormal.z;
}
#endif
/* transform the normal into ambient map space */
globalNormal.x = dot3( localNormal, localToGlobalX );
globalNormal.y = dot3( localNormal, localToGlobalY );
globalNormal.z = dot3( localNormal, localToGlobalZ );
globalNormal = normalize( globalNormal );
}
#endtemplate
/*
==================================================================================
CALC_FROM_VIEWER
==================================================================================
*/
#template CALC_FROM_VIEWER( fromViewerN, fromViewer )
{
fromViewerN = normalize( fromViewer.xyz );
}
#endtemplate
/*
==================================================================================
CALC_GLOBAL_REFLECTION
==================================================================================
*/
#template CALC_GLOBAL_REFLECTION( globalReflection, globalNormal, fromViewerN )
{
// reflection vector
globalReflection.xyz = fromViewerN - ( globalNormal * dot3( fromViewerN, globalNormal ) * 2.0 );
}
#endtemplate
/*
==================================================================================
SAMPLE_DIMSHADOW_BUFFER
==================================================================================
*/
#template SAMPLE_DIMSHADOW_BUFFER( shadow )
{
// this is normalized window space, not strict openGL window space
// that uses integer viewport values.
float3 window;
window.xy = screenPosToTexcoord( fragment.position.xy, $renderPositionToViewTexture );
// fetch the window space depth value
window.z = tex2Ddepth( $viewDepthMap, window.xy );
float4 wclip = float4( window.xyz, 1.0f );
// now transform to the light clip space
float4 light;
light.x = dot4( wclip, $windowPosToDimShadowBlurS );
light.y = dot4( wclip, $windowPosToDimShadowBlurT );
light.z = dot4( wclip, $windowPosToDimShadowBlurR );
light.w = dot4( wclip, $windowPosToDimShadowBlurQ );
// divide by w to get to light device coordinates
light.xyz /= light.w;
// move the -1.0 - 1.0 light device st to the 0.0 - 1.0 texture range
#ifdef XBOX
light.xy = ( light * 0.5 ) + 0.5; // don't adjust z, it is already 0 - 1
#else
light = ( light * 0.5 ) + 0.5;
#endif
#ifndef PC
light.y = 1.0 - light.y; // image y origin adjust
#endif
// clamp before sampling, because the shadow depth map may have
// only been updated in a restricted viewport
light.xy = min( light.xy, 0.99 );
light.xy = max( light.xy, 0.01 );
// make sure that the cleared z = 1.0 in the shadow buffer
// will always be farther away than any world surface
light.z = min( light.z, 0.9999999 );
// four samples
float2 tc = fragment.position.xy * float2( 1.0/128, 1.0/128 ) + $viewRandom.xy;
float2 dither = tex2D( $dither256map, tc ).xw;
const float step = 1.0 / 768.0; // FIXME: hard coded dim-shadow buffer size
float3 center;
// this biases by +1.5 on average, so we can test -3, -2, -1, 0 offsets
center.xy = light.xy + step + dither * step;
center.z = light.z;
shadow = shadow2Ddepth( $dimShadowDepthMap, center + float3( -2*step, -2*step, 0 ) );
shadow += shadow2Ddepth( $dimShadowDepthMap, center + float3( -1*step, -2*step, 0 ) );
shadow += shadow2Ddepth( $dimShadowDepthMap, center + float3( -2*step, -1*step, 0 ) );
shadow += shadow2Ddepth( $dimShadowDepthMap, center + float3( -1*step, -1*step, 0 ) );
shadow *= 0.25;
}
#endtemplate
/*
==================================================================================
APPLY_MODEL_FADE
==================================================================================
*/
#template APPLY_MODEL_FADE()
{
BRANCH if ( $modelFade.x < 1.0 ) {
float2 texcoord = fragment.position.xy * ( 1.0 / 256.0 );
float dither = tex2D( $dither256Map, texcoord ).x;
// 1 - fully opaque - 0.8 - stippling - 0.2 - fully transparent - 0
clip( $modelFade.x - 0.2 - dither * 0.6 );
}
}
#endtemplate
/*
==================================================================================
CALC_GRAZING
==================================================================================
*/
#template CALC_GRAZING( graze, globalNormal, fromViewerN )
{
/* calculate the view grazing fraction */
graze = saturate( dot3( -fromViewerN, globalNormal ) );
graze = saturate( ( $viewGraze.x - max( graze, -graze ) ) / max( $viewGraze.x, 0.0001 ) );
}
#endtemplate
/*
==================================================================================
APPLY_DIFFUSE_GRAZING
==================================================================================
*/
#template APPLY_DIFFUSE_GRAZING( diffuse, graze )
{
diffuse.xyz = lerp( diffuse.xyz, $grazingDiffuseColor.xyz, graze );
}
#endtemplate
/*
==================================================================================
APPLY_SPECULAR_GRAZING
==================================================================================
*/
#template APPLY_SPECULAR_GRAZING( specular, graze )
{
specular.xyz = lerp( specular.xyz, $grazingSpecularColor.xyz, graze );
}
#endtemplate
/*
==================================================================================
APPLY_GRAZING
==================================================================================
*/
#template APPLY_GRAZING( diffuse, specular, globalNormal, fromViewerN )
{
half graze;
CALC_GRAZING( graze, globalNormal, fromViewerN );
APPLY_DIFFUSE_GRAZING( diffuse, graze, );
APPLY_SPECULAR_GRAZING( specular, graze );
}
#endtemplate
/*
==================================================================================
APPLY_GRAZINGS
==================================================================================
*/
#template APPLY_GRAZINGS( diffuse, globalDiffuseNormal, specular, globalSpecularNormal, fromViewerN )
{
half grazeDiffuse;
half grazeSpecular;
CALC_GRAZING( grazeDiffuse, globalDiffuseNormal, fromViewerN );
CALC_GRAZING( grazeSpecular, globalSpecularNormal, fromViewerN );
APPLY_DIFFUSE_GRAZING( diffuse, grazeDiffuse );
APPLY_SPECULAR_GRAZING( specular, grazeSpecular );
}
#endtemplate
/*
==================================================================================
APPLY_RIMLIGHT
==================================================================================
*/
#template APPLY_RIMLIGHT( diffuse, globalNormal, fromViewer )
{
/* calculate the view grazing fraction */
half graze = 1.0 - saturate( dot3( -normalize( fromViewer ), globalNormal ) );
graze *= saturate( globalNormal.z );
graze = pow( graze, $RimlightColor.w );
diffuse.xyz += $rimlightColor.xyz * _half3( graze );
}
#endtemplate
/*
==================================================================================
APPLY_SCALING_SPECULAR
==================================================================================
*/
#template APPLY_SCALING_SPECULAR( specular )
{
specular.xyz *= $newSpecularScale.xyz;
}
#endtemplate
/*
==================================================================================
APPLY_SCALING_DIFFUSE
==================================================================================
*/
#template APPLY_SCALING_DIFFUSE( diffuse )
{
diffuse.xyz *= $newDiffuseScale.xyz * 2.0; /* why times two? */
}
#endtemplate
/*
==================================================================================
APPLY_SCALING
==================================================================================
*/
#template APPLY_SCALING( diffuse, specular )
{
APPLY_SCALING_DIFFUSE( diffuse )
APPLY_SCALING_SPECULAR( specular );
}
#endtemplate
/*
==================================================================================
APPLY_SPECULAR_REFLECTION
==================================================================================
*/
#template APPLY_SPECULAR_REFLECTION( specular, power, globalReflection )
{
/* Power factor is stored in sampleNormal.x as 0.0 - 1.0 */
/* We want a 0 | 1 | 2 | 3 mip value. */
/* The artists really prefer white to be shiny instead of dull, so invert it here. */
/* We could probably skip the floor, but I am wary of hardware / api rounding. */
globalReflection.w = floor( ( 1.0 - power ) * 4.0 + $newPowerScale.x );
half3 envColor = texCUBElod( $dynamicEnvMap, globalReflection ).xyz;
/* modulate by the environment mask map (specular channel) */
specular *= envColor;
}
#endtemplate
/*
==================================================================================
APPLY_FOLIAGE_SPECULAR
==================================================================================
*/
#template APPLY_FOLIAGE_SPECULAR( specular, power, globalNormal, fromViewer )
{
/* calculate the specular reflection vector from viewer and globalNormal */
half4 reflection;
reflection.xyz = fromViewer - ( globalNormal * dot3( fromViewer, globalNormal ) * 2.0 );
/* Power factor is stored in sampleNormal.x as 0.0 - 1.0 */
/* We want a 0 | 1 | 2 | 3 mip value. */
/* The artists really prefer white to be shiny instead of dull, so invert it here. */
/* We could probably skip the floor, but I am wary of hardware / api rounding. */
reflection.w = floor( ( 1.0 - power ) * 4.0 + $newPowerScale.x );
half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz;
/* modulate by the environment mask map (specular channel) */
envColor = lerp( _half3( max( max( envColor.x, envColor.y ), envColor.z ) ), envColor, _half3( $envSatScalePower.x ) );
envColor = pow( envColor, _half3( $envSatScalePower.z ) );
//envColor *= _half3( saturate( globalNormal.z + 1.0 ) );
specular *= envColor * _half3( $envSatScalePower.y );
}
#endtemplate
/*
==================================================================================
APPLY_PHYSICAL_SPECULAR
==================================================================================
*/
#template APPLY_PHYSICAL_SPECULAR( specular, surfaceSpecular, globalNormal, fromViewer )
{
/* calculate the specular reflection vector from viewer and globalNormal */
half4 reflection;
reflection.xyz = fromViewer - ( globalNormal * dot3( fromViewer, globalNormal ) * 2.0 );
//extract the color from the specular map
half3 specColor = normalize( surfaceSpecular.xyz ) * _half3( 1.73 );
//the gloss map is a greyscale version of the specular map
half glossMask = ( surfaceSpecular.x + surfaceSpecular.y + surfaceSpecular.z ) * 0.333;
//make dark parts of the spec map have less color
specColor = lerp( _half3( 1.0 ), specColor, glossMask );
glossMask = glossMask * $maxGloss.x;
half piMul = 0.039808917197; // 1 / ( pi * 8 )
half3 pSpecMask = _half3( ( glossMask + 8.0 ) * piMul );
half3 pSpecular = _half3( saturate( dot3( normalize( reflection.xyz ), $primeLightDir.xyz ) ) );
pSpecular *= pow( pSpecular, _half3( glossMask ) );
pSpecular *= $primeLightColor.xyz;
pSpecular *= pSpecMask * specColor;
specular += pSpecular;
}
#endtemplate
/*
==================================================================================
APPLY_MUZZLE_FLASH
==================================================================================
*/
#template APPLY_MUZZLE_FLASH( color, surfaceDiffuse, globalNormal, MFVector )
{
half muzzleFlash = saturate( dot( MFVector, globalNormal ) );
color.xyz += _half3( $gunMuzzleFlash.x * muzzleFlash * $gunMuzzleFlashColor.w ) * $gunMuzzleFlashColor.xyz * surfaceDiffuse;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING_FOLIAGE
==================================================================================
*/
#template APPLY_LIGHTING_FOLIAGE( color, diffuse, specular, trueNormal, fromViewer, treeMask, transmissionMask )
{
//half treeMaskFromZ = saturate( ( 1.0 - treeMask ) * 5.0 );
//half3 trueNormal = lerp( globalNormal, treeNormal, 0.9 * treeMaskFromZ );
half ndotl = dot3( $primeLightDir, trueNormal );
half3 primeLightFactor = _half3( saturate( ndotl ) );
half3 primeLight = $primeLightColor.xyz * primeLightFactor;
half3 channelLight =
+ max( trueNormal.x * $channelLight0.xyz, 0 )
+ max( -trueNormal.x * $channelLight1.xyz, 0 )
+ max( trueNormal.y * $channelLight2.xyz, 0 )
+ max( -trueNormal.y * $channelLight3.xyz, 0 )
+ max( trueNormal.z * $channelLight4.xyz, 0 )
+ max( -trueNormal.z * $channelLight5.xyz, 0 );
half backLightFactor = pow( saturate( dot3( $primeLightDir, normalize( fromViewer ) ) ), 5.0 );
half backLightFalloff = pow( 1.0 - abs( ndotl ), 3.0 );
backLightFactor *= backLightFalloff * 3.0;
half3 backLight = $primeLightColor.xyz * transmissionMask.xyz * treeMask * backLightFactor;
half3 light = primeLight + channelLight + backLight;
/* maximum amount of dim-shadowing based on the pime light contribution */
float acceptDimShadow = max( primeLightFactor.x, max( primeLightFactor.y, primeLightFactor.z ) ) * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
color.xyz = light * ( diffuse + specular );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING
==================================================================================
*/
#template APPLY_LIGHTING( color, diffuse, specular, globalNormal )
{
half primeLightFactor = saturate( dot3( $primeLightDir, globalNormal ) );
half3 primeLight = $primeLightColor.xyz * primeLightFactor;
half3 channelLight =
+ max( globalNormal.x * $channelLight0.xyz, 0 )
+ max( -globalNormal.x * $channelLight1.xyz, 0 )
+ max( globalNormal.y * $channelLight2.xyz, 0 )
+ max( -globalNormal.y * $channelLight3.xyz, 0 )
+ max( globalNormal.z * $channelLight4.xyz, 0 )
+ max( -globalNormal.z * $channelLight5.xyz, 0 );
half3 light = primeLight + channelLight;
/* maximum amount of dim-shadowing based on the pime light contribution */
float acceptDimShadow = primeLightFactor * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
color.xyz = light * ( diffuse + specular );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING_NOAMBIENT
==================================================================================
*/
#template APPLY_LIGHTING_NOAMBIENT( color, diffuse, specular, globalNormal )
{
half primeLightFactor = saturate( dot3( $primeLightDir, globalNormal ) );
half3 primeLight = $primeLightColor.xyz * primeLightFactor;
half3 light = primeLight;
/* maximum amount of dim-shadowing based on the pime light contribution */
float acceptDimShadow = primeLightFactor * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
color.xyz = light * ( diffuse + specular );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING_ZHEIGHT
==================================================================================
*/
#template APPLY_LIGHTING_ZHEIGHT( color, diffuse, specular, globalNormal, height )
{
half primeLightFactor = saturate( dot3( $primeLightDir, globalNormal ) );
half3 primeLight = $primeLightColor.xyz * primeLightFactor;
half3 channelLight =
+ max( globalNormal.x * $channelLight0.xyz, 0 )
+ max( -globalNormal.x * $channelLight1.xyz, 0 )
+ max( globalNormal.y * $channelLight2.xyz, 0 )
+ max( -globalNormal.y * $channelLight3.xyz, 0 )
+ max( globalNormal.z * $channelLight4.xyz, 0 )
+ max( -globalNormal.z * $channelLight5.xyz, 0 );
half3 light = primeLight + channelLight;
/* modulate by the z-height blend */
light = lerp( channelLight, light, height );
/* maximum amount of dim-shadowing based on the pime light contribution */
float acceptDimShadow = primeLightFactor * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
color.xyz = light * ( diffuse + specular );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING_KEY
==================================================================================
*/
#template APPLY_LIGHTING_KEY( color, diffuse, specular, power, globalNormal, fromViewer,
primaryShadow, secondaryShadow, ambientScale, directScale )
{
half3 fromViewerN;
half3 globalReflection;
// reflection vector
CALC_FROM_VIEWER( fromViewerN, fromViewer );
CALC_GLOBAL_REFLECTION( globalReflection, globalNormal, fromViewerN );
half3 specularLight;
half3 diffuseLight;
//---------------------------------------------------------------
// primary light
//---------------------------------------------------------------
float primaryFactor = saturate( dot3( $primeLightDir, globalNormal ) );
float3 primeLight = primaryShadow * $primeLightColor.xyz * primaryFactor;
diffuseLight = primeLight;
// classic specular calculation
// power factor is stored in bumpPage.x as 0.0 - 1.0, with 1.0 being tightest highlights
float specDot = saturate( dot3( $primeLightDir, globalReflection ) );
specDot = pow( specDot, 1 + power * 40 );
specularLight = primeLight * specDot;
//---------------------------------------------------------------
// secondary light
//---------------------------------------------------------------
float secondaryFactor = saturate( dot3( $secondaryLightDir, globalNormal ) );
float3 secondaryLight = secondaryShadow * $secondaryLightColor.xyz * secondaryFactor;
diffuseLight += secondaryLight;
specDot = saturate( dot3( $secondaryLightDir, globalReflection ) );
specDot = pow( specDot, 1 + power * 40 );
specularLight += secondaryLight * specDot;
//---------------------------------------------------------------
// ambient lighting
//---------------------------------------------------------------
float3 ambientLight =
+ max( globalNormal.x * $channelLight0.xyz, 0 )
+ max( -globalNormal.x * $channelLight1.xyz, 0 )
+ max( globalNormal.y * $channelLight2.xyz, 0 )
+ max( -globalNormal.y * $channelLight3.xyz, 0 )
+ max( globalNormal.z * $channelLight4.xyz, 0 )
+ max( -globalNormal.z * $channelLight5.xyz, 0 );
//---------------------------------------------------------------
// height lerp
//---------------------------------------------------------------
// lerp in the diffuse lighting from the ground up
diffuseLight *= directScale;
specularLight *= directScale;
// lerp down the ambient from the ground up
diffuseLight += ambientLight * ambientScale;
//---------------------------------------------------------------
// sum everything up
//---------------------------------------------------------------
/* maximum amount of dim-shadowing based on the pime light contribution */
float acceptDimShadow = primaryFactor * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
color.xyz = ( specularLight * specular.xyz ) + ( diffuseLight * diffuse.xyz );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
CALC_FRAGMENT_POS
==================================================================================
*/
#template CALC_FRAGMENT_POS( fragmentXYZ, fromViewer )
{
// world space coordinate of the fragment
// texcoord4 is fragmentXYZ - $globalViewOrigin.xyz;
fragmentXYZ = fromViewer + $globalViewOrigin.xyz;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING
==================================================================================
*/
#template APPLY_LIGHTING_LOCAL( color, diffuse, specular, power, globalNormal, fragmentXYZ, globalReflection )
{
// power factor is stored in bumpPage.x as 0.0 - 1.0, with 1.0 being tightest highlights
const float powerExp = 4 + power * 100;
half3 specularLight = half3( 0, 0, 0 );
half3 diffuseLight = half3( 0, 0, 0 );
//---------------------------------------------------------------
// first light
//---------------------------------------------------------------
const float3 light0Dir = $channellight0.xyz - fragmentXYZ;
const float3 light0DirNormalized = normalize( light0Dir );
const float light0Dist = length( light0Dir );
const float light0Attenuation = 1.0 - ( min( light0Dist, $channellight1.w ) / $channellight1.w );
const float light0Factor = saturate( dot3( light0DirNormalized, globalNormal ) );
const float light0SpecDot = saturate( dot3( light0DirNormalized, globalReflection ) );
const float light0Pow = pow( light0SpecDot, powerExp );
const float3 light0Color = $channellight1.xyz * light0Factor * light0Attenuation;
diffuseLight += light0Color;
specularLight += light0Color * light0Pow;
//---------------------------------------------------------------
// second light
//---------------------------------------------------------------
const float3 light1Dir = $channellight2.xyz - fragmentXYZ;
const float3 light1DirNormalized = normalize( light1Dir );
const float light1Dist = length( light1Dir );
const float light1Attenuation = 1.0 - ( min( light1Dist, $channellight1.w ) / $channellight1.w );
const float light1Factor = saturate( dot3( light1DirNormalized, globalNormal ) );
const float light1SpecDot = saturate( dot3( light1DirNormalized, globalReflection ) );
const float light1Pow = pow( light1SpecDot, powerExp );
const float3 light1Color = $channellight3.xyz * light1Factor * light1Attenuation;
diffuseLight += light1Color;
specularLight += light1Color * light1Pow;
//---------------------------------------------------------------
// third light
//---------------------------------------------------------------
const float3 light2Dir = $channellight4.xyz - fragmentXYZ;
const float3 light2DirNormalized = normalize( light2Dir );
const float light2Dist = length( light2Dir );
const float light2Attenuation = 1.0 - ( min( light2Dist, $channellight1.w ) / $channellight1.w );
const float light2Factor = saturate( dot3( light2DirNormalized, globalNormal ) );
const float light2SpecDot = saturate( dot3( light2DirNormalized, globalReflection ) );
const float light2Pow = pow( light2SpecDot, powerExp );
const float3 light2Color = $channellight5.xyz * light2Factor * light2Attenuation;
diffuseLight += light2Color;
specularLight += light2Color * light2Pow;
//---------------------------------------------------------------
// sum everything up
//---------------------------------------------------------------
// the YCoCg conversion can go slightly negative!
diffuse = saturate( diffuse );
// de-gamma the textures
diffuse.x = pow( diffuse.x, 2.2 );
diffuse.y = pow( diffuse.y, 2.2 );
diffuse.z = pow( diffuse.z, 2.2 );
specular.x = pow( specular.x, 2.2 );
specular.y = pow( specular.y, 2.2 );
specular.z = pow( specular.z, 2.2 );
const float3 finalColor = ( specularLight * specular.xyz ) + ( diffuseLight * diffuse.xyz );
// gamma correct
color.x = pow( finalColor.x, 1.0/2.2 );
color.y = pow( finalColor.y, 1.0/2.2 );
color.z = pow( finalColor.z, 1.0/2.2 );
/* maximum amount of dim-shadowing based on the pime light contribution */
const half primeLightFactor = saturate( dot3( $primeLightDir, globalNormal ) )
* ( 1.0 - saturate( 0.5 + $primeLightMin.x ) ); // FIXME: make a constant!
color.w = primeLightFactor;
}
#endtemplate
/*
==================================================================================
APPLY_LIGHTING_SKIN
==================================================================================
*/
#template APPLY_LIGHTING_SKIN( color, diffuse, specular, ambientOcclusion, globalDiffuseNormal, globalReflection )
{
// Calculate diffuse warp from diffuse normal and use it as lookup
half cosd = saturate( ( dot3( $primeLightDir, globalDiffuseNormal ) * 0.5 ) + 0.5 );
half3 diffuseWarp = tex2D( $textureMap, float2( cosd, 0.0 ) ).xyz;
half specularAmbienceScale = 0.25;
half primeLightFactor = saturate( dot3( $primeLightDir, globalDiffuseNormal ) );
// Diffuse primary and ambient light
half3 diffusePrimary = $primeLightColor.xyz * diffuseWarp;
half3 diffuseAmbient = _half3( 0.0 )
+ max( globalDiffuseNormal.x * $channelLight0.xyz, 0.0 )
+ max( -globalDiffuseNormal.x * $channelLight1.xyz, 0.0 )
+ max( globalDiffuseNormal.y * $channelLight2.xyz, 0.0 )
+ max( -globalDiffuseNormal.y * $channelLight3.xyz, 0.0 )
+ max( globalDiffuseNormal.z * $channelLight4.xyz, 0.0 )
+ max( -globalDiffuseNormal.z * $channelLight5.xyz, 0.0 );
// Specular primary and ambient light
half3 specularPrimary = $primeLightColor.xyz * saturate( dot3( globalReflection, $primeLightDir ) );
half3 specularAmbient = _half3( 0.0 )
+ max( globalReflection.x * $channelLight0.xyz, 0.0 );
+ max( -globalReflection.x * $channelLight1.xyz, 0.0 );
+ max( globalReflection.y * $channelLight2.xyz, 0.0 );
+ max( -globalReflection.y * $channelLight3.xyz, 0.0 );
+ max( globalReflection.z * $channelLight4.xyz, 0.0 );
+ max( -globalReflection.z * $channelLight5.xyz, 0.0 );
// Apply ambient occlusion on ambient lights
diffuseAmbient *= ambientOcclusion;
specularAmbient *= ambientOcclusion * specularAmbienceScale;
half3 diffuseLight = diffusePrimary + diffuseAmbient;
half3 specularLight = specularPrimary + specularAmbient;
// Maximum amount of dim-shadowing based on the pime light contribution
float acceptDimShadow = primeLightFactor * ( 1.0 - saturate( 0.5 + $primeLightMin.x ) );
// Sum
color.xyz = _half3( 0.0 )
+ ( diffuseLight * diffuse )
+ ( specularLight * specular );
color.w = acceptDimShadow;
}
#endtemplate
/*
==================================================================================
APPLY_HOLOGRAM
==================================================================================
*/
#template APPLY_HOLOGRAM( color )
{
// scanline texture
float2 screenCoords = screenPosToTexcoord( fragment.position.xy, $positionToViewTexture );
half scanlinesWide = tex2D( $scanlineMap, screenCoords + ( $time.x * 0.025 ) ).x;
screenCoords *= float2( 1.0, 5.5 );
half scanlinesFine = tex2D( $scanlineMap, screenCoords + ( $time.x * 0.01 ) ).x;
color.xyz *= scanlinesWide + ( scanlinesFine * 0.25 ) ;
color.xyz *= 2.5;
color.xyz += $hologramColor.xyz * ( color.xyz + 0.1 );
color.xyz *= $hologramColor.w;
}
#endtemplate
/*
==================================================================================
APPLY_HIGHLIGHT
==================================================================================
*/
#template APPLY_HIGHLIGHT( color, fromViewerN, localToGlobalX, localToGlobalY, localToGlobalZ )
{
/* Reference,
This is the code we ran to get the approximated look of how we wanted the
rimming of usables to look like.
half k = 1.0 - saturate( abs( dot3( objectNormal.xyz, $globalViewFwd.xyz ) ) );
half bias = 0.25;
half scale = 1.0 / max( 1.0 - bias, 0.00001 );
half r = saturate( ( k - bias ) * scale );
color.xyz += _half3( r * r ) * half3( 0.968, 0.941, 0.705 ) * _half3( 1.0 );
*/
half3 objectNormal = half3( localToGlobalX.z, localToGlobalY.z, localToGlobalZ.z );
half k = 1.0 - saturate( abs( dot3( objectNormal.xyz, $globalViewFwd.xyz ) ) );
half r = ( k - 0.25 ) * 1.333333;
color.xyz += $highlightColor.xyz * _half3( r * r );
}
#endtemplate
/*
==================================================================================
OUTPUT_SURFACE_ATTRIBUTES
==================================================================================
*/
#template OUTPUT_SURFACE_ATTRIBUTES( diffuse, specular, power, globalNormal )
{
#ifdef DEFERRED_LIGHTING
result.color2.xyz = diffuse.xyz;
result.color2.w = length( specular.xyz );
result.color3.xyz = globalNormal.xyz * _float3( 0.5 ) + _float3( 0.5 );
result.color3.w = power;
#endif
}
#endtemplate