Combined lightgrid trilerp with IBL PBR lighting

This commit is contained in:
Robert Beckebans 2021-04-15 15:01:31 +02:00
parent 884658d6dd
commit 0596300c45
10 changed files with 1397 additions and 3 deletions

View file

@ -42,6 +42,8 @@ return
"builtin/lighting/ambient_lighting.vs.hlsl",
"builtin/lighting/ambient_lighting_IBL.ps.hlsl",
"builtin/lighting/ambient_lighting_IBL.vs.hlsl",
"builtin/lighting/ambient_lightgrid_IBL.ps.hlsl",
"builtin/lighting/ambient_lightgrid_IBL.vs.hlsl",
"builtin/lighting/interaction.ps.hlsl",
"builtin/lighting/interaction.vs.hlsl",
"builtin/lighting/interactionAmbient.ps.hlsl",

View file

@ -0,0 +1,414 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2021 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.hlsl"
#include "renderprogs/BRDF.inc.hlsl"
// *INDENT-OFF*
uniform sampler2D samp0 : register(s0); // texture 0 is the per-surface normal map
uniform sampler2D samp1 : register(s1); // texture 1 is the per-surface specular or roughness/metallic/AO mixer map
uniform sampler2D samp2 : register(s2); // texture 2 is the per-surface baseColor map
uniform sampler2D samp3 : register(s3); // texture 3 is the BRDF LUT
uniform sampler2D samp4 : register(s4); // texture 4 is SSAO
uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map
uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map
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 color : COLOR0;
};
struct PS_OUT
{
half4 color : COLOR;
};
// *INDENT-ON*
float3 lightGridOrigin = float3( -192.0, -128.0, 0 );
float3 lightGridSize = float3( 64.0, 64.0, 128.0 );
int3 lightGridBounds = int3( 7, 7, 3 );
int3 GetBaseGridCoord( float3 origin )
{
int3 pos;
float3 lightOrigin = origin - lightGridOrigin;
for( int i = 0; i < 3; i++ )
{
float v;
v = lightOrigin[i] * ( 1.0f / lightGridSize[i] );
pos[i] = int( floor( v ) );
if( pos[i] < 0 )
{
pos[i] = 0;
}
else if( pos[i] >= lightGridBounds[i] - 1 )
{
pos[i] = lightGridBounds[i] - 1;
}
}
return pos;
}
// RB: TODO OPTIMIZE
// this is a straight port of idBounds::RayIntersection
bool AABBRayIntersection( float3 b[2], float3 start, float3 dir, out float scale )
{
int i, ax0, ax1, ax2, side, inside;
float f;
float3 hit;
ax0 = -1;
inside = 0;
for( i = 0; i < 3; i++ )
{
if( start[i] < b[0][i] )
{
side = 0;
}
else if( start[i] > b[1][i] )
{
side = 1;
}
else
{
inside++;
continue;
}
if( dir[i] == 0.0f )
{
continue;
}
f = ( start[i] - b[side][i] );
if( ax0 < 0 || abs( f ) > abs( scale * dir[i] ) )
{
scale = - ( f / dir[i] );
ax0 = i;
}
}
if( ax0 < 0 )
{
scale = 0.0f;
// return true if the start point is inside the bounds
return ( inside == 3 );
}
ax1 = ( ax0 + 1 ) % 3;
ax2 = ( ax0 + 2 ) % 3;
hit[ax1] = start[ax1] + scale * dir[ax1];
hit[ax2] = start[ax2] + scale * dir[ax2];
return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&
hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
}
void main( PS_IN fragment, out PS_OUT result )
{
half4 bumpMap = tex2D( samp0, fragment.texcoord0.xy );
half4 YCoCG = tex2D( samp2, fragment.texcoord1.xy );
half4 specMapSRGB = tex2D( samp1, fragment.texcoord2.xy );
half4 specMap = sRGBAToLinearRGBA( specMapSRGB );
half3 diffuseMap = sRGBToLinearRGB( ConvertYCoCgToRGB( YCoCG ) );
half3 localNormal;
#if defined(USE_NORMAL_FMT_RGB8)
localNormal.xy = bumpMap.rg - 0.5;
#else
localNormal.xy = bumpMap.wy - 0.5;
#endif
localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );
localNormal = normalize( localNormal );
float3 globalNormal;
globalNormal.x = dot3( localNormal, fragment.texcoord4 );
globalNormal.y = dot3( localNormal, fragment.texcoord5 );
globalNormal.z = dot3( localNormal, fragment.texcoord6 );
globalNormal = normalize( globalNormal );
float3 globalPosition = fragment.texcoord7.xyz;
// RB: rpGlobalLightOrigin is global view origin
float3 globalEye = normalize( rpGlobalLightOrigin.xyz - globalPosition );
float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal );
reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalEye );
#if 1
// parallax box correction using portal area bounds
float hitScale;
float3 bounds[2];
bounds[0].x = rpWobbleSkyX.x;
bounds[0].y = rpWobbleSkyX.y;
bounds[0].z = rpWobbleSkyX.z;
bounds[1].x = rpWobbleSkyY.x;
bounds[1].y = rpWobbleSkyY.y;
bounds[1].z = rpWobbleSkyY.z;
// global fragment position
float3 rayStart = fragment.texcoord7.xyz;
// we can't start inside the box so move this outside and use the reverse path
rayStart += reflectionVector * 10000.0;
// only do a box <-> ray intersection test if we use a local cubemap
if( ( rpWobbleSkyX.w > 0.0 ) && AABBRayIntersection( bounds, rayStart, -reflectionVector, hitScale ) )
{
float3 hitPoint = rayStart - reflectionVector * hitScale;
// rpWobbleSkyZ is cubemap center
reflectionVector = hitPoint - rpWobbleSkyZ.xyz;
}
#endif
half vDotN = saturate( dot3( globalEye, globalNormal ) );
#if defined( USE_PBR )
const half metallic = specMapSRGB.g;
const half roughness = specMapSRGB.r;
const half glossiness = 1.0 - roughness;
// the vast majority of real-world materials (anything not metal or gems) have F(0°)
// values in a very narrow range (~0.02 - 0.08)
// approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4)
const half3 dielectricColor = half3( 0.04 );
// derive diffuse and specular from albedo(m) base color
const half3 baseColor = diffuseMap;
half3 diffuseColor = baseColor * ( 1.0 - metallic );
half3 specularColor = lerp( dielectricColor, baseColor, metallic );
#if defined( DEBUG_PBR )
diffuseColor = half3( 0.0, 0.0, 0.0 );
specularColor = half3( 0.0, 1.0, 0.0 );
#endif
float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );
float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic );
#else
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
half3 diffuseColor = diffuseMap;
half3 specularColor = specMap.rgb;
#if defined( DEBUG_PBR )
diffuseColor = half3( 0.0, 0.0, 0.0 );
specularColor = half3( 1.0, 0.0, 0.0 );
#endif
float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );
// NOTE: metalness is missing
float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS );
#endif
//diffuseColor = half3( 1.0, 1.0, 1.0 );
//diffuseColor = half3( 0.0, 0.0, 0.0 );
// calculate the screen texcoord in the 0.0 to 1.0 range
//float2 screenTexCoord = vposToScreenPosTexCoord( fragment.position.xy );
float2 screenTexCoord = fragment.position.xy * rpWindowCoord.xy;
float ao = 1.0;
ao = tex2D( samp4, screenTexCoord ).r;
//diffuseColor.rgb *= ao;
// evaluate diffuse IBL
float2 normalizedOctCoord = octEncode( globalNormal );
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
// lightgrid atlas
float invXY = ( 1.0 / ( lightGridBounds[0] * lightGridBounds[1] ) );
float invZ = ( 1.0 / lightGridBounds[2] );
normalizedOctCoordZeroOne.x *= invXY;
normalizedOctCoordZeroOne.y *= invZ;
int3 gridCoord;
float3 frac;
float3 lightOrigin = globalPosition - lightGridOrigin;
for( int i = 0; i < 3; i++ )
{
float v;
v = lightOrigin[i] * ( 1.0f / lightGridSize[i] );
gridCoord[i] = int( floor( v ) );
frac[ i ] = v - gridCoord[ i ];
if( gridCoord[i] < 0 )
{
gridCoord[i] = 0;
}
else if( gridCoord[i] >= lightGridBounds[i] - 1 )
{
gridCoord[i] = lightGridBounds[i] - 1;
}
}
// trilerp the light value
int3 gridStep;
gridStep[0] = 1;
gridStep[1] = lightGridBounds[0];
gridStep[2] = lightGridBounds[0] * lightGridBounds[1];
float totalFactor = 0.0;
float3 irradiance;
/*
for( int i = 0; i < 8; i++ )
{
for( int j = 0; j < 3; j++ )
{
if( i & ( 1 << j ) )
results in these offsets
*/
const float3 cornerOffsets[8] = float3[](
float3( 0.0, 0.0, 0.0 ),
float3( 1.0, 0.0, 0.0 ),
float3( 0.0, 2.0, 0.0 ),
float3( 1.0, 2.0, 0.0 ),
float3( 0.0, 0.0, 4.0 ),
float3( 1.0, 0.0, 4.0 ),
float3( 0.0, 2.0, 4.0 ),
float3( 1.0, 2.0, 4.0 ) );
for( int i = 0; i < 8; i++ )
{
float factor = 1.0;
int3 gridCoord2 = gridCoord;
for( int j = 0; j < 3; j++ )
{
if( cornerOffsets[ i ][ j ] > 0.0f )
{
factor *= frac[ j ];
gridCoord2[ j ] += 1;
}
else
{
factor *= ( 1.0f - frac[ j ] );
}
}
float2 atlasOffset;
atlasOffset.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[1] * gridStep[1] ) * invXY;
atlasOffset.y = ( gridCoord2[2] * invZ );
irradiance += tex2D( samp7, normalizedOctCoordZeroOne + atlasOffset ).rgb * factor;
totalFactor += factor;
}
if( totalFactor > 0 && totalFactor < 0.99 )
{
totalFactor = 1.0f / totalFactor;
irradiance *= totalFactor;
}
// lightgrid atlas
float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ao * ( rpDiffuseModifier.xyz * 1.0 );
// evaluate specular IBL
// should be 8 = numMips - 1, 256^2 = 9 mips
const float MAX_REFLECTION_LOD = 10.0;
float mip = clamp( ( roughness * MAX_REFLECTION_LOD ), 0.0, MAX_REFLECTION_LOD );
//float mip = 0.0;
normalizedOctCoord = octEncode( reflectionVector );
normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;
//radiance = float3( 0.0 );
float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg;
#if 0
result.color.rgb = float3( envBRDF.x, envBRDF.y, 0.0 );
result.color.w = fragment.color.a;
return;
#endif
float specAO = ComputeSpecularAO( vDotN, ao, roughness );
float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 );
#if 0
// Marmoset Horizon Fade trick
const half horizonFade = 1.3;
half horiz = saturate( 1.0 + horizonFade * saturate( dot3( reflectionVector, globalNormal ) ) );
horiz *= horiz;
//horiz = clamp( horiz, 0.0, 1.0 );
#endif
half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );
//result.color.rgb = diffuseLight;
//result.color.rgb = diffuseLight * lightColor;
//result.color.rgb = specularLight;
result.color.rgb = ( diffuseLight + specularLight ) * lightColor * fragment.color.rgb;
//result.color.rgb = localNormal.xyz * 0.5 + 0.5;
//result.color.rgb = float3( ao );
result.color.w = fragment.color.a;
}

