From 0596300c4578a33b3c2c0662b95f56ac3da77116 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Thu, 15 Apr 2021 15:01:31 +0200 Subject: [PATCH] Combined lightgrid trilerp with IBL PBR lighting --- base/renderprogs/_manifest.lua | 2 + .../lighting/ambient_lightgrid_IBL.ps.hlsl | 414 ++++++++++++ .../lighting/ambient_lightgrid_IBL.vs.hlsl | 200 ++++++ neo/renderer/OpenGL/RenderDebug_GL.cpp | 6 +- neo/renderer/RenderBackend.cpp | 84 ++- neo/renderer/RenderCommon.h | 6 + neo/renderer/RenderProgs.cpp | 12 + neo/renderer/RenderProgs.h | 29 + neo/renderer/RenderProgs_embedded.h | 625 ++++++++++++++++++ neo/renderer/tr_frontend_main.cpp | 22 +- 10 files changed, 1397 insertions(+), 3 deletions(-) create mode 100644 base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl create mode 100644 base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.vs.hlsl diff --git a/base/renderprogs/_manifest.lua b/base/renderprogs/_manifest.lua index 7878a186..6c98de7a 100644 --- a/base/renderprogs/_manifest.lua +++ b/base/renderprogs/_manifest.lua @@ -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", diff --git a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl new file mode 100644 index 00000000..38d06221 --- /dev/null +++ b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl @@ -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 . + +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; +} diff --git a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.vs.hlsl b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.vs.hlsl new file mode 100644 index 00000000..35bd0b7b --- /dev/null +++ b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.vs.hlsl @@ -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 . + +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 +} \ No newline at end of file diff --git a/neo/renderer/OpenGL/RenderDebug_GL.cpp b/neo/renderer/OpenGL/RenderDebug_GL.cpp index f8684580..2a88cc0a 100644 --- a/neo/renderer/OpenGL/RenderDebug_GL.cpp +++ b/neo/renderer/OpenGL/RenderDebug_GL.cpp @@ -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]; diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 96f1f59b..f4af42dc 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -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; diff --git a/neo/renderer/RenderCommon.h b/neo/renderer/RenderCommon.h index 9e45b250..17910cbe 100644 --- a/neo/renderer/RenderCommon.h +++ b/neo/renderer/RenderCommon.h @@ -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 }; diff --git a/neo/renderer/RenderProgs.cpp b/neo/renderer/RenderProgs.cpp index cfb9c982..329df96f 100644 --- a/neo/renderer/RenderProgs.cpp +++ b/neo/renderer/RenderProgs.cpp @@ -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; diff --git a/neo/renderer/RenderProgs.h b/neo/renderer/RenderProgs.h index 76114f8b..59f97fed 100644 --- a/neo/renderer/RenderProgs.h +++ b/neo/renderer/RenderProgs.h @@ -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 diff --git a/neo/renderer/RenderProgs_embedded.h b/neo/renderer/RenderProgs_embedded.h index 2d797e87..644bdc9c 100644 --- a/neo/renderer/RenderProgs_embedded.h +++ b/neo/renderer/RenderProgs_embedded.h @@ -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 .\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 .\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" diff --git a/neo/renderer/tr_frontend_main.cpp b/neo/renderer/tr_frontend_main.cpp index e9199c01..5adfb5f3 100644 --- a/neo/renderer/tr_frontend_main.cpp +++ b/neo/renderer/tr_frontend_main.cpp @@ -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;