doom3-bfg/base/renderprogs/interactionSM.pixel
Robert Beckebans 277964f074 Because I can :)
- Implemented soft shadows using PCF hardware shadow mapping

  The implementation uses sampler2DArrayShadow and PCF which usually
  requires Direct3D 10.1 however it is in the OpenGL 3.2 core so it should
  be widely supported.
  All 3 light types are supported which means parallel lights (sun) use
  scene independent cascaded shadow mapping.
  The implementation is very fast with single taps (400 fps average per
  scene on a GTX 660 ti OC) however I defaulted it to 16 taps so the shadows look
  really good which should you give stable 100 fps on todays hardware.

  The shadow filtering algorithm is based on Carmack's research which was
  released in the original Doom 3 GPL release draw_exp.cpp.

- Changed interaction shaders to use Half-Lambert lighting like in HL2 to
  make the game less dark

- Fixed some of the renderer debugging/development tools like r_showTris
2014-05-10 14:40:01 +02:00

260 lines
7.9 KiB
Text

/*
===========================================================================
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 <http://www.gnu.org/licenses/>.
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.001 * tan( acos( ldotN ) );
//bias = clamp( bias, 0, 0.001 );
float bias = 0.001;
shadowTexcoord.xyz /= shadowTexcoord.w;
shadowTexcoord.z = shadowTexcoord.z * 0.9991;
//shadowTexcoord.z = shadowTexcoord.z - bias;
shadowTexcoord.w = 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;
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 );
#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;
}