View file

@ -0,0 +1,200 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2015 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.hlsl"
#if defined( USE_GPU_SKINNING )
uniform matrices_ubo { float4 matrices[408]; };
#endif
// *INDENT-OFF*
struct VS_IN {
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : POSITION;
float4 texcoord0 : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
float4 texcoord4 : TEXCOORD4;
float4 texcoord5 : TEXCOORD5;
float4 texcoord6 : TEXCOORD6;
float4 texcoord7 : TEXCOORD7;
float4 color : COLOR0;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
float4 vNormal = vertex.normal * 2.0 - 1.0;
float4 vTangent = vertex.tangent * 2.0 - 1.0;
float3 vBitangent = cross( vNormal.xyz, vTangent.xyz ) * vTangent.w;
#if defined( USE_GPU_SKINNING )
//--------------------------------------------------------------
// GPU transformation of the normal / tangent / bitangent
//
// multiplying with 255.1 give us the same result and is faster than floor( w * 255 + 0.5 )
//--------------------------------------------------------------
const float w0 = vertex.color2.x;
const float w1 = vertex.color2.y;
const float w2 = vertex.color2.z;
const float w3 = vertex.color2.w;
float4 matX, matY, matZ; // must be float4 for vec4
int joint = int( vertex.color.x * 255.1 * 3.0 );
matX = matrices[int( joint + 0 )] * w0;
matY = matrices[int( joint + 1 )] * w0;
matZ = matrices[int( joint + 2 )] * w0;
joint = int( vertex.color.y * 255.1 * 3.0 );
matX += matrices[int( joint + 0 )] * w1;
matY += matrices[int( joint + 1 )] * w1;
matZ += matrices[int( joint + 2 )] * w1;
joint = int( vertex.color.z * 255.1 * 3.0 );
matX += matrices[int( joint + 0 )] * w2;
matY += matrices[int( joint + 1 )] * w2;
matZ += matrices[int( joint + 2 )] * w2;
joint = int( vertex.color.w * 255.1 * 3.0 );
matX += matrices[int( joint + 0 )] * w3;
matY += matrices[int( joint + 1 )] * w3;
matZ += matrices[int( joint + 2 )] * w3;
float3 normal;
normal.x = dot3( matX, vNormal );
normal.y = dot3( matY, vNormal );
normal.z = dot3( matZ, vNormal );
normal = normalize( normal );
float3 tangent;
tangent.x = dot3( matX, vTangent );
tangent.y = dot3( matY, vTangent );
tangent.z = dot3( matZ, vTangent );
tangent = normalize( tangent );
float3 bitangent;
bitangent.x = dot3( matX, vBitangent );
bitangent.y = dot3( matY, vBitangent );
bitangent.z = dot3( matZ, vBitangent );
bitangent = normalize( bitangent );
float4 modelPosition;
modelPosition.x = dot4( matX, vertex.position );
modelPosition.y = dot4( matY, vertex.position );
modelPosition.z = dot4( matZ, vertex.position );
modelPosition.w = 1.0;
#else
float4 modelPosition = vertex.position;
float3 normal = vNormal.xyz;
float3 tangent = vTangent.xyz;
float3 bitangent = vBitangent.xyz;
#endif
result.position.x = dot4( modelPosition, rpMVPmatrixX );
result.position.y = dot4( modelPosition, rpMVPmatrixY );
result.position.z = dot4( modelPosition, rpMVPmatrixZ );
result.position.w = dot4( modelPosition, rpMVPmatrixW );
float4 defaultTexCoord = float4( 0.0f, 0.5f, 0.0f, 1.0f );
//calculate vector to light
//float4 toLight = rpLocalLightOrigin;
float4 toLight = normalize( float4( 0.0f, 0.5f, 1.0f, 1.0f ) );
//--------------------------------------------------------------
//# textures 0 takes the base coordinates by the texture matrix
result.texcoord0 = defaultTexCoord;
result.texcoord0.x = dot4( vertex.texcoord.xy, rpBumpMatrixS );
result.texcoord0.y = dot4( vertex.texcoord.xy, rpBumpMatrixT );
//# textures 1 takes the base coordinates by the texture matrix
result.texcoord1 = defaultTexCoord;
result.texcoord1.x = dot4( vertex.texcoord.xy, rpDiffuseMatrixS );
result.texcoord1.y = dot4( vertex.texcoord.xy, rpDiffuseMatrixT );
//# textures 2 takes the base coordinates by the texture matrix
result.texcoord2 = defaultTexCoord;
result.texcoord2.x = dot4( vertex.texcoord.xy, rpSpecularMatrixS );
result.texcoord2.y = dot4( vertex.texcoord.xy, rpSpecularMatrixT );
//# calculate normalized vector to viewer in R1
//result.texcoord3 = modelPosition;
float4 toEye = normalize( rpLocalViewOrigin - modelPosition );
result.texcoord3.x = dot3( toEye, rpModelMatrixX );
result.texcoord3.y = dot3( toEye, rpModelMatrixY );
result.texcoord3.z = dot3( toEye, rpModelMatrixZ );
result.texcoord4.x = dot3( tangent, rpModelMatrixX );
result.texcoord5.x = dot3( tangent, rpModelMatrixY );
result.texcoord6.x = dot3( tangent, rpModelMatrixZ );
result.texcoord4.y = dot3( bitangent, rpModelMatrixX );
result.texcoord5.y = dot3( bitangent, rpModelMatrixY );
result.texcoord6.y = dot3( bitangent, rpModelMatrixZ );
result.texcoord4.z = dot3( normal, rpModelMatrixX );
result.texcoord5.z = dot3( normal, rpModelMatrixY );
result.texcoord6.z = dot3( normal, rpModelMatrixZ );
float4 worldPosition;
worldPosition.x = dot4( modelPosition, rpModelMatrixX );
worldPosition.y = dot4( modelPosition, rpModelMatrixY );
worldPosition.z = dot4( modelPosition, rpModelMatrixZ );
worldPosition.w = dot4( modelPosition, rpModelMatrixW );
result.texcoord7 = worldPosition;
#if defined( USE_GPU_SKINNING )
// for joint transformation of the tangent space, we use color and
// color2 for weighting information, so hopefully there aren't any
// effects that need vertex color...
result.color = float4( 1.0f, 1.0f, 1.0f, 1.0f );
#else
//# generate the vertex color, which can be 1.0, color, or 1.0 - color
//# for 1.0 : env[16] = 0, env[17] = 1
//# for color : env[16] = 1, env[17] = 0
//# for 1.0-color : env[16] = -1, env[17] = 1
result.color = ( swizzleColor( vertex.color ) * rpVertexColorModulate ) + rpVertexColorAdd;
#endif
}

