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

156 lines
6.2 KiB
Plaintext

{
parms {
stageSort sortCoverage
}
state {
depthfunc GL_LEQUAL
depthmask
#ifdef PS3
alphamask // the ps3 does not make a copy of the alpha buffer
#endif
}
hlsl_vp {
#include "skinning_normals.inc"
// vertex 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 );
// Convert back from 16 bit vertex elements.
float2 texcoord0 = vertex.texcoord0 * $vertexStScaleBias.xy + $vertexStScaleBias.zw;
// texture 0 takes the base and offseted coordinates
result.texcoord0.x = dot4( texcoord0, $sMatrix );
result.texcoord0.y = dot4( texcoord0, $tMatrix );
result.texcoord0.z = dot4( texcoord0, $rMatrix );
result.texcoord0.w = dot4( texcoord0, $qMatrix );
// transform the local space vectors to world space
result.texcoord1.x = dot3( tangent, $modelMatrixX );
result.texcoord1.y = dot3( bitangent, $modelMatrixX );
result.texcoord1.z = dot3( normal, $modelMatrixX );
result.texcoord1.w = morphScale;
result.texcoord2.x = dot3( tangent, $modelMatrixY );
result.texcoord2.y = dot3( bitangent, $modelMatrixY );
result.texcoord2.z = dot3( normal, $modelMatrixY );
result.texcoord2.w = 0.0;
result.texcoord3.x = dot3( tangent, $modelMatrixZ );
result.texcoord3.y = dot3( bitangent, $modelMatrixZ );
result.texcoord3.z = dot3( normal, $modelMatrixZ );
result.texcoord3.w = 0.0;
// texture 4 takes the dir to the viewer and the fog value
result.texcoord4.x = dot4( position, $modelMatrixX );
result.texcoord4.y = dot4( position, $modelMatrixY );
result.texcoord4.z = dot4( position, $modelMatrixZ );
result.texcoord4.xyz -= $globalViewOrigin.xyz;
result.texcoord4.w = -( clamp( result.position.w - $fogStart.x, 0.0, $fogEnd.x ) * $fogScale.x );
}
hlsl_fp {
float2 texcoord = fragment.texcoord0.xy;
float4 diffuse = tex2D( $spare1Map, texcoord );
float4 specular = tex2D( $spareSpecularMap, texcoord );
float4 bump = tex2D( $spareBumpMap, texcoord );
// blend in another texture based on the morph map
BRANCH if ( $useSkinBlending.x > 0.0 ) { // fragment.htexcoord1.w > 0.0
float4 diffuse2 = tex2D( $spare2Map, texcoord );
float4 specular2 = tex2D( $spareSpecularMap2, texcoord );
float4 bump2 = tex2D( $spareBumpMap2, texcoord );
float morphScale = fragment.htexcoord1.w;
diffuse = lerp( diffuse, diffuse2, morphScale );
specular = lerp( specular, specular2, morphScale );
bump = lerp( bump, bump2, morphScale );
}
//--------- environment mapping ----------
// Note that the optimized derivation of the localNormal below results in a vector that is half-unit length!
half3 localNormal = bump.wyz - 0.5;
localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );
// transform into global space
half3 globalNormal;
globalNormal.x = dot3( localNormal, fragment.htexcoord1.xyz );
globalNormal.y = dot3( localNormal, fragment.htexcoord2.xyz );
globalNormal.z = dot3( localNormal, fragment.htexcoord3.xyz );
globalNormal = normalize( globalNormal );
// normalize the direction from the viewer
half3 fromViewer = normalize( fragment.htexcoord4.xyz );
// reflection vector
half4 reflection;
reflection.xyz = fromViewer - ( globalNormal * dot3( fromViewer, globalNormal ) * 2.0 );
// 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 - powerFactor ) * 4.0 + $newPowerScale.x );
reflection.w = 0.0;
half3 envColor = texCUBElod( $dynamicEnvMap, reflection ).xyz;
//--------- read the dimshadow factor ----------
// this is normalized window space, not strict openGL window space
// that uses integer viewport values.
float4 window;
window.xy = screenPosToTexcoord( fragment.position.xy, $renderPositionToViewTexture );
window.z = 0.0;
window.w = 0.0; // blur factor
float shadow = tex2Dlod( $viewColorMap, window ).w; // from alpha channel
// only use half the dimshadow value, since we can't separate the
// contribution along the shadow from the remainder
shadow = saturate( shadow + $primeLightMin.x );
//---------------------------------------------------------------
// calculate direct lighting, applying the shadow factor to the first
// light, which should be in the same direction as the dimshadow projection.
//---------------------------------------------------------------
float3 primeLight = shadow * $primeLightColor.xyz *
saturate( dot3( $primeLightDir, globalNormal ) - 0.2 );
float3 light = primeLight
+ 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 );
//---------------------------------------------------------------
// calculate the view grazing fraction
//---------------------------------------------------------------
half graze = saturate( dot3( -fromViewer, globalNormal ) );
graze = saturate( ( $viewGraze.x - max( graze, -graze ) ) / max( $viewGraze.x, 0.0001 ) );
diffuse.xyz = lerp( diffuse.xyz, $grazingDiffuseColor.xyz, graze );
specular.xyz = lerp( specular.xyz, $grazingSpecularColor.xyz, graze );
//---------------------------------------------------------------
// sum everything up
//---------------------------------------------------------------
// automatically scale diffuseScale by 2.0 to match the baked-in behavior
// only have specular with primeLight to avoid shiny ambient guys
half3 color = light * ( envColor * specular.xyz * $newSpecularScale.xyz )
+ light * ( diffuse.xyz * $newDiffuseScale.xyz * 2.0 );
// calculate fog term
half fog = saturate( exp2( fragment.htexcoord4.w ) );
// lerp towards the fog color by the fog factor
result.color.xyz = lerp( $fogColor.xyz, color.xyz, fog );
#ifndef PS3
result.color.w = specular.w;
#endif
}
}