/* =========================================================================== Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. Copyright (C) 2013-2014 Robert Beckebans This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 BFG Edition Source Code. If not, see . In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "renderprogs/global.inc" uniform sampler2D samp0 : register(s0); // texture 1 is the per-surface bump map uniform sampler2D samp1 : register(s1); // texture 2 is the light falloff texture uniform sampler2D samp2 : register(s2); // texture 3 is the light projection texture uniform sampler2D samp3 : register(s3); // texture 4 is the per-surface diffuse map uniform sampler2D samp4 : register(s4); // texture 5 is the per-surface specular map uniform sampler2DArrayShadow samp5 : register(s5); // texture 6 is the shadowmap array uniform sampler2D samp6 : register(s6); // texture 7 is the jitter texture struct PS_IN { half4 position : VPOS; half4 texcoord0 : TEXCOORD0_centroid; half4 texcoord1 : TEXCOORD1_centroid; half4 texcoord2 : TEXCOORD2_centroid; half4 texcoord3 : TEXCOORD3_centroid; half4 texcoord4 : TEXCOORD4_centroid; half4 texcoord5 : TEXCOORD5_centroid; half4 texcoord6 : TEXCOORD6_centroid; half4 texcoord7 : TEXCOORD7_centroid; half4 texcoord8 : TEXCOORD8_centroid; half4 texcoord9 : TEXCOORD9_centroid; half4 color : COLOR0; }; struct PS_OUT { half4 color : COLOR; }; void main( PS_IN fragment, out PS_OUT result ) { half4 bumpMap = tex2D( samp0, fragment.texcoord1.xy ); half4 lightFalloff = idtex2Dproj( samp1, fragment.texcoord2 ); half4 lightProj = idtex2Dproj( samp2, fragment.texcoord3 ); half4 YCoCG = tex2D( samp3, fragment.texcoord4.xy ); half4 specMap = tex2D( samp4, fragment.texcoord5.xy ); half3 lightVector = normalize( fragment.texcoord0.xyz ); half3 diffuseMap = ConvertYCoCgToRGB( YCoCG ); half3 localNormal; // RB begin #if defined(GLES2) localNormal.xy = bumpMap.rg - 0.5; #else localNormal.xy = bumpMap.wy - 0.5; #endif // RB end localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) ); localNormal = normalize( localNormal ); // RB: http://developer.valvesoftware.com/wiki/Half_Lambert float halfLdotN = dot3( localNormal, lightVector ) * 0.5 + 0.5; halfLdotN *= halfLdotN; // traditional very dark Lambert light model used in Doom 3 float ldotN = dot3( localNormal, lightVector ); const half specularPower = 10.0f; half hDotN = dot3( normalize( fragment.texcoord6.xyz ), localNormal ); // RB: added abs half3 specularContribution = _half3( pow( abs( hDotN ), specularPower ) ); half3 diffuseColor = diffuseMap * rpDiffuseModifier.xyz; half3 specularColor = specMap.xyz * specularContribution * rpSpecularModifier.xyz; half3 lightColor = lightProj.xyz * lightFalloff.xyz; half rim = 1.0f - saturate( hDotN ); half rimPower = 16.0f; half3 rimColor = diffuseColor * lightProj.xyz * lightFalloff.xyz * 1.0f * pow( rim, rimPower ) * fragment.color.rgb;// * halfLdotN; // // shadow mapping // int shadowIndex = 0; #if defined( LIGHT_POINT ) float3 toLightGlobal = normalize( fragment.texcoord8.xyz ); float axis[6]; axis[0] = -toLightGlobal.x; axis[1] = toLightGlobal.x; axis[2] = -toLightGlobal.y; axis[3] = toLightGlobal.y; axis[4] = -toLightGlobal.z; axis[5] = toLightGlobal.z; for( int i = 0; i < 6; i++ ) { if( axis[i] > axis[shadowIndex] ) { shadowIndex = i; } } #endif // #if defined( POINTLIGHT ) #if defined( LIGHT_PARALLEL ) float viewZ = -fragment.texcoord9.z; shadowIndex = 4; for( int i = 0; i < 4; i++ ) { if( viewZ < rpCascadeDistances[i] ) { shadowIndex = i; break; } } #endif #if 0 if( shadowIndex == 0 ) { result.color = float4( 1.0, 0.0, 0.0, 1.0 ); } else if( shadowIndex == 1 ) { result.color = float4( 0.0, 1.0, 0.0, 1.0 ); } else if( shadowIndex == 2 ) { result.color = float4( 0.0, 0.0, 1.0, 1.0 ); } else if( shadowIndex == 3 ) { result.color = float4( 1.0, 1.0, 0.0, 1.0 ); } else if( shadowIndex == 4 ) { result.color = float4( 1.0, 0.0, 1.0, 1.0 ); } else if( shadowIndex == 5 ) { result.color = float4( 0.0, 1.0, 1.0, 1.0 ); } //result.color.xyz *= lightColor; return; #endif float4 shadowMatrixX = rpShadowMatrices[ int ( shadowIndex * 4 + 0 ) ]; float4 shadowMatrixY = rpShadowMatrices[ int ( shadowIndex * 4 + 1 ) ]; float4 shadowMatrixZ = rpShadowMatrices[ int ( shadowIndex * 4 + 2 ) ]; float4 shadowMatrixW = rpShadowMatrices[ int ( shadowIndex * 4 + 3 ) ]; float4 modelPosition = float4( fragment.texcoord7.xyz, 1.0 ); float4 shadowTexcoord; shadowTexcoord.x = dot4( modelPosition, shadowMatrixX ); shadowTexcoord.y = dot4( modelPosition, shadowMatrixY ); shadowTexcoord.z = dot4( modelPosition, shadowMatrixZ ); shadowTexcoord.w = dot4( modelPosition, shadowMatrixW ); //float bias = 0.005 * tan( acos( ldotN ) ); //bias = clamp( bias, 0, 0.01 ); float bias = 0.001; shadowTexcoord.xyz /= shadowTexcoord.w; //shadowTexcoord.z = shadowTexcoord.z * 0.9991; shadowTexcoord.z = shadowTexcoord.z - bias; shadowTexcoord.w = float(shadowIndex); #if 0 result.color.xyz = float3( shadowTexcoord.z, shadowTexcoord.z, shadowTexcoord.z ); result.color.w = 1.0; return; #endif // multiple taps #if 0 const float2 poissonDisk2[12] = float2[]( float2(-0.326,-0.406), float2(-0.840,-0.074), float2(-0.696, 0.457), float2(-0.203, 0.621), float2( 0.962,-0.195), float2( 0.473,-0.480), float2( 0.519, 0.767), float2( 0.185,-0.893), float2( 0.507, 0.064), float2( 0.896, 0.412), float2(-0.322,-0.933), float2(-0.792,-0.598) ); float shadow = 0.0; float shadowTexelSize = ( 1.0 / 1024.0 ) * 0.5; for( int i = 0; i < 12; i++ ) { int index = int( rand( shadowTexcoord.xy * 1.0 ) * 12 ); float4 shadowTexcoordOffset = float4( shadowTexcoord.xy + poissonDisk2[index] * shadowTexelSize, shadowTexcoord.z, shadowTexcoord.w ); shadow += texture( samp5, shadowTexcoordOffset.xywz); } shadow *= ( 1.0 / 12.0 ); #elif 1 float4 base = shadowTexcoord; base.xy += rpJitterTexScale.xy * -0.5; float shadow = 0.0; float stepSize = 1.0 / 16.0; float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset; for( int i = 0; i < 16; i++ ) { float4 jitter = base + tex2D( samp6, jitterTC.xy ) * rpJitterTexScale; jitter.zw = shadowTexcoord.zw; shadow += texture( samp5, jitter.xywz ); jitterTC.x += stepSize; } shadow *= ( 1.0 / 16.0 ); #else float shadow = texture( samp5, shadowTexcoord.xywz ); #endif result.color.xyz = ( diffuseColor + specularColor ) * halfLdotN * lightColor * fragment.color.rgb * shadow;// + rimColor; result.color.w = 1.0; }