View file

@ -1972,6 +1972,8 @@ void idRenderBackend::DBG_ShowLightGrid()
gridPoint = &area->lightGrid.lightGridPoints[ gridPointIndex ];
totalFactor = 0;
idVec3 cornerOffsets[8];
for( int i = 0; i < 8; i++ )
{
float factor = 1.0;
@ -1981,7 +1983,9 @@ void idRenderBackend::DBG_ShowLightGrid()
for( int j = 0; j < 3; j++ )
{
if( i & ( 1 << j ) )
cornerOffsets[i][j] = i & ( 1 << j );
if( cornerOffsets[i][j] > 0.0f )
{
factor *= frac[j];

View file

@ -1323,7 +1323,89 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
const textureUsage_t specUsage = din->specularImage->GetUsage();
// RB begin
if( useIBL )
if( useIBL && viewDef->useLightGrid )
{
idVec4 probeMins, probeMaxs, probeCenter;
probeMins[0] = viewDef->globalProbeBounds[0][0];
probeMins[1] = viewDef->globalProbeBounds[0][1];
probeMins[2] = viewDef->globalProbeBounds[0][2];
probeMins[3] = viewDef->globalProbeBounds.IsCleared() ? 0.0f : 1.0f;
probeMaxs[0] = viewDef->globalProbeBounds[1][0];
probeMaxs[1] = viewDef->globalProbeBounds[1][1];
probeMaxs[2] = viewDef->globalProbeBounds[1][2];
probeMaxs[3] = 0.0f;
idVec3 center = viewDef->globalProbeBounds.GetCenter();
probeCenter.Set( center.x, center.y, center.z, 1.0f );
SetVertexParm( RENDERPARM_WOBBLESKY_X, probeMins.ToFloatPtr() );
SetVertexParm( RENDERPARM_WOBBLESKY_Y, probeMaxs.ToFloatPtr() );
SetVertexParm( RENDERPARM_WOBBLESKY_Z, probeCenter.ToFloatPtr() );
if( specUsage == TD_SPECULAR_PBR_RMAO || specUsage == TD_SPECULAR_PBR_RMAOD )
{
// PBR path with roughness, metal and AO
if( din->surf->jointCache )
{
renderProgManager.BindShader_ImageBasedLightGridSkinned_PBR();
}
else
{
renderProgManager.BindShader_ImageBasedLightGrid_PBR();
}
}
else
{
if( din->surf->jointCache )
{
renderProgManager.BindShader_ImageBasedLightGridSkinned();
}
else
{
renderProgManager.BindShader_ImageBasedLightGrid();
}
}
GL_SelectTexture( INTERACTION_TEXUNIT_FALLOFF );
globalImages->brdfLutImage->Bind();
GL_SelectTexture( INTERACTION_TEXUNIT_PROJECTION );
#if defined( USE_VULKAN )
globalImages->whiteImage->Bind();
#else
if( !r_useSSAO.GetBool() )
{
globalImages->whiteImage->Bind();
}
else
{
globalImages->ambientOcclusionImage[0]->Bind();
}
#endif
GL_SelectTexture( INTERACTION_TEXUNIT_AMBIENT_CUBE1 );
if( viewDef->irradianceImage )
{
viewDef->irradianceImage->Bind();
}
else
{
globalImages->defaultUACIrradianceCube->Bind();
}
GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE1 );
if( viewDef->radianceImage )
{
viewDef->radianceImage->Bind();
}
else
{
globalImages->defaultUACRadianceCube->Bind();
}
}
else if( useIBL )
{
idVec4 probeMins, probeMaxs, probeCenter;

View file

@ -636,6 +636,12 @@ struct viewDef_t
idRenderMatrix inverseBaseEnvProbeProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the environent probe volume in world space
idImage* irradianceImage; // cubemap image used for diffuse IBL by backend
idImage* radianceImage; // cubemap image used for specular IBL by backend
// lightGrid
bool useLightGrid;
idVec3 lightGridOrigin;
idVec3 lightGridSize;
int lightGridBounds[3];
// RB end
};

View file

@ -109,10 +109,17 @@ void idRenderProgManager::Init()
{ BUILTIN_VERTEX_COLOR, "builtin/vertex_color", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING, "builtin/lighting/ambient_lighting", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING_SKINNED, "builtin/lighting/ambient_lighting", "_skinned", BIT( USE_GPU_SKINNING ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING_IBL, "builtin/lighting/ambient_lighting_IBL", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING_IBL_SKINNED, "builtin/lighting/ambient_lighting_IBL", "_skinned", BIT( USE_GPU_SKINNING ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING_IBL_PBR, "builtin/lighting/ambient_lighting_IBL", "_PBR", BIT( USE_PBR ), false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTING_IBL_PBR_SKINNED, "builtin/lighting/ambient_lighting_IBL", "_PBR_skinned", BIT( USE_GPU_SKINNING | USE_PBR ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTGRID_IBL, "builtin/lighting/ambient_lightgrid_IBL", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTGRID_IBL_SKINNED, "builtin/lighting/ambient_lightgrid_IBL", "_skinned", BIT( USE_GPU_SKINNING ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR, "builtin/lighting/ambient_lightgrid_IBL", "_PBR", BIT( USE_PBR ), false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR_SKINNED, "builtin/lighting/ambient_lightgrid_IBL", "_PBR_skinned", BIT( USE_GPU_SKINNING | USE_PBR ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_SMALL_GEOMETRY_BUFFER, "builtin/gbuffer", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
{ BUILTIN_SMALL_GEOMETRY_BUFFER_SKINNED, "builtin/gbuffer", "_skinned", BIT( USE_GPU_SKINNING ), true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
// RB end
@ -279,8 +286,13 @@ void idRenderProgManager::Init()
renderProgs[builtinShaders[BUILTIN_DEBUG_LIGHTGRID_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_DEBUG_OCTAHEDRON_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_AMBIENT_LIGHTING_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_AMBIENT_LIGHTING_IBL_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_AMBIENT_LIGHTING_IBL_PBR_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_AMBIENT_LIGHTGRID_IBL_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_SMALL_GEOMETRY_BUFFER_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_INTERACTION_SHADOW_MAPPING_SPOT_SKINNED]].usesJoints = true;
renderProgs[builtinShaders[BUILTIN_INTERACTION_SHADOW_MAPPING_POINT_SKINNED]].usesJoints = true;

View file

@ -311,6 +311,28 @@ public:
BindShader_Builtin( BUILTIN_AMBIENT_LIGHTING_IBL_PBR_SKINNED );
}
void BindShader_ImageBasedLightGrid()
{
BindShader_Builtin( BUILTIN_AMBIENT_LIGHTGRID_IBL );
}
void BindShader_ImageBasedLightGridSkinned()
{
BindShader_Builtin( BUILTIN_AMBIENT_LIGHTGRID_IBL_SKINNED );
}
void BindShader_ImageBasedLightGrid_PBR()
{
BindShader_Builtin( BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR );
}
void BindShader_ImageBasedLightGridSkinned_PBR()
{
BindShader_Builtin( BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR_SKINNED );
}
void BindShader_SmallGeometryBuffer()
{
BindShader_Builtin( BUILTIN_SMALL_GEOMETRY_BUFFER );
@ -741,10 +763,17 @@ private:
BUILTIN_VERTEX_COLOR,
BUILTIN_AMBIENT_LIGHTING,
BUILTIN_AMBIENT_LIGHTING_SKINNED,
BUILTIN_AMBIENT_LIGHTING_IBL,
BUILTIN_AMBIENT_LIGHTING_IBL_SKINNED,
BUILTIN_AMBIENT_LIGHTING_IBL_PBR,
BUILTIN_AMBIENT_LIGHTING_IBL_PBR_SKINNED,
BUILTIN_AMBIENT_LIGHTGRID_IBL,
BUILTIN_AMBIENT_LIGHTGRID_IBL_SKINNED,
BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR,
BUILTIN_AMBIENT_LIGHTGRID_IBL_PBR_SKINNED,
BUILTIN_SMALL_GEOMETRY_BUFFER,
BUILTIN_SMALL_GEOMETRY_BUFFER_SKINNED,
// RB end

View file

@ -5229,6 +5229,631 @@ static const cgShaderDef_t cg_renderprogs[] =
},
{
"renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl",
"/*\n"
"===========================================================================\n"
"\n"
"Doom 3 BFG Edition GPL Source Code\n"
"Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n"
"Copyright (C) 2013-2021 Robert Beckebans\n"
"\n"
"This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n"
"\n"
"Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation, either version 3 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.\n"
"\n"
"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.\n"
"\n"
"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.\n"
"\n"
"===========================================================================\n"
"*/\n"
"\n"
"#include \"renderprogs/global.inc.hlsl\"\n"
"\n"
"#include \"renderprogs/BRDF.inc.hlsl\"\n"
"\n"
"\n"
"// *INDENT-OFF*\n"
"uniform sampler2D samp0 : register(s0); // texture 0 is the per-surface normal map\n"
"uniform sampler2D samp1 : register(s1); // texture 1 is the per-surface specular or roughness/metallic/AO mixer map\n"
"uniform sampler2D samp2 : register(s2); // texture 2 is the per-surface baseColor map \n"
"uniform sampler2D samp3 : register(s3); // texture 3 is the BRDF LUT\n"
"uniform sampler2D samp4 : register(s4); // texture 4 is SSAO\n"
"\n"
"uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map\n"
"uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map\n"
"\n"
"struct PS_IN \n"
"{\n"
" half4 position : VPOS;\n"
" half4 texcoord0 : TEXCOORD0_centroid;\n"
" half4 texcoord1 : TEXCOORD1_centroid;\n"
" half4 texcoord2 : TEXCOORD2_centroid;\n"
" half4 texcoord3 : TEXCOORD3_centroid;\n"
" half4 texcoord4 : TEXCOORD4_centroid;\n"
" half4 texcoord5 : TEXCOORD5_centroid;\n"
" half4 texcoord6 : TEXCOORD6_centroid;\n"
" half4 texcoord7 : TEXCOORD7_centroid;\n"
" half4 color : COLOR0;\n"
"};\n"
"\n"
"struct PS_OUT\n"
"{\n"
" half4 color : COLOR;\n"
"};\n"
"// *INDENT-ON*\n"
"\n"
"\n"
"float3 lightGridOrigin = float3( -192.0, -128.0, 0 );\n"
"float3 lightGridSize = float3( 64.0, 64.0, 128.0 );\n"
"int3 lightGridBounds = int3( 7, 7, 3 );\n"
"\n"
"int3 GetBaseGridCoord( float3 origin )\n"
"{\n"
" int3 pos;\n"
"\n"
" float3 lightOrigin = origin - lightGridOrigin;\n"
" for( int i = 0; i < 3; i++ )\n"
" {\n"
" float v;\n"
"\n"
" v = lightOrigin[i] * ( 1.0f / lightGridSize[i] );\n"
" pos[i] = int( floor( v ) );\n"
"\n"
" if( pos[i] < 0 )\n"
" {\n"
" pos[i] = 0;\n"
" }\n"
" else if( pos[i] >= lightGridBounds[i] - 1 )\n"
" {\n"
" pos[i] = lightGridBounds[i] - 1;\n"
" }\n"
" }\n"
"\n"
" return pos;\n"
"}\n"
"\n"
"\n"
"// RB: TODO OPTIMIZE\n"
"// this is a straight port of idBounds::RayIntersection\n"
"bool AABBRayIntersection( float3 b[2], float3 start, float3 dir, out float scale )\n"
"{\n"
" int i, ax0, ax1, ax2, side, inside;\n"
" float f;\n"
" float3 hit;\n"
"\n"
" ax0 = -1;\n"
" inside = 0;\n"
" for( i = 0; i < 3; i++ )\n"
" {\n"
" if( start[i] < b[0][i] )\n"
" {\n"
" side = 0;\n"
" }\n"
" else if( start[i] > b[1][i] )\n"
" {\n"
" side = 1;\n"
" }\n"
" else\n"
" {\n"
" inside++;\n"
" continue;\n"
" }\n"
" if( dir[i] == 0.0f )\n"
" {\n"
" continue;\n"
" }\n"
"\n"
" f = ( start[i] - b[side][i] );\n"
"\n"
" if( ax0 < 0 || abs( f ) > abs( scale * dir[i] ) )\n"
" {\n"
" scale = - ( f / dir[i] );\n"
" ax0 = i;\n"
" }\n"
" }\n"
"\n"
" if( ax0 < 0 )\n"
" {\n"
" scale = 0.0f;\n"
"\n"
" // return true if the start point is inside the bounds\n"
" return ( inside == 3 );\n"
" }\n"
"\n"
" ax1 = ( ax0 + 1 ) % 3;\n"
" ax2 = ( ax0 + 2 ) % 3;\n"
" hit[ax1] = start[ax1] + scale * dir[ax1];\n"
" hit[ax2] = start[ax2] + scale * dir[ax2];\n"
"\n"
" return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&\n"
" hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );\n"
"}\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" half4 bumpMap = tex2D( samp0, fragment.texcoord0.xy );\n"
" half4 YCoCG = tex2D( samp2, fragment.texcoord1.xy );\n"
" half4 specMapSRGB = tex2D( samp1, fragment.texcoord2.xy );\n"
" half4 specMap = sRGBAToLinearRGBA( specMapSRGB );\n"
"\n"
" half3 diffuseMap = sRGBToLinearRGB( ConvertYCoCgToRGB( YCoCG ) );\n"
"\n"
" half3 localNormal;\n"
"#if defined(USE_NORMAL_FMT_RGB8)\n"
" localNormal.xy = bumpMap.rg - 0.5;\n"
"#else\n"
" localNormal.xy = bumpMap.wy - 0.5;\n"
"#endif\n"
" localNormal.z = sqrt( abs( dot( localNormal.xy, localNormal.xy ) - 0.25 ) );\n"
" localNormal = normalize( localNormal );\n"
"\n"
" float3 globalNormal;\n"
" globalNormal.x = dot3( localNormal, fragment.texcoord4 );\n"
" globalNormal.y = dot3( localNormal, fragment.texcoord5 );\n"
" globalNormal.z = dot3( localNormal, fragment.texcoord6 );\n"
" globalNormal = normalize( globalNormal );\n"
"\n"
" float3 globalPosition = fragment.texcoord7.xyz;\n"
"\n"
" // RB: rpGlobalLightOrigin is global view origin\n"
" float3 globalEye = normalize( rpGlobalLightOrigin.xyz - globalPosition );\n"
"\n"
" float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal );\n"
" reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalEye );\n"
"\n"
"#if 1\n"
" // parallax box correction using portal area bounds\n"
" float hitScale;\n"
" float3 bounds[2];\n"
" bounds[0].x = rpWobbleSkyX.x;\n"
" bounds[0].y = rpWobbleSkyX.y;\n"
" bounds[0].z = rpWobbleSkyX.z;\n"
"\n"
" bounds[1].x = rpWobbleSkyY.x;\n"
" bounds[1].y = rpWobbleSkyY.y;\n"
" bounds[1].z = rpWobbleSkyY.z;\n"
"\n"
" // global fragment position\n"
" float3 rayStart = fragment.texcoord7.xyz;\n"
"\n"
" // we can't start inside the box so move this outside and use the reverse path\n"
" rayStart += reflectionVector * 10000.0;\n"
"\n"
" // only do a box <-> ray intersection test if we use a local cubemap\n"
" if( ( rpWobbleSkyX.w > 0.0 ) && AABBRayIntersection( bounds, rayStart, -reflectionVector, hitScale ) )\n"
" {\n"
" float3 hitPoint = rayStart - reflectionVector * hitScale;\n"
"\n"
" // rpWobbleSkyZ is cubemap center\n"
" reflectionVector = hitPoint - rpWobbleSkyZ.xyz;\n"
" }\n"
"#endif\n"
"\n"
" half vDotN = saturate( dot3( globalEye, globalNormal ) );\n"
"\n"
"#if defined( USE_PBR )\n"
" const half metallic = specMapSRGB.g;\n"
" const half roughness = specMapSRGB.r;\n"
" const half glossiness = 1.0 - roughness;\n"
"\n"
" // the vast majority of real-world materials (anything not metal or gems) have F(0°)\n"
" // values in a very narrow range (~0.02 - 0.08)\n"
"\n"
" // approximate non-metals with linear RGB 0.04 which is 0.08 * 0.5 (default in UE4)\n"
" const half3 dielectricColor = half3( 0.04 );\n"
"\n"
" // derive diffuse and specular from albedo(m) base color\n"
" const half3 baseColor = diffuseMap;\n"
"\n"
" half3 diffuseColor = baseColor * ( 1.0 - metallic );\n"
" half3 specularColor = lerp( dielectricColor, baseColor, metallic );\n"
"\n"
"#if defined( DEBUG_PBR )\n"
" diffuseColor = half3( 0.0, 0.0, 0.0 );\n"
" specularColor = half3( 0.0, 1.0, 0.0 );\n"
"#endif\n"
"\n"
" float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );\n"
" float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic );\n"
"\n"
"#else\n"
" const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );\n"
"\n"
" half3 diffuseColor = diffuseMap;\n"
" half3 specularColor = specMap.rgb;\n"
"\n"
"#if defined( DEBUG_PBR )\n"
" diffuseColor = half3( 0.0, 0.0, 0.0 );\n"
" specularColor = half3( 1.0, 0.0, 0.0 );\n"
"#endif\n"
"\n"
" float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );\n"
"\n"
" // NOTE: metalness is missing\n"
" float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS );\n"
"\n"
"#endif\n"
"\n"
" //diffuseColor = half3( 1.0, 1.0, 1.0 );\n"
" //diffuseColor = half3( 0.0, 0.0, 0.0 );\n"
"\n"
" // calculate the screen texcoord in the 0.0 to 1.0 range\n"
" //float2 screenTexCoord = vposToScreenPosTexCoord( fragment.position.xy );\n"
" float2 screenTexCoord = fragment.position.xy * rpWindowCoord.xy;\n"
"\n"
" float ao = 1.0;\n"
" ao = tex2D( samp4, screenTexCoord ).r;\n"
" //diffuseColor.rgb *= ao;\n"
"\n"
" // evaluate diffuse IBL\n"
"\n"
" float2 normalizedOctCoord = octEncode( globalNormal );\n"
" float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
"\n"
"// lightgrid atlas\n"
" float invXY = ( 1.0 / ( lightGridBounds[0] * lightGridBounds[1] ) );\n"
" float invZ = ( 1.0 / lightGridBounds[2] );\n"
"\n"
" normalizedOctCoordZeroOne.x *= invXY;\n"
" normalizedOctCoordZeroOne.y *= invZ;\n"
"\n"
" int3 gridCoord;\n"
" float3 frac;\n"
" float3 lightOrigin = globalPosition - lightGridOrigin;\n"
"\n"
" for( int i = 0; i < 3; i++ )\n"
" {\n"
" float v;\n"
"\n"
" v = lightOrigin[i] * ( 1.0f / lightGridSize[i] );\n"
" gridCoord[i] = int( floor( v ) );\n"
" frac[ i ] = v - gridCoord[ i ];\n"
"\n"
" if( gridCoord[i] < 0 )\n"
" {\n"
" gridCoord[i] = 0;\n"
" }\n"
" else if( gridCoord[i] >= lightGridBounds[i] - 1 )\n"
" {\n"
" gridCoord[i] = lightGridBounds[i] - 1;\n"
" }\n"
" }\n"
"\n"
" // trilerp the light value\n"
" int3 gridStep;\n"
"\n"
" gridStep[0] = 1;\n"
" gridStep[1] = lightGridBounds[0];\n"
" gridStep[2] = lightGridBounds[0] * lightGridBounds[1];\n"
"\n"
" float totalFactor = 0.0;\n"
" float3 irradiance;\n"
"\n"
" /*\n"
" for( int i = 0; i < 8; i++ )\n"
" {\n"
" for( int j = 0; j < 3; j++ )\n"
" {\n"
" if( i & ( 1 << j ) )\n"
"\n"
" results in these offsets\n"
" */\n"
" const float3 cornerOffsets[8] = float3[](\n"
" float3( 0.0, 0.0, 0.0 ),\n"
" float3( 1.0, 0.0, 0.0 ),\n"
" float3( 0.0, 2.0, 0.0 ),\n"
" float3( 1.0, 2.0, 0.0 ),\n"
" float3( 0.0, 0.0, 4.0 ),\n"
" float3( 1.0, 0.0, 4.0 ),\n"
" float3( 0.0, 2.0, 4.0 ),\n"
" float3( 1.0, 2.0, 4.0 ) );\n"
"\n"
" for( int i = 0; i < 8; i++ )\n"
" {\n"
" float factor = 1.0;\n"
"\n"
" int3 gridCoord2 = gridCoord;\n"
"\n"
" for( int j = 0; j < 3; j++ )\n"
" {\n"
" if( cornerOffsets[ i ][ j ] > 0.0f )\n"
" {\n"
" factor *= frac[ j ];\n"
"\n"
" gridCoord2[ j ] += 1;\n"
" }\n"
" else\n"
" {\n"
" factor *= ( 1.0f - frac[ j ] );\n"
" }\n"
" }\n"
"\n"
" float2 atlasOffset;\n"
"\n"
" atlasOffset.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[1] * gridStep[1] ) * invXY;\n"
" atlasOffset.y = ( gridCoord2[2] * invZ );\n"
"\n"
" irradiance += tex2D( samp7, normalizedOctCoordZeroOne + atlasOffset ).rgb * factor;\n"
"\n"
" totalFactor += factor;\n"
" }\n"
"\n"
" if( totalFactor > 0 && totalFactor < 0.99 )\n"
" {\n"
" totalFactor = 1.0f / totalFactor;\n"
"\n"
" irradiance *= totalFactor;\n"
" }\n"
"\n"
"// lightgrid atlas\n"
"\n"
"\n"
" float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ao * ( rpDiffuseModifier.xyz * 1.0 );\n"
"\n"
" // evaluate specular IBL\n"
"\n"
" // should be 8 = numMips - 1, 256^2 = 9 mips\n"
" const float MAX_REFLECTION_LOD = 10.0;\n"
" float mip = clamp( ( roughness * MAX_REFLECTION_LOD ), 0.0, MAX_REFLECTION_LOD );\n"
" //float mip = 0.0;\n"
"\n"
" normalizedOctCoord = octEncode( reflectionVector );\n"
" normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
"\n"
" float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;\n"
" //radiance = float3( 0.0 );\n"
"\n"
" float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg;\n"
"\n"
"#if 0\n"
" result.color.rgb = float3( envBRDF.x, envBRDF.y, 0.0 );\n"
" result.color.w = fragment.color.a;\n"
" return;\n"
"#endif\n"
"\n"
" float specAO = ComputeSpecularAO( vDotN, ao, roughness );\n"
" float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 );\n"
"\n"
"#if 0\n"
" // Marmoset Horizon Fade trick\n"
" const half horizonFade = 1.3;\n"
" half horiz = saturate( 1.0 + horizonFade * saturate( dot3( reflectionVector, globalNormal ) ) );\n"
" horiz *= horiz;\n"
" //horiz = clamp( horiz, 0.0, 1.0 );\n"
"#endif\n"
"\n"
" half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n"
"\n"
" //result.color.rgb = diffuseLight;\n"
" //result.color.rgb = diffuseLight * lightColor;\n"
" //result.color.rgb = specularLight;\n"
" result.color.rgb = ( diffuseLight + specularLight ) * lightColor * fragment.color.rgb;\n"
" //result.color.rgb = localNormal.xyz * 0.5 + 0.5;\n"
" //result.color.rgb = float3( ao );\n"
" result.color.w = fragment.color.a;\n"
"}\n"
"\n"
},
{
"renderprogs/builtin/lighting/ambient_lightgrid_IBL.vs.hlsl",
"/*\n"
"===========================================================================\n"
"\n"
"Doom 3 BFG Edition GPL Source Code\n"
"Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n"
"Copyright (C) 2013-2015 Robert Beckebans\n"
"\n"
"This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n"
"\n"
"Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation, either version 3 of the License, or\n"
"(at your option) any later version.\n"
"\n"
"Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.\n"
"\n"
"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.\n"
"\n"
"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.\n"
"\n"
"===========================================================================\n"
"*/\n"
"\n"
"#include \"renderprogs/global.inc.hlsl\"\n"
"\n"
"\n"
"#if defined( USE_GPU_SKINNING )\n"
"uniform matrices_ubo { float4 matrices[408]; };\n"
"#endif\n"
"\n"
"// *INDENT-OFF*\n"
"struct VS_IN {\n"
" float4 position : POSITION;\n"
" float2 texcoord : TEXCOORD0;\n"
" float4 normal : NORMAL;\n"
" float4 tangent : TANGENT;\n"
" float4 color : COLOR0;\n"
" float4 color2 : COLOR1;\n"
"};\n"
"\n"
"struct VS_OUT {\n"
" float4 position : POSITION;\n"
" float4 texcoord0 : TEXCOORD0;\n"
" float4 texcoord1 : TEXCOORD1;\n"
" float4 texcoord2 : TEXCOORD2;\n"
" float4 texcoord3 : TEXCOORD3;\n"
" float4 texcoord4 : TEXCOORD4;\n"
" float4 texcoord5 : TEXCOORD5;\n"
" float4 texcoord6 : TEXCOORD6;\n"
" float4 texcoord7 : TEXCOORD7;\n"
" float4 color : COLOR0;\n"
"};\n"
"// *INDENT-ON*\n"
"\n"
"void main( VS_IN vertex, out VS_OUT result )\n"
"{\n"
"\n"
" float4 vNormal = vertex.normal * 2.0 - 1.0;\n"
" float4 vTangent = vertex.tangent * 2.0 - 1.0;\n"
" float3 vBitangent = cross( vNormal.xyz, vTangent.xyz ) * vTangent.w;\n"
"\n"
"#if defined( USE_GPU_SKINNING )\n"
" //--------------------------------------------------------------\n"
" // GPU transformation of the normal / tangent / bitangent\n"
" //\n"
" // multiplying with 255.1 give us the same result and is faster than floor( w * 255 + 0.5 )\n"
" //--------------------------------------------------------------\n"
" const float w0 = vertex.color2.x;\n"
" const float w1 = vertex.color2.y;\n"
" const float w2 = vertex.color2.z;\n"
" const float w3 = vertex.color2.w;\n"
"\n"
" float4 matX, matY, matZ; // must be float4 for vec4\n"
" int joint = int( vertex.color.x * 255.1 * 3.0 );\n"
" matX = matrices[int( joint + 0 )] * w0;\n"
" matY = matrices[int( joint + 1 )] * w0;\n"
" matZ = matrices[int( joint + 2 )] * w0;\n"
"\n"
" joint = int( vertex.color.y * 255.1 * 3.0 );\n"
" matX += matrices[int( joint + 0 )] * w1;\n"
" matY += matrices[int( joint + 1 )] * w1;\n"
" matZ += matrices[int( joint + 2 )] * w1;\n"
"\n"
" joint = int( vertex.color.z * 255.1 * 3.0 );\n"
" matX += matrices[int( joint + 0 )] * w2;\n"
" matY += matrices[int( joint + 1 )] * w2;\n"
" matZ += matrices[int( joint + 2 )] * w2;\n"
"\n"
" joint = int( vertex.color.w * 255.1 * 3.0 );\n"
" matX += matrices[int( joint + 0 )] * w3;\n"
" matY += matrices[int( joint + 1 )] * w3;\n"
" matZ += matrices[int( joint + 2 )] * w3;\n"
"\n"
" float3 normal;\n"
" normal.x = dot3( matX, vNormal );\n"
" normal.y = dot3( matY, vNormal );\n"
" normal.z = dot3( matZ, vNormal );\n"
" normal = normalize( normal );\n"
"\n"
" float3 tangent;\n"
" tangent.x = dot3( matX, vTangent );\n"
" tangent.y = dot3( matY, vTangent );\n"
" tangent.z = dot3( matZ, vTangent );\n"
" tangent = normalize( tangent );\n"
"\n"
" float3 bitangent;\n"
" bitangent.x = dot3( matX, vBitangent );\n"
" bitangent.y = dot3( matY, vBitangent );\n"
" bitangent.z = dot3( matZ, vBitangent );\n"
" bitangent = normalize( bitangent );\n"
"\n"
" float4 modelPosition;\n"
" modelPosition.x = dot4( matX, vertex.position );\n"
" modelPosition.y = dot4( matY, vertex.position );\n"
" modelPosition.z = dot4( matZ, vertex.position );\n"
" modelPosition.w = 1.0;\n"
"\n"
"#else\n"
" float4 modelPosition = vertex.position;\n"
" float3 normal = vNormal.xyz;\n"
" float3 tangent = vTangent.xyz;\n"
" float3 bitangent = vBitangent.xyz;\n"
"#endif\n"
"\n"
" result.position.x = dot4( modelPosition, rpMVPmatrixX );\n"
" result.position.y = dot4( modelPosition, rpMVPmatrixY );\n"
" result.position.z = dot4( modelPosition, rpMVPmatrixZ );\n"
" result.position.w = dot4( modelPosition, rpMVPmatrixW );\n"
"\n"
" float4 defaultTexCoord = float4( 0.0f, 0.5f, 0.0f, 1.0f );\n"
"\n"
" //calculate vector to light\n"
" //float4 toLight = rpLocalLightOrigin;\n"
" float4 toLight = normalize( float4( 0.0f, 0.5f, 1.0f, 1.0f ) );\n"
"\n"
" //--------------------------------------------------------------\n"
"\n"
"\n"
" //# textures 0 takes the base coordinates by the texture matrix\n"
" result.texcoord0 = defaultTexCoord;\n"
" result.texcoord0.x = dot4( vertex.texcoord.xy, rpBumpMatrixS );\n"
" result.texcoord0.y = dot4( vertex.texcoord.xy, rpBumpMatrixT );\n"
"\n"
" //# textures 1 takes the base coordinates by the texture matrix\n"
" result.texcoord1 = defaultTexCoord;\n"
" result.texcoord1.x = dot4( vertex.texcoord.xy, rpDiffuseMatrixS );\n"
" result.texcoord1.y = dot4( vertex.texcoord.xy, rpDiffuseMatrixT );\n"
"\n"
" //# textures 2 takes the base coordinates by the texture matrix\n"
" result.texcoord2 = defaultTexCoord;\n"
" result.texcoord2.x = dot4( vertex.texcoord.xy, rpSpecularMatrixS );\n"
" result.texcoord2.y = dot4( vertex.texcoord.xy, rpSpecularMatrixT );\n"
"\n"
" //# calculate normalized vector to viewer in R1\n"
" //result.texcoord3 = modelPosition;\n"
"\n"
" float4 toEye = normalize( rpLocalViewOrigin - modelPosition );\n"
"\n"
" result.texcoord3.x = dot3( toEye, rpModelMatrixX );\n"
" result.texcoord3.y = dot3( toEye, rpModelMatrixY );\n"
" result.texcoord3.z = dot3( toEye, rpModelMatrixZ );\n"
"\n"
" result.texcoord4.x = dot3( tangent, rpModelMatrixX );\n"
" result.texcoord5.x = dot3( tangent, rpModelMatrixY );\n"
" result.texcoord6.x = dot3( tangent, rpModelMatrixZ );\n"
"\n"
" result.texcoord4.y = dot3( bitangent, rpModelMatrixX );\n"
" result.texcoord5.y = dot3( bitangent, rpModelMatrixY );\n"
" result.texcoord6.y = dot3( bitangent, rpModelMatrixZ );\n"
"\n"
" result.texcoord4.z = dot3( normal, rpModelMatrixX );\n"
" result.texcoord5.z = dot3( normal, rpModelMatrixY );\n"
" result.texcoord6.z = dot3( normal, rpModelMatrixZ );\n"
"\n"
" float4 worldPosition;\n"
" worldPosition.x = dot4( modelPosition, rpModelMatrixX );\n"
" worldPosition.y = dot4( modelPosition, rpModelMatrixY );\n"
" worldPosition.z = dot4( modelPosition, rpModelMatrixZ );\n"
" worldPosition.w = dot4( modelPosition, rpModelMatrixW );\n"
" result.texcoord7 = worldPosition;\n"
"\n"
"#if defined( USE_GPU_SKINNING )\n"
" // for joint transformation of the tangent space, we use color and\n"
" // color2 for weighting information, so hopefully there aren't any\n"
" // effects that need vertex color...\n"
" result.color = float4( 1.0f, 1.0f, 1.0f, 1.0f );\n"
"#else\n"
" //# generate the vertex color, which can be 1.0, color, or 1.0 - color\n"
" //# for 1.0 : env[16] = 0, env[17] = 1\n"
" //# for color : env[16] = 1, env[17] = 0\n"
" //# for 1.0-color : env[16] = -1, env[17] = 1\n"
" result.color = ( swizzleColor( vertex.color ) * rpVertexColorModulate ) + rpVertexColorAdd;\n"
"#endif\n"
"}\n"
},
{
"renderprogs/builtin/lighting/interaction.ps.hlsl",
"/*\n"

View file

@ -549,6 +549,22 @@ void R_RenderView( viewDef_t* parms )
tr.viewDef->irradianceImage = globalImages->defaultUACIrradianceCube;
tr.viewDef->radianceImage = globalImages->defaultUACRadianceCube;
bool useLightGrid = tr.viewDef->useLightGrid = false;
portalArea_t* area = &tr.primaryWorld->portalAreas[tr.viewDef->areaNum];
if( area->lightGrid.irradianceImage && !area->lightGrid.irradianceImage->IsDefaulted() )
{
tr.viewDef->irradianceImage = area->lightGrid.irradianceImage;
tr.viewDef->useLightGrid = useLightGrid = true;
for( int i = 0; i < 3; i++ )
{
tr.viewDef->lightGridOrigin[i] = area->lightGrid.lightGridOrigin[i];
tr.viewDef->lightGridSize[i] = area->lightGrid.lightGridSize[i];
tr.viewDef->lightGridBounds[i] = area->lightGrid.lightGridBounds[i];
}
}
for( viewEnvprobe_t* vProbe = tr.viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next )
{
float dist = ( tr.viewDef->renderView.vieworg - vProbe->globalOrigin ).Length();
@ -557,7 +573,11 @@ void R_RenderView( viewDef_t* parms )
if( vProbe->irradianceImage->IsLoaded() && !vProbe->irradianceImage->IsDefaulted() )
{
tr.viewDef->globalProbeBounds = vProbe->globalProbeBounds;
tr.viewDef->irradianceImage = vProbe->irradianceImage;
if( !useLightGrid )
{
tr.viewDef->irradianceImage = vProbe->irradianceImage;
}
tr.viewDef->radianceImage = vProbe->radianceImage;
bestDist = dist;