mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-13 22:22:05 +00:00
Merge branch '946-better-blood'
This commit is contained in:
commit
5df21bdfc0
25 changed files with 1515 additions and 228 deletions
|
@ -19,6 +19,30 @@ TBD - RBDOOM-3-BFG 1.6.0
|
|||
_______________________________
|
||||
|
||||
|
||||
## .plan - November 27, 2024
|
||||
|
||||
Another test build.
|
||||
|
||||
Changelog:
|
||||
|
||||
* Added new PBR roughness and specular color estimation by Kennedith98
|
||||
|
||||
* Tuned r_lightScale influence for PBR so specular is less dominant
|
||||
|
||||
* Added back SMAA so r_antiAliasing 1 = SMAA, 2 = TAA
|
||||
|
||||
* Fixed TAA problems with 3D guis and transparent decals
|
||||
|
||||
* Killed 3DTV render code. It's either VR or flat.
|
||||
|
||||
* MOC now renders only at the half resolution for better perf
|
||||
|
||||
* Improved interpolation between env_probes, especially when they are parallel placed
|
||||
|
||||
* Updated NVRHI with Nvidia's latest patches
|
||||
|
||||
|
||||
|
||||
## .plan - September 06, 2024
|
||||
|
||||
This is a test build for the Masked Software Occlusion Culling (MOC) implementation. Many modern engines have a solution like Umbra integrated that automatically hides hidden objects in the renderer before they even get rendered to optimize the performance.
|
||||
|
|
|
@ -573,6 +573,7 @@ public:
|
|||
idImage* blackImage; // full of 0x00
|
||||
idImage* blackDiffuseImage; // full of 0x00
|
||||
idImage* cyanImage; // cyan
|
||||
idImage* redClayImage; // dark red
|
||||
idImage* noFalloffImage; // all 255, but zero clamped
|
||||
idImage* fogImage; // increasing alpha is denser fog
|
||||
idImage* fogEnterImage; // adjust fogImage alpha based on terminator plane
|
||||
|
|
|
@ -170,6 +170,24 @@ static void R_CyanImage( idImage* image, nvrhi::ICommandList* commandList )
|
|||
image->GenerateImage( ( byte* )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, TR_REPEAT, TD_DIFFUSE, commandList );
|
||||
}
|
||||
|
||||
static void R_RedClayImage( idImage* image, nvrhi::ICommandList* commandList )
|
||||
{
|
||||
byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
|
||||
|
||||
for( int x = 0; x < DEFAULT_SIZE; x++ )
|
||||
{
|
||||
for( int y = 0; y < DEFAULT_SIZE; y++ )
|
||||
{
|
||||
data[y][x][0] = 165;
|
||||
data[y][x][1] = 42;
|
||||
data[y][x][2] = 42;
|
||||
data[y][x][3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
image->GenerateImage( ( byte* )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, TR_REPEAT, TD_DIFFUSE, commandList );
|
||||
}
|
||||
|
||||
static void R_ChromeSpecImage( idImage* image, nvrhi::ICommandList* commandList )
|
||||
{
|
||||
byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
|
||||
|
@ -181,7 +199,7 @@ static void R_ChromeSpecImage( idImage* image, nvrhi::ICommandList* commandList
|
|||
data[y][x][0] = 0;
|
||||
data[y][x][1] = 255;
|
||||
data[y][x][2] = 255;
|
||||
data[y][x][3] = 255;
|
||||
data[y][x][3] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,10 +214,10 @@ static void R_PlasticSpecImage( idImage* image, nvrhi::ICommandList* commandList
|
|||
{
|
||||
for( int y = 0; y < DEFAULT_SIZE; y++ )
|
||||
{
|
||||
data[y][x][0] = 0;
|
||||
data[y][x][0] = 32;
|
||||
data[y][x][1] = 0;
|
||||
data[y][x][2] = 255;
|
||||
data[y][x][3] = 255;
|
||||
data[y][x][3] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1046,6 +1064,7 @@ void idImageManager::CreateIntrinsicImages()
|
|||
blackImage = ImageFromFunction( "_black", R_BlackImage );
|
||||
blackDiffuseImage = ImageFromFunction( "_blackDiffuse", R_BlackDiffuseImage );
|
||||
cyanImage = ImageFromFunction( "_cyan", R_CyanImage );
|
||||
redClayImage = ImageFromFunction( "_redClay", R_RedClayImage );
|
||||
flatNormalMap = ImageFromFunction( "_flat", R_FlatNormalImage );
|
||||
alphaNotchImage = ImageFromFunction( "_alphaNotch", R_AlphaNotchImage );
|
||||
fogImage = ImageFromFunction( "_fog", R_FogImage );
|
||||
|
|
|
@ -1918,6 +1918,10 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
|
|||
{
|
||||
ts->texgen = TG_REFLECT_CUBE;
|
||||
}
|
||||
else if( !token.Icmp( "reflect2" ) )
|
||||
{
|
||||
ts->texgen = TG_REFLECT_CUBE2;
|
||||
}
|
||||
else if( !token.Icmp( "skybox" ) )
|
||||
{
|
||||
ts->texgen = TG_SKYBOX_CUBE;
|
||||
|
@ -2759,6 +2763,11 @@ void idMaterial::ParseMaterial( idLexer& src )
|
|||
mikktspace = true;
|
||||
continue;
|
||||
}
|
||||
else if( !token.Icmp( "unlit" ) )
|
||||
{
|
||||
SetMaterialFlag( MF_UNLIT );
|
||||
continue;
|
||||
}
|
||||
// lightFallofImage <imageprogram>
|
||||
// specifies the image to use for the third axis of projected
|
||||
// light volumes
|
||||
|
|
|
@ -164,11 +164,12 @@ typedef enum
|
|||
TG_EXPLICIT,
|
||||
TG_DIFFUSE_CUBE,
|
||||
TG_REFLECT_CUBE,
|
||||
TG_REFLECT_CUBE2, // RB interpolates 3 octahedrons like for ambient lighting
|
||||
TG_SKYBOX_CUBE,
|
||||
TG_WOBBLESKY_CUBE,
|
||||
TG_SCREEN, // screen aligned, for mirrorRenders and screen space temporaries
|
||||
TG_SCREEN2,
|
||||
TG_GLASSWARP
|
||||
TG_GLASSWARP,
|
||||
} texgen_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -361,9 +362,8 @@ typedef enum
|
|||
MF_LOD3 = BIT( 9 ), // motorsep 11-24-2014; material flag for LOD3 iteration
|
||||
MF_LOD4 = BIT( 10 ), // motorsep 11-24-2014; material flag for LOD4 iteration
|
||||
MF_LOD_PERSISTENT = BIT( 11 ), // motorsep 11-24-2014; material flag for persistent LOD iteration
|
||||
MF_GUITARGET = BIT( 12 ), // Admer: this GUI surface is used to compute a GUI render map, but a GUI should NOT be drawn on it
|
||||
MF_AUTOGEN_TEMPLATE = BIT( 13 ), // Admer: this material is a template for auto-generated templates
|
||||
MF_ORIGIN = BIT( 14 ), // Admer: for origin brushes
|
||||
MF_ORIGIN = BIT( 12 ), // Admer: for origin brushes
|
||||
MF_UNLIT = BIT( 13 ), // RB: receive no lighting
|
||||
} materialFlags_t;
|
||||
|
||||
// contents flags, NOTE: make sure to keep the defines in doom_defs.script up to date with these!
|
||||
|
@ -595,7 +595,7 @@ public:
|
|||
// stages, and don't interact with lights at all
|
||||
bool ReceivesLighting() const
|
||||
{
|
||||
return numAmbientStages != numStages;
|
||||
return ( numAmbientStages != numStages ) && ( materialFlags & MF_UNLIT ) == 0;
|
||||
}
|
||||
|
||||
// returns true if the material should generate interactions on sides facing away
|
||||
|
|
|
@ -1787,6 +1787,102 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
|
|||
}
|
||||
}
|
||||
}
|
||||
else if( type == BINDING_LAYOUT_OCTAHEDRON_CUBE || type == BINDING_LAYOUT_OCTAHEDRON_CUBE_SKINNED )
|
||||
{
|
||||
if( type == BINDING_LAYOUT_OCTAHEDRON_CUBE_SKINNED )
|
||||
{
|
||||
if( desc[0].bindings.empty() )
|
||||
{
|
||||
desc[0].bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, paramCb, range ),
|
||||
nvrhi::BindingSetItem::StructuredBuffer_SRV( 11, currentJointBuffer, nvrhi::Format::UNKNOWN, nvrhi::BufferRange( currentJointOffset, sizeof( idVec4 ) * numBoneMatrices ) )
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& bindings = desc[0].bindings;
|
||||
bindings[0].resourceHandle = paramCb;
|
||||
bindings[0].range = range;
|
||||
|
||||
bindings[1].resourceHandle = currentJointBuffer;
|
||||
bindings[1].range = nvrhi::BufferRange{ currentJointOffset, sizeof( idVec4 )* numBoneMatrices };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( desc[0].bindings.empty() )
|
||||
{
|
||||
desc[0].bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::ConstantBuffer( 0, paramCb, range ),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
desc[0].bindings[0].resourceHandle = paramCb;
|
||||
desc[0].bindings[0].range = range;
|
||||
}
|
||||
}
|
||||
|
||||
if( desc[1].bindings.empty() )
|
||||
{
|
||||
desc[1].bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 1, ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 2, ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 3, ( nvrhi::ITexture* )GetImageAt( 3 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 4, ( nvrhi::ITexture* )GetImageAt( 4 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 5, ( nvrhi::ITexture* )GetImageAt( 5 )->GetTextureID() ),
|
||||
nvrhi::BindingSetItem::Texture_SRV( 6, ( nvrhi::ITexture* )GetImageAt( 6 )->GetTextureID() )
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& bindings = desc[1].bindings;
|
||||
bindings[0].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID();
|
||||
bindings[1].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID();
|
||||
bindings[2].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 2 )->GetTextureID();
|
||||
bindings[3].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 3 )->GetTextureID();
|
||||
bindings[4].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 4 )->GetTextureID();
|
||||
bindings[5].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 5 )->GetTextureID();
|
||||
bindings[6].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 6 )->GetTextureID();
|
||||
}
|
||||
|
||||
if( R_UsePixelatedLook() )
|
||||
{
|
||||
if( desc[2].bindings.empty() )
|
||||
{
|
||||
desc[2].bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_PointWrapSampler ),
|
||||
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
desc[2].bindings[0].resourceHandle = commonPasses.m_PointWrapSampler;
|
||||
desc[2].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( desc[2].bindings.empty() )
|
||||
{
|
||||
desc[2].bindings =
|
||||
{
|
||||
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_AnisotropicWrapSampler ),
|
||||
nvrhi::BindingSetItem::Sampler( 1, commonPasses.m_LinearBorderSampler )
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
desc[2].bindings[0].resourceHandle = commonPasses.m_AnisotropicWrapSampler;
|
||||
desc[2].bindings[1].resourceHandle = commonPasses.m_LinearBorderSampler;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( type == BINDING_LAYOUT_BINK_VIDEO )
|
||||
{
|
||||
if( desc[0].bindings.empty() )
|
||||
|
|
|
@ -336,7 +336,14 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
|
|||
{
|
||||
if( texture->image != NULL )
|
||||
{
|
||||
texture->image->Bind();
|
||||
if( texture->image->IsLoaded() && !texture->image->IsDefaulted() )
|
||||
{
|
||||
texture->image->Bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
globalImages->defaultImage->Bind();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,7 +363,6 @@ void idRenderBackend::PrepareStageTexturing( const shaderStage_t* pStage, const
|
|||
// texgens
|
||||
if( pStage->texture.texgen == TG_REFLECT_CUBE )
|
||||
{
|
||||
|
||||
// see if there is also a bump map specified
|
||||
const shaderStage_t* bumpStage = surf->material->GetBumpStage();
|
||||
if( bumpStage != NULL )
|
||||
|
@ -387,7 +393,130 @@ void idRenderBackend::PrepareStageTexturing( const shaderStage_t* pStage, const
|
|||
renderProgManager.BindShader_Environment();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_REFLECT_CUBE2 )
|
||||
{
|
||||
if( r_useSSR.GetBool() && R_UseHiZ() )
|
||||
{
|
||||
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() );
|
||||
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_S, viewDef->probePositions[0].ToFloatPtr() );
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_T, viewDef->probePositions[1].ToFloatPtr() );
|
||||
SetVertexParm( RENDERPARM_TEXGEN_0_Q, viewDef->probePositions[2].ToFloatPtr() );
|
||||
|
||||
// specular cubemap blend weights
|
||||
renderProgManager.SetUniformValue( RENDERPARM_LOCALLIGHTORIGIN, viewDef->radianceImageBlends.ToFloatPtr() );
|
||||
|
||||
// general SSR parms
|
||||
idVec4 ssrParms;
|
||||
ssrParms.x = r_ssrStride.GetFloat();
|
||||
ssrParms.y = r_ssrMaxDistance.GetFloat();
|
||||
ssrParms.z = r_ssrZThickness.GetFloat();
|
||||
ssrParms.w = r_ssrJitter.GetFloat();
|
||||
|
||||
idVec4 jitterTexScale;
|
||||
jitterTexScale.x = r_ssrMaxDistance.GetFloat();
|
||||
jitterTexScale.y = 0;
|
||||
jitterTexScale.z = 0;
|
||||
jitterTexScale.w = 0;
|
||||
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale.ToFloatPtr() ); // rpJitterTexScale
|
||||
|
||||
renderProgManager.SetUniformValue( RENDERPARM_GLOBALLIGHTORIGIN, ssrParms.ToFloatPtr() );
|
||||
|
||||
// allow reconstruction of depth buffer value to full view space position
|
||||
SetVertexParms( RENDERPARM_SHADOW_MATRIX_0_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 );
|
||||
|
||||
// we need to rotate the normals from world space to view space
|
||||
idRenderMatrix viewMatrix;
|
||||
idRenderMatrix::Transpose( *( idRenderMatrix* ) viewDef->worldSpace.modelViewMatrix, viewMatrix );
|
||||
//SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, viewMatrix[0], 4 );
|
||||
|
||||
// this is the main requirement for the DDA SSR algorithm next to the linear z buffer
|
||||
// we need clip space [-1..1] -> window space [0..1] -> to texture space [0..w|h]
|
||||
ALIGNTYPE16 const idRenderMatrix matClipToUvzw(
|
||||
0.5f, 0.0f, 0.0f, 0.5f,
|
||||
0.0f, -0.5f, 0.0f, 0.5f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
|
||||
// should this be the viewport width / height instead?
|
||||
int w = renderSystem->GetWidth();
|
||||
int h = renderSystem->GetHeight();
|
||||
|
||||
ALIGNTYPE16 const idRenderMatrix screenScale(
|
||||
w, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, h, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
);
|
||||
|
||||
idRenderMatrix screenSpaceScaled;
|
||||
idRenderMatrix::Multiply( screenScale, matClipToUvzw, screenSpaceScaled );
|
||||
|
||||
idRenderMatrix screenSpace;
|
||||
idRenderMatrix::Multiply( screenSpaceScaled, viewDef->projectionRenderMatrix, screenSpace );
|
||||
|
||||
SetVertexParms( RENDERPARM_SHADOW_MATRIX_1_X, screenSpace[0], 4 );
|
||||
|
||||
|
||||
// see if there is also a bump map specified
|
||||
const shaderStage_t* bumpStage = surf->material->GetBumpStage();
|
||||
if( bumpStage != NULL )
|
||||
{
|
||||
// per-pixel reflection mapping with bump mapping
|
||||
GL_SelectTexture( 0 );
|
||||
bumpStage->texture.image->Bind();
|
||||
//globalImages->flatNormalMap->Bind();
|
||||
|
||||
GL_SelectTexture( 1 );
|
||||
globalImages->currentRenderImage->Bind();
|
||||
|
||||
GL_SelectTexture( 2 );
|
||||
globalImages->gbufferNormalsRoughnessImage->Bind();
|
||||
|
||||
GL_SelectTexture( 3 );
|
||||
// use hierachical Z to avoid read & write at the same time on the depth buffer
|
||||
globalImages->hierarchicalZbufferImage->Bind();
|
||||
|
||||
GL_SelectTexture( 4 );
|
||||
viewDef->radianceImages[0]->Bind();
|
||||
|
||||
GL_SelectTexture( 5 );
|
||||
viewDef->radianceImages[1]->Bind();
|
||||
|
||||
GL_SelectTexture( 6 );
|
||||
viewDef->radianceImages[2]->Bind();
|
||||
|
||||
GL_SelectTexture( 0 );
|
||||
|
||||
if( surf->jointCache )
|
||||
{
|
||||
renderProgManager.BindShader_BumpyEnvironment2Skinned();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderProgManager.BindShader_BumpyEnvironment2();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( pStage->texture.texgen == TG_SKYBOX_CUBE )
|
||||
{
|
||||
|
@ -395,7 +524,6 @@ void idRenderBackend::PrepareStageTexturing( const shaderStage_t* pStage, const
|
|||
}
|
||||
else if( pStage->texture.texgen == TG_WOBBLESKY_CUBE )
|
||||
{
|
||||
|
||||
const int* parms = surf->material->GetTexGenRegisters();
|
||||
|
||||
float wobbleDegrees = surf->shaderRegisters[ parms[0] ] * ( idMath::PI / 180.0f );
|
||||
|
@ -453,7 +581,6 @@ void idRenderBackend::PrepareStageTexturing( const shaderStage_t* pStage, const
|
|||
}
|
||||
else if( ( pStage->texture.texgen == TG_SCREEN ) || ( pStage->texture.texgen == TG_SCREEN2 ) )
|
||||
{
|
||||
|
||||
useTexGenParm[0] = 1.0f;
|
||||
useTexGenParm[1] = 1.0f;
|
||||
useTexGenParm[2] = 1.0f;
|
||||
|
@ -518,7 +645,7 @@ void idRenderBackend::FinishStageTexturing( const shaderStage_t* pStage, const d
|
|||
GL_SelectTexture( 0 );
|
||||
}
|
||||
|
||||
if( pStage->texture.texgen == TG_REFLECT_CUBE )
|
||||
if( pStage->texture.texgen == TG_REFLECT_CUBE || pStage->texture.texgen == TG_REFLECT_CUBE2 )
|
||||
{
|
||||
// see if there is also a bump map specified
|
||||
const shaderStage_t* bumpStage = surf->material->GetBumpStage();
|
||||
|
@ -531,6 +658,7 @@ void idRenderBackend::FinishStageTexturing( const shaderStage_t* pStage, const d
|
|||
{
|
||||
// per-pixel reflection mapping without bump mapping
|
||||
}
|
||||
|
||||
renderProgManager.Unbind();
|
||||
}
|
||||
}
|
||||
|
@ -994,7 +1122,14 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
|
|||
return;
|
||||
}
|
||||
|
||||
if( r_skipDiffuse.GetInteger() == 2 )
|
||||
if( r_skipDiffuse.GetInteger() == 3 )
|
||||
{
|
||||
// RB: for testing specular aliasing
|
||||
din->diffuseImage = globalImages->redClayImage;
|
||||
din->specularImage = globalImages->plasticSpecImage;
|
||||
din->specularColor = colorWhite;
|
||||
}
|
||||
else if( r_skipDiffuse.GetInteger() == 2 )
|
||||
{
|
||||
din->diffuseImage = globalImages->whiteImage;
|
||||
}
|
||||
|
@ -1704,9 +1839,11 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view
|
|||
|
||||
// apply the world-global overbright and the 2x factor for specular
|
||||
idVec4 diffuseColor = lightColor;
|
||||
// jmarshall
|
||||
idVec4 specularColor = lightColor * 2.0f;
|
||||
|
||||
// RB: the BFG edition has exagerated specular lighting compared to vanilla Doom 3
|
||||
// turn this back to 1.0
|
||||
idVec4 specularColor = lightColor * 1.0f;
|
||||
// jmarshall
|
||||
if( vLight->lightDef->parms.noSpecular )
|
||||
{
|
||||
specularColor.Zero();
|
||||
|
@ -2067,13 +2204,13 @@ void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDr
|
|||
|
||||
if( fillGbuffer )
|
||||
{
|
||||
commandList->clearTextureFloat( globalImages->gbufferNormalsRoughnessImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 0.f ) );
|
||||
commandList->clearTextureFloat( globalImages->gbufferNormalsRoughnessImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 0.0f ) );
|
||||
}
|
||||
|
||||
// RB: TODO remove this
|
||||
if( !fillGbuffer && r_useSSAO.GetBool() && r_ssaoDebug.GetBool() )
|
||||
{
|
||||
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS );
|
||||
GL_State( GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS | GLS_CULL_TWOSIDED );
|
||||
|
||||
// We just want to do a quad pass - so make sure we disable any texgen and
|
||||
// set the texture matrix to the identity so we don't get anomalies from
|
||||
|
@ -5035,31 +5172,7 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef
|
|||
int screenWidth = renderSystem->GetWidth();
|
||||
int screenHeight = renderSystem->GetHeight();
|
||||
|
||||
commandList->clearTextureFloat( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) );
|
||||
commandList->clearTextureFloat( globalImages->ambientOcclusionImage[0]->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) );
|
||||
|
||||
// build hierarchical depth buffer
|
||||
if( r_useHierarchicalDepthBuffer.GetBool() )
|
||||
{
|
||||
renderLog.OpenBlock( "Render_HiZ" );
|
||||
|
||||
//if( R_GetMSAASamples() > 1 )
|
||||
//{
|
||||
// commandList->resolveTexture( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, globalImages->currentDepthImage->GetTextureHandle(), nvrhi::AllSubresources );
|
||||
//}
|
||||
//else
|
||||
{
|
||||
commonPasses.BlitTexture(
|
||||
commandList,
|
||||
globalFramebuffers.csDepthFBO[0]->GetApiObject(),
|
||||
globalImages->currentDepthImage->GetTextureHandle(),
|
||||
&bindingCache );
|
||||
}
|
||||
|
||||
hiZGenPass->Dispatch( commandList, MAX_HIERARCHICAL_ZBUFFERS );
|
||||
|
||||
renderLog.CloseBlock();
|
||||
}
|
||||
commandList->clearTextureFloat( globalImages->ambientOcclusionImage[0]->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.0f ) );
|
||||
|
||||
if( previousFramebuffer != NULL )
|
||||
{
|
||||
|
@ -5151,7 +5264,7 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef
|
|||
globalImages->gbufferNormalsRoughnessImage->Bind();
|
||||
|
||||
GL_SelectTexture( 1 );
|
||||
if( r_useHierarchicalDepthBuffer.GetBool() )
|
||||
if( R_UseHiZ() )
|
||||
{
|
||||
globalImages->hierarchicalZbufferImage->Bind();
|
||||
}
|
||||
|
@ -5433,8 +5546,10 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
OPTICK_GPU_CONTEXT( ( void* ) commandList->getNativeObject( commandObject ) );
|
||||
//OPTICK_GPU_EVENT( "DrawView" ); // SRS - now in DrawView() for 3D vs. GUI
|
||||
|
||||
bool is3D = _viewDef->viewEntitys && !_viewDef->is2Dgui;
|
||||
|
||||
// ugly but still faster than building the string
|
||||
if( !_viewDef->viewEntitys || _viewDef->is2Dgui )
|
||||
if( !is3D )
|
||||
{
|
||||
if( stereoEye == -1 )
|
||||
{
|
||||
|
@ -5503,7 +5618,6 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
// ensures that depth writes are enabled for the depth clear
|
||||
GL_State( GLS_DEFAULT | GLS_CULL_FRONTSIDED, true );
|
||||
|
||||
bool useHDR = !_viewDef->is2Dgui;
|
||||
bool clearColor = false;
|
||||
|
||||
if( _viewDef->renderView.rdflags & RDF_IRRADIANCE )
|
||||
|
@ -5511,7 +5625,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
globalFramebuffers.envprobeFBO->Bind();
|
||||
clearColor = true;
|
||||
}
|
||||
else if( useHDR )
|
||||
else if( is3D )
|
||||
{
|
||||
globalFramebuffers.hdrFBO->Bind();
|
||||
}
|
||||
|
@ -5561,9 +5675,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
SetFragmentParm( RENDERPARM_OVERBRIGHT, parm );
|
||||
|
||||
// Set Projection Matrix
|
||||
float projMatrixTranspose[16];
|
||||
R_MatrixTranspose( viewDef->projectionMatrix, projMatrixTranspose );
|
||||
SetVertexParms( RENDERPARM_PROJMATRIX_X, projMatrixTranspose, 4 );
|
||||
SetVertexParms( RENDERPARM_PROJMATRIX_X, viewDef->projectionRenderMatrix[0], 4 );
|
||||
|
||||
// PSX jitter parms
|
||||
if( ( r_renderMode.GetInteger() == RENDERMODE_PSX ) && ( _viewDef->viewEntitys && !_viewDef->is2Dgui ) )
|
||||
|
@ -5588,6 +5700,19 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
}
|
||||
|
||||
SetVertexParm( RENDERPARM_PSX_DISTORTIONS, parm );
|
||||
|
||||
// make sure rpWindowCoord is set even without post processing surfaces in the view
|
||||
int x = viewDef->viewport.x1;
|
||||
int y = viewDef->viewport.y1;
|
||||
int w = viewDef->viewport.x2 - viewDef->viewport.x1 + 1;
|
||||
int h = viewDef->viewport.y2 - viewDef->viewport.y1 + 1;
|
||||
|
||||
float windowCoordParm[4];
|
||||
windowCoordParm[0] = 1.0f / w;
|
||||
windowCoordParm[1] = 1.0f / h;
|
||||
windowCoordParm[2] = w;
|
||||
windowCoordParm[3] = h;
|
||||
SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -5595,12 +5720,32 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
//-------------------------------------------------
|
||||
FillDepthBufferFast( drawSurfs, numDrawSurfs );
|
||||
|
||||
//-------------------------------------------------
|
||||
// build hierarchical depth buffer
|
||||
//-------------------------------------------------
|
||||
if( R_UseHiZ() && is3D )
|
||||
{
|
||||
renderLog.OpenBlock( "Render_HiZ" );
|
||||
|
||||
commandList->clearTextureFloat( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) );
|
||||
|
||||
commonPasses.BlitTexture(
|
||||
commandList,
|
||||
globalFramebuffers.csDepthFBO[0]->GetApiObject(),
|
||||
globalImages->currentDepthImage->GetTextureHandle(),
|
||||
&bindingCache );
|
||||
|
||||
hiZGenPass->Dispatch( commandList, MAX_HIERARCHICAL_ZBUFFERS );
|
||||
|
||||
renderLog.CloseBlock();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// FIXME, OPTIMIZE: merge this with FillDepthBufferFast like in a light prepass deferred renderer
|
||||
//
|
||||
// fill the geometric buffer with normals and roughness
|
||||
//-------------------------------------------------
|
||||
if( viewDef->viewEntitys ) // 3D views only
|
||||
if( is3D )
|
||||
{
|
||||
//OPTICK_EVENT( "Render_GeometryBuffer" );
|
||||
OPTICK_GPU_EVENT( "Render_GeometryBuffer" );
|
||||
|
@ -5623,7 +5768,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
//-------------------------------------------------
|
||||
// render static lighting and consider SSAO results
|
||||
//-------------------------------------------------
|
||||
if( viewDef->viewEntitys ) // 3D views only
|
||||
if( is3D )
|
||||
{
|
||||
//OPTICK_EVENT( "Render_AmbientPass" );
|
||||
OPTICK_GPU_EVENT( "Render_AmbientPass" );
|
||||
|
@ -5641,9 +5786,35 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
//-------------------------------------------------
|
||||
DrawInteractions( _viewDef );
|
||||
|
||||
//-------------------------------------------------
|
||||
// resolve the screen for SSR
|
||||
//-------------------------------------------------
|
||||
{
|
||||
if( R_GetMSAASamples() > 1 )
|
||||
{
|
||||
renderLog.OpenBlock( "Resolve to _currentRender" );
|
||||
|
||||
commandList->resolveTexture( globalImages->currentRenderImage->GetTextureHandle(), nvrhi::AllSubresources, globalImages->currentRenderHDRImage->GetTextureHandle(), nvrhi::AllSubresources );
|
||||
}
|
||||
else
|
||||
{
|
||||
renderLog.OpenBlock( "Blit to _currentRender" );
|
||||
|
||||
BlitParameters blitParms;
|
||||
nvrhi::IFramebuffer* currentFB = ( nvrhi::IFramebuffer* )currentFrameBuffer->GetApiObject();
|
||||
blitParms.sourceTexture = currentFB->getDesc().colorAttachments[0].texture;
|
||||
blitParms.targetFramebuffer = globalFramebuffers.postProcFBO->GetApiObject(); // _currentRender image
|
||||
blitParms.targetViewport = nvrhi::Viewport( renderSystem->GetWidth(), renderSystem->GetHeight() );
|
||||
commonPasses.BlitTexture( commandList, blitParms, &bindingCache );
|
||||
}
|
||||
|
||||
renderLog.CloseBlock();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// now draw any non-light dependent shading passes
|
||||
//-------------------------------------------------
|
||||
|
||||
int processed = 0;
|
||||
if( !r_skipShaderPasses.GetBool() )
|
||||
{
|
||||
|
@ -5759,7 +5930,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
|
|||
// tonemapping: convert back from HDR to LDR range
|
||||
//-------------------------------------------------
|
||||
|
||||
if( useHDR && !( _viewDef->renderView.rdflags & RDF_IRRADIANCE ) && !_viewDef->targetRender )
|
||||
if( is3D && !( _viewDef->renderView.rdflags & RDF_IRRADIANCE ) && !_viewDef->targetRender )
|
||||
{
|
||||
OPTICK_GPU_EVENT( "Render_ToneMapPass" );
|
||||
|
||||
|
@ -6373,23 +6544,8 @@ void idRenderBackend::PostProcess( const void* data )
|
|||
globalImages->gbufferNormalsRoughnessImage->Bind();
|
||||
|
||||
GL_SelectTexture( 3 );
|
||||
if( r_useHierarchicalDepthBuffer.GetBool() )
|
||||
if( R_UseHiZ() )
|
||||
{
|
||||
// build hierarchical depth buffer
|
||||
renderLog.OpenBlock( "Render_HiZ" );
|
||||
|
||||
commandList->clearTextureFloat( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) );
|
||||
|
||||
commonPasses.BlitTexture(
|
||||
commandList,
|
||||
globalFramebuffers.csDepthFBO[0]->GetApiObject(),
|
||||
globalImages->currentDepthImage->GetTextureHandle(),
|
||||
&bindingCache );
|
||||
|
||||
hiZGenPass->Dispatch( commandList, MAX_HIERARCHICAL_ZBUFFERS );
|
||||
|
||||
renderLog.CloseBlock();
|
||||
|
||||
globalImages->hierarchicalZbufferImage->Bind();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -623,12 +623,13 @@ struct viewDef_t
|
|||
// RB: collect environment probes like lights
|
||||
viewEnvprobe_t* viewEnvprobes;
|
||||
|
||||
// RB: nearest probe for now
|
||||
// RB: nearest 3 probes for now
|
||||
idBounds globalProbeBounds;
|
||||
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* radianceImages[3]; // cubemap image used for specular IBL by backend
|
||||
idVec4 radianceImageBlends; // blending weights
|
||||
idVec4 probePositions[3]; // only used by parallax correction
|
||||
|
||||
Framebuffer* targetRender; // SP: The framebuffer to render to
|
||||
|
||||
|
@ -823,6 +824,9 @@ enum bindingLayoutType_t
|
|||
BINDING_LAYOUT_NORMAL_CUBE,
|
||||
BINDING_LAYOUT_NORMAL_CUBE_SKINNED,
|
||||
|
||||
BINDING_LAYOUT_OCTAHEDRON_CUBE,
|
||||
BINDING_LAYOUT_OCTAHEDRON_CUBE_SKINNED,
|
||||
|
||||
// NO GPU SKINNING ANYMORE
|
||||
BINDING_LAYOUT_POST_PROCESS_INGAME,
|
||||
BINDING_LAYOUT_POST_PROCESS_FINAL,
|
||||
|
@ -1263,6 +1267,13 @@ extern idCVar r_useLightGrid;
|
|||
|
||||
extern idCVar r_exposure;
|
||||
|
||||
extern idCVar r_useSSR;
|
||||
extern idCVar r_ssrJitter;
|
||||
extern idCVar r_ssrMaxDistance;
|
||||
extern idCVar r_ssrMaxSteps;
|
||||
extern idCVar r_ssrStride;
|
||||
extern idCVar r_ssrZThickness;
|
||||
|
||||
extern idCVar r_useTemporalAA;
|
||||
extern idCVar r_taaJitter;
|
||||
extern idCVar r_taaEnableHistoryClamping;
|
||||
|
@ -1315,6 +1326,8 @@ bool R_UsePixelatedLook();
|
|||
|
||||
bool R_UseTemporalAA();
|
||||
|
||||
bool R_UseHiZ();
|
||||
|
||||
uint R_GetMSAASamples();
|
||||
|
||||
void R_SetNewMode( const bool fullInit );
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2013-2023 Robert Beckebans
|
||||
Copyright (C) 2013-2024 Robert Beckebans
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
@ -368,6 +368,27 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
|
|||
skinningLayout, normalCubeBindingLayout, samplerOneBindingLayout
|
||||
};
|
||||
|
||||
auto octahedronCubeBindingLayoutDesc = nvrhi::BindingLayoutDesc()
|
||||
.setVisibility( nvrhi::ShaderType::Pixel )
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) ) // normal map
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 1 ) ) // HDR _currentRender
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 2 ) ) // _currentNormals
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 3 ) ) // _currentDepth
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 4 ) ) // radiance cube map 1
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 5 ) ) // radiance cube map 2
|
||||
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 6 ) ); // radiance cube map 3
|
||||
|
||||
auto octahedronCubeBindingLayout = device->createBindingLayout( octahedronCubeBindingLayoutDesc );
|
||||
|
||||
bindingLayouts[BINDING_LAYOUT_OCTAHEDRON_CUBE] =
|
||||
{
|
||||
uniformsLayout, octahedronCubeBindingLayout, samplerTwoBindingLayout
|
||||
};
|
||||
bindingLayouts[BINDING_LAYOUT_OCTAHEDRON_CUBE_SKINNED] =
|
||||
{
|
||||
skinningLayout, octahedronCubeBindingLayout, samplerTwoBindingLayout
|
||||
};
|
||||
|
||||
auto binkVideoBindingLayout = nvrhi::BindingLayoutDesc()
|
||||
.setVisibility( nvrhi::ShaderType::All )
|
||||
.addItem( renderParmLayoutItem )
|
||||
|
@ -538,6 +559,8 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
|
|||
{ BUILTIN_ENVIRONMENT_SKINNED, "builtin/legacy/environment", "_skinned", { {"USE_GPU_SKINNING", "1" } }, true , SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT_SKINNED },
|
||||
{ BUILTIN_BUMPY_ENVIRONMENT, "builtin/legacy/bumpyenvironment", "", { {"USE_GPU_SKINNING", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_NORMAL_CUBE },
|
||||
{ BUILTIN_BUMPY_ENVIRONMENT_SKINNED, "builtin/legacy/bumpyenvironment", "_skinned", { {"USE_GPU_SKINNING", "1" } }, true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_NORMAL_CUBE_SKINNED },
|
||||
{ BUILTIN_BUMPY_ENVIRONMENT2, "builtin/legacy/bumpyenvironment2", "", { {"USE_GPU_SKINNING", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_OCTAHEDRON_CUBE },
|
||||
{ BUILTIN_BUMPY_ENVIRONMENT2_SKINNED, "builtin/legacy/bumpyenvironment2", "_skinned", { {"USE_GPU_SKINNING", "1" } }, true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_OCTAHEDRON_CUBE_SKINNED },
|
||||
|
||||
{ BUILTIN_DEPTH, "builtin/depth", "", { {"USE_GPU_SKINNING", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_CONSTANT_BUFFER_ONLY },
|
||||
{ BUILTIN_DEPTH_SKINNED, "builtin/depth", "_skinned", { {"USE_GPU_SKINNING", "1" } }, true, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_CONSTANT_BUFFER_ONLY_SKINNED },
|
||||
|
|
|
@ -353,10 +353,13 @@ enum
|
|||
BUILTIN_DEBUG_OCTAHEDRON,
|
||||
BUILTIN_DEBUG_OCTAHEDRON_SKINNED,
|
||||
// RB end
|
||||
|
||||
BUILTIN_ENVIRONMENT,
|
||||
BUILTIN_ENVIRONMENT_SKINNED,
|
||||
BUILTIN_BUMPY_ENVIRONMENT,
|
||||
BUILTIN_BUMPY_ENVIRONMENT_SKINNED,
|
||||
BUILTIN_BUMPY_ENVIRONMENT2, // RB
|
||||
BUILTIN_BUMPY_ENVIRONMENT2_SKINNED, // RB
|
||||
|
||||
BUILTIN_DEPTH,
|
||||
BUILTIN_DEPTH_SKINNED,
|
||||
|
@ -774,6 +777,16 @@ public:
|
|||
BindShader_Builtin( BUILTIN_BUMPY_ENVIRONMENT_SKINNED );
|
||||
}
|
||||
|
||||
void BindShader_BumpyEnvironment2()
|
||||
{
|
||||
BindShader_Builtin( BUILTIN_BUMPY_ENVIRONMENT2 );
|
||||
}
|
||||
|
||||
void BindShader_BumpyEnvironment2Skinned()
|
||||
{
|
||||
BindShader_Builtin( BUILTIN_BUMPY_ENVIRONMENT2_SKINNED );
|
||||
}
|
||||
|
||||
void BindShader_Depth()
|
||||
{
|
||||
BindShader_Builtin( BUILTIN_DEPTH );
|
||||
|
|
|
@ -82,7 +82,7 @@ idCVar r_useValidationLayers( "r_useValidationLayers", "1", CVAR_INTEGER | CVAR_
|
|||
#if ID_MSAA
|
||||
idCVar r_antiAliasing( "r_antiAliasing", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER | CVAR_NEW, " 0 = None\n 1 = TAA 1x\n 2 = TAA + SMAA 1x\n 3 = MSAA 2x\n 4 = MSAA 4x\n", 0, ANTI_ALIASING_MSAA_4X );
|
||||
#else
|
||||
idCVar r_antiAliasing( "r_antiAliasing", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER | CVAR_NEW, " 0 = None\n 1 = SMAA 1x, 2 = TAA", 0, ANTI_ALIASING_TAA );
|
||||
idCVar r_antiAliasing( "r_antiAliasing", "2", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER | CVAR_NEW, " 0 = None\n 1 = SMAA 1x, 2 = TAA", 0, ANTI_ALIASING_TAA );
|
||||
#endif
|
||||
// RB end
|
||||
idCVar r_vidMode( "r_vidMode", "0", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_INTEGER, "fullscreen video mode number" );
|
||||
|
@ -154,7 +154,7 @@ idCVar r_useLightPortalCulling( "r_useLightPortalCulling", "1", CVAR_RENDERER |
|
|||
idCVar r_useLightAreaCulling( "r_useLightAreaCulling", "1", CVAR_RENDERER | CVAR_BOOL, "0 = off, 1 = on" );
|
||||
idCVar r_useLightScissors( "r_useLightScissors", "3", CVAR_RENDERER | CVAR_INTEGER, "0 = no scissor, 1 = non-clipped scissor, 2 = near-clipped scissor, 3 = fully-clipped scissor", 0, 3, idCmdSystem::ArgCompletion_Integer<0, 3> );
|
||||
idCVar r_useEntityPortalCulling( "r_useEntityPortalCulling", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = none, 1 = cull frustum corners to plane, 2 = exact clip the frustum faces", 0, 2, idCmdSystem::ArgCompletion_Integer<0, 2> );
|
||||
idCVar r_clear( "r_clear", "2", CVAR_RENDERER, "force screen clear every frame, 1 = purple, 2 = black, 'r g b' = custom" );
|
||||
idCVar r_clear( "r_clear", "2", CVAR_RENDERER | CVAR_NOCHEAT, "force screen clear every frame, 1 = purple, 2 = black, 'r g b' = custom" );
|
||||
|
||||
idCVar r_offsetFactor( "r_offsetfactor", "0", CVAR_RENDERER | CVAR_FLOAT, "polygon offset parameter" );
|
||||
// RB: offset factor was 0, and units were -600 which caused some very ugly polygon offsets on Android so I reverted the values to the same as in Q3A
|
||||
|
@ -294,6 +294,13 @@ idCVar r_useLightGrid( "r_useLightGrid", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_N
|
|||
|
||||
idCVar r_exposure( "r_exposure", "0.5", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "HDR exposure or LDR brightness [-4.0 .. 4.0]", -4.0f, 4.0f );
|
||||
|
||||
idCVar r_useSSR( "r_useSSR", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL | CVAR_NEW, "" );
|
||||
idCVar r_ssrJitter( "r_ssrJitter", "0", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
|
||||
idCVar r_ssrMaxDistance( "r_ssrMaxDistance", "100", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "In meters" );
|
||||
idCVar r_ssrMaxSteps( "r_ssrMaxSteps", "100", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
|
||||
idCVar r_ssrStride( "r_ssrStride", "12", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
|
||||
idCVar r_ssrZThickness( "r_ssrZThickness", "2", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
|
||||
|
||||
idCVar r_useTemporalAA( "r_useTemporalAA", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "only disable for debugging" );
|
||||
idCVar r_taaJitter( "r_taaJitter", "1", CVAR_RENDERER | CVAR_INTEGER | CVAR_NEW, "0: None, 1: MSAA, 2: Halton, 3: R2 Sequence, 4: White Noise" );
|
||||
idCVar r_taaEnableHistoryClamping( "r_taaEnableHistoryClamping", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "" );
|
||||
|
@ -355,6 +362,12 @@ bool R_UseTemporalAA()
|
|||
}
|
||||
}
|
||||
|
||||
bool R_UseHiZ()
|
||||
{
|
||||
// TODO check for driver problems here
|
||||
return r_useHierarchicalDepthBuffer.GetBool();
|
||||
}
|
||||
|
||||
uint R_GetMSAASamples()
|
||||
{
|
||||
#if ID_MSAA
|
||||
|
|
|
@ -959,6 +959,14 @@ CONSOLE_COMMAND_SHIP( bakeEnvironmentProbes, "Bake environment probes", NULL )
|
|||
// make sure the game / draw thread has completed
|
||||
commonLocal.WaitGameThread();
|
||||
|
||||
// turn vsync off for faster capturing of the probes
|
||||
int oldVsync = r_swapInterval.GetInteger();
|
||||
r_swapInterval.SetInteger( 0 );
|
||||
|
||||
// turn off clear in between views so we keep the progress bar visible
|
||||
int oldClear = r_clear.GetInteger();
|
||||
r_clear.SetInteger( 0 );
|
||||
|
||||
// disable scissor, so we don't need to adjust all those rects
|
||||
r_useScissor.SetBool( false );
|
||||
|
||||
|
@ -1124,6 +1132,9 @@ CONSOLE_COMMAND_SHIP( bakeEnvironmentProbes, "Bake environment probes", NULL )
|
|||
}
|
||||
}
|
||||
|
||||
// generate .bimage file
|
||||
globalImages->ImageFromFile( job->filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
|
||||
|
||||
Mem_Free( job->outBuffer );
|
||||
|
||||
delete job;
|
||||
|
@ -1157,6 +1168,10 @@ CONSOLE_COMMAND_SHIP( bakeEnvironmentProbes, "Bake environment probes", NULL )
|
|||
idLib::Printf( "----------------------------------\n" );
|
||||
idLib::Printf( "Processed %i light probes\n", totalProcessedProbes );
|
||||
common->Printf( "Baked SH irradiance and GGX mip maps in %5.1f minutes\n\n", ( totalEnd - totalStart ) / ( 1000.0f * 60 ) );
|
||||
|
||||
// restore vsync setting
|
||||
r_swapInterval.SetInteger( oldVsync );
|
||||
r_clear.SetInteger( oldClear );
|
||||
}
|
||||
|
||||
CONSOLE_COMMAND( makeBrdfLUT, "make a GGX BRDF lookup table", NULL )
|
||||
|
|
|
@ -1162,6 +1162,10 @@ CONSOLE_COMMAND_SHIP( bakeLightGrids, "Bake irradiance/vis light grid data", NUL
|
|||
int oldVsync = r_swapInterval.GetInteger();
|
||||
r_swapInterval.SetInteger( 0 );
|
||||
|
||||
// turn off clear in between views so we keep the progress bar visible
|
||||
int oldClear = r_clear.GetInteger();
|
||||
r_clear.SetInteger( 0 );
|
||||
|
||||
idLib::Printf( "----------------------------------\n" );
|
||||
idLib::Printf( "Processing %i light probes in %i areas for %i bounces\n", totalProcessedProbes, totalProcessedAreas, bounces );
|
||||
//common->Printf( "ETA %5.1f minutes\n\n", ( totalEnd - totalStart ) / ( 1000.0f * 60 ) );
|
||||
|
@ -1441,5 +1445,6 @@ CONSOLE_COMMAND_SHIP( bakeLightGrids, "Bake irradiance/vis light grid data", NUL
|
|||
|
||||
// restore vsync setting
|
||||
r_swapInterval.SetInteger( oldVsync );
|
||||
r_clear.SetInteger( oldClear );
|
||||
}
|
||||
|
||||
|
|
|
@ -537,6 +537,114 @@ static void R_FindClosestEnvironmentProbes()
|
|||
tr.viewDef->irradianceImage = nearest->irradianceImage;
|
||||
}
|
||||
|
||||
// form a triangle of the 3 closest probes
|
||||
idVec3 verts[3];
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
verts[i] = viewEnvprobes[0]->parms.origin;
|
||||
}
|
||||
|
||||
for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ )
|
||||
{
|
||||
RenderEnvprobeLocal* vProbe = viewEnvprobes[i];
|
||||
|
||||
verts[i] = vProbe->parms.origin;
|
||||
}
|
||||
|
||||
tr.viewDef->probePositions->Set( verts[0].x, verts[0].y, verts[0].z, 1 );
|
||||
tr.viewDef->probePositions->Set( verts[1].x, verts[1].y, verts[1].z, 1 );
|
||||
tr.viewDef->probePositions->Set( verts[2].x, verts[2].y, verts[2].z, 1 );
|
||||
|
||||
idVec3 closest = R_ClosestPointPointTriangle( testOrigin, verts[0], verts[1], verts[2] );
|
||||
idVec3 bary;
|
||||
|
||||
// find the barycentric coordinates
|
||||
float denom = idWinding::TriangleArea( verts[0], verts[1], verts[2] );
|
||||
if( denom == 0 )
|
||||
{
|
||||
// triangle is line
|
||||
float t;
|
||||
|
||||
R_ClosestPointOnLineSegment( testOrigin, verts[0], verts[1], t );
|
||||
|
||||
bary.Set( 1.0f - t, t, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
float a, b, c;
|
||||
|
||||
a = idWinding::TriangleArea( closest, verts[1], verts[2] ) / denom;
|
||||
b = idWinding::TriangleArea( closest, verts[2], verts[0] ) / denom;
|
||||
c = idWinding::TriangleArea( closest, verts[0], verts[1] ) / denom;
|
||||
|
||||
bary.Set( a, b, c );
|
||||
}
|
||||
|
||||
tr.viewDef->radianceImageBlends.Set( bary.x, bary.y, bary.z, 0.0f );
|
||||
|
||||
for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ )
|
||||
{
|
||||
if( !viewEnvprobes[i]->radianceImage->IsDefaulted() )
|
||||
{
|
||||
tr.viewDef->radianceImages[i] = viewEnvprobes[i]->radianceImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this one tries to interpolate between probes over time
|
||||
static void R_FindClosestEnvironmentProbes2()
|
||||
{
|
||||
// set safe defaults
|
||||
tr.viewDef->globalProbeBounds.Clear();
|
||||
|
||||
tr.viewDef->irradianceImage = globalImages->defaultUACIrradianceCube;
|
||||
tr.viewDef->radianceImageBlends.Set( 1, 0, 0, 0 );
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
tr.viewDef->radianceImages[i] = globalImages->defaultUACRadianceCube;
|
||||
}
|
||||
|
||||
// early out
|
||||
if( tr.viewDef->areaNum == -1 || tr.viewDef->isSubview )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idList<RenderEnvprobeLocal*, TAG_RENDER_ENVPROBE> viewEnvprobes;
|
||||
for( int i = 0; i < tr.primaryWorld->envprobeDefs.Num(); i++ )
|
||||
{
|
||||
RenderEnvprobeLocal* vProbe = tr.primaryWorld->envprobeDefs[i];
|
||||
if( vProbe )
|
||||
{
|
||||
// check for being closed off behind a door
|
||||
if( r_useLightAreaCulling.GetBool() && vProbe->areaNum != -1 && !tr.viewDef->connectedAreas[ vProbe->areaNum ] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
viewEnvprobes.AddUnique( vProbe );
|
||||
}
|
||||
}
|
||||
|
||||
if( viewEnvprobes.Num() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idVec3 testOrigin = tr.viewDef->renderView.vieworg;
|
||||
|
||||
// sort by distance
|
||||
// RB: each Doom 3 level has ~50 - 150 probes so this should be ok for each frame
|
||||
viewEnvprobes.SortWithTemplate( idSort_CompareEnvprobe( testOrigin ) );
|
||||
|
||||
RenderEnvprobeLocal* nearest = viewEnvprobes[0];
|
||||
tr.viewDef->globalProbeBounds = nearest->globalProbeBounds;
|
||||
|
||||
if( nearest->irradianceImage->IsLoaded() && !nearest->irradianceImage->IsDefaulted() )
|
||||
{
|
||||
tr.viewDef->irradianceImage = nearest->irradianceImage;
|
||||
}
|
||||
|
||||
static float oldBarycentricWeights[3] = {0};
|
||||
static int oldIndexes[3] = {0};
|
||||
static int timeInterpolateStart = 0;
|
||||
|
@ -559,6 +667,10 @@ static void R_FindClosestEnvironmentProbes()
|
|||
triIndexes[i] = vProbe->index;
|
||||
}
|
||||
|
||||
tr.viewDef->probePositions->Set( verts[0].x, verts[0].y, verts[0].z, 1 );
|
||||
tr.viewDef->probePositions->Set( verts[1].x, verts[1].y, verts[1].z, 1 );
|
||||
tr.viewDef->probePositions->Set( verts[2].x, verts[2].y, verts[2].z, 1 );
|
||||
|
||||
// don't assume tri changed if we just moved inside a triangle and only the indixes switched
|
||||
// because one vertex is closer than before
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
// Normal Distribution Function ( NDF ) or D( h )
|
||||
// GGX ( Trowbridge-Reitz )
|
||||
half Distribution_GGX( half hdotN, half alpha )
|
||||
float Distribution_GGX( float hdotN, float alpha )
|
||||
{
|
||||
// alpha is assumed to be roughness^2
|
||||
float a2 = alpha * alpha;
|
||||
|
@ -38,16 +38,17 @@ half Distribution_GGX( half hdotN, half alpha )
|
|||
return ( a2 / ( PI * tmp * tmp ) );
|
||||
}
|
||||
|
||||
half Distribution_GGX_Disney( half hdotN, half alphaG )
|
||||
float Distribution_GGX_Disney( float hdotN, float alphaG )
|
||||
{
|
||||
float a2 = alphaG * alphaG;
|
||||
float tmp = ( hdotN * hdotN ) * ( a2 - 1.0 ) + 1.0;
|
||||
//tmp *= tmp;
|
||||
tmp *= tmp;
|
||||
|
||||
return ( a2 / ( PI * tmp ) );
|
||||
//return ( a2 / ( PI * tmp ) );
|
||||
return ( a2 / tmp );
|
||||
}
|
||||
|
||||
half Distribution_GGX_1886( half hdotN, half alpha )
|
||||
float Distribution_GGX_1886( float hdotN, float alpha )
|
||||
{
|
||||
// alpha is assumed to be roughness^2
|
||||
return ( alpha / ( PI * pow( hdotN * hdotN * ( alpha - 1.0 ) + 1.0, 2.0 ) ) );
|
||||
|
@ -55,16 +56,16 @@ half Distribution_GGX_1886( half hdotN, half alpha )
|
|||
|
||||
// Fresnel term F( v, h )
|
||||
// Fnone( v, h ) = F(0) = specularColor
|
||||
half3 Fresnel_Schlick( half3 specularColor, half vDotN )
|
||||
float3 Fresnel_Schlick( float3 specularColor, float vDotN )
|
||||
{
|
||||
return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
}
|
||||
|
||||
// Fresnel term that takes roughness into account so rough non-metal surfaces aren't too shiny [Lagarde11]
|
||||
half3 Fresnel_SchlickRoughness( half3 specularColor, half vDotN, half roughness )
|
||||
float3 Fresnel_SchlickRoughness( float3 specularColor, float vDotN, float roughness )
|
||||
{
|
||||
float oneMinusRoughness = 1.0 - roughness;
|
||||
return specularColor + ( max( half3( oneMinusRoughness, oneMinusRoughness, oneMinusRoughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
return specularColor + ( max( float3( oneMinusRoughness, oneMinusRoughness, oneMinusRoughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
}
|
||||
|
||||
// Sebastien Lagarde proposes an empirical approach to derive the specular occlusion term from the diffuse occlusion term in [Lagarde14].
|
||||
|
@ -77,21 +78,21 @@ float ComputeSpecularAO( float vDotN, float ao, float roughness )
|
|||
|
||||
// Visibility term G( l, v, h )
|
||||
// Very similar to Marmoset Toolbag 2 and gives almost the same results as Smith GGX
|
||||
float Visibility_Schlick( half vdotN, half ldotN, float alpha )
|
||||
float Visibility_Schlick( float vdotN, float ldotN, float alpha )
|
||||
{
|
||||
float k = alpha * 0.5;
|
||||
|
||||
float schlickL = ( ldotN * ( 1.0 - k ) + k );
|
||||
float schlickV = ( vdotN * ( 1.0 - k ) + k );
|
||||
|
||||
return ( 0.25 / ( schlickL * schlickV ) );
|
||||
return ( 0.25 / max( 0.001, schlickL * schlickV ) );
|
||||
//return ( ( schlickL * schlickV ) / ( 4.0 * vdotN * ldotN ) );
|
||||
}
|
||||
|
||||
// see s2013_pbs_rad_notes.pdf
|
||||
// Crafting a Next-Gen Material Pipeline for The Order: 1886
|
||||
// this visibility function also provides some sort of back lighting
|
||||
float Visibility_SmithGGX( half vdotN, half ldotN, float alpha )
|
||||
float Visibility_SmithGGX( float vdotN, float ldotN, float alpha )
|
||||
{
|
||||
// alpha is already roughness^2
|
||||
|
||||
|
@ -102,7 +103,7 @@ float Visibility_SmithGGX( half vdotN, half ldotN, float alpha )
|
|||
return ( 1.0 / max( V1 * V2, 0.15 ) );
|
||||
}
|
||||
|
||||
// HACK calculate roughness from D3 gloss maps
|
||||
// RB: HACK calculate roughness from D3 gloss maps
|
||||
float EstimateLegacyRoughness( float3 specMapSRGB )
|
||||
{
|
||||
float Y = dot( LUMINANCE_SRGB.rgb, specMapSRGB );
|
||||
|
@ -115,45 +116,143 @@ float EstimateLegacyRoughness( float3 specMapSRGB )
|
|||
return roughness;
|
||||
}
|
||||
|
||||
#define KENNY_PBR 1
|
||||
|
||||
// Kennedith98 begin
|
||||
// takes a gamma-space specular texture
|
||||
// outputs F0 color and roughness for PBR
|
||||
void PBRFromSpecmap( float3 specMap, out float3 F0, out float roughness )
|
||||
{
|
||||
// desaturate specular
|
||||
//float specLum = max( specMap.r, max( specMap.g, specMap.b ) );
|
||||
float specLum = dot( LUMINANCE_SRGB.rgb, specMap );
|
||||
|
||||
// fresnel base
|
||||
F0 = _float3( 0.04 );
|
||||
|
||||
// fresnel contrast (will tighten low spec and broaden high spec, stops specular looking too flat or shiny)
|
||||
float contrastMid = 0.214;
|
||||
float contrastAmount = 2.0;
|
||||
float contrast = saturate( ( specLum - contrastMid ) / ( 1 - contrastMid ) ); //high spec
|
||||
contrast += saturate( specLum / contrastMid ) - 1.0; //low spec
|
||||
contrast = exp2( contrastAmount * contrast );
|
||||
F0 *= contrast;
|
||||
|
||||
// reverse blinn BRDF to perfectly match vanilla specular brightness
|
||||
// fresnel is affected when specPow is 0, experimentation is desmos showed that happens at F0/4
|
||||
float linearBrightness = Linear1( 2.0 * specLum );
|
||||
float specPow = max( 0.0, ( ( 8 * linearBrightness ) / F0.y ) - 2.0 );
|
||||
F0 *= min( 1.0, linearBrightness / ( F0.y * 0.25 ) );
|
||||
|
||||
// specular power to roughness
|
||||
roughness = sqrt( 2.0 / ( specPow + 2.0 ) );
|
||||
|
||||
#if 1
|
||||
// RB: try to distinct between dielectrics and metal materials
|
||||
float glossiness = saturate( 1.0 - roughness );
|
||||
float metallic = step( 0.7, glossiness );
|
||||
|
||||
float3 glossColor = Linear3( specMap.rgb );
|
||||
F0 = lerp( F0, glossColor, metallic );
|
||||
#endif
|
||||
|
||||
// RB: do another sqrt because PBR shader squares it
|
||||
roughness = sqrt( roughness );
|
||||
}
|
||||
// Kennedith98 end
|
||||
|
||||
// https://yusuketokuyoshi.com/papers/2021/Tokuyoshi2021SAA.pdf
|
||||
|
||||
float2x2 NonAxisAlignedNDFFiltering( float3 halfvectorTS, float2 roughness2 )
|
||||
{
|
||||
// Compute the derivatives of the halfvector in the projected space.
|
||||
float2 halfvector2D = halfvectorTS.xy / abs( halfvectorTS.z );
|
||||
float2 deltaU = ddx( halfvector2D );
|
||||
float2 deltaV = ddy( halfvector2D );
|
||||
|
||||
// Compute 2 * covariance matrix for the filter kernel (Eq. (3)).
|
||||
float SIGMA2 = 0.15915494;
|
||||
float2x2 delta = {deltaU, deltaV};
|
||||
float2x2 kernelRoughnessMat = 2.0 * SIGMA2 * mul( transpose( delta ), delta );
|
||||
|
||||
// Approximate NDF filtering (Eq. (9)).
|
||||
float2x2 roughnessMat = {roughness2.x, 0.0, 0.0, roughness2.y};
|
||||
float2x2 filteredRoughnessMat = roughnessMat + kernelRoughnessMat;
|
||||
|
||||
return filteredRoughnessMat;
|
||||
}
|
||||
|
||||
float2 AxisAlignedNDFFiltering( float3 halfvectorTS, float2 roughness2 )
|
||||
{
|
||||
// Compute the bounding rectangle of halfvector derivatives.
|
||||
float2 halfvector2D = halfvectorTS.xy / abs( halfvectorTS.z );
|
||||
float2 bounds = fwidth( halfvector2D );
|
||||
|
||||
// Compute an axis-aligned filter kernel from the bounding rectangle.
|
||||
float SIGMA2 = 0.15915494;
|
||||
float2 kernelRoughness2 = 2.0 * SIGMA2 * ( bounds * bounds );
|
||||
|
||||
// Approximate NDF filtering (Eq. (9)).
|
||||
// We clamp the kernel size to avoid overfiltering.
|
||||
float KAPPA = 0.18;
|
||||
float2 clampedKernelRoughness2 = min( kernelRoughness2, KAPPA );
|
||||
float2 filteredRoughness2 = saturate( roughness2 + clampedKernelRoughness2 );
|
||||
return filteredRoughness2;
|
||||
}
|
||||
|
||||
|
||||
float IsotropicNDFFiltering( float3 normal, float roughness2 )
|
||||
{
|
||||
const float SIGMA2 = 0.15915494;
|
||||
const float KAPPA = 0.18;
|
||||
float3 dndu = ddx( normal );
|
||||
float3 dndv = ddy( normal );
|
||||
float kernelRoughness2 = 2.0 * SIGMA2 * ( dot( dndu, dndu ) + dot( dndv, dndv ) );
|
||||
float clampedKernelRoughness2 = min( kernelRoughness2, KAPPA );
|
||||
float filteredRoughness2 = saturate( roughness2 + clampedKernelRoughness2 );
|
||||
|
||||
return filteredRoughness2;
|
||||
}
|
||||
|
||||
// Environment BRDF approximations
|
||||
// see s2013_pbs_black_ops_2_notes.pdf
|
||||
/*
|
||||
half a1vf( half g )
|
||||
float a1vf( float g )
|
||||
{
|
||||
return ( 0.25 * g + 0.75 );
|
||||
}
|
||||
|
||||
half a004( half g, half vdotN )
|
||||
float a004( float g, float vdotN )
|
||||
{
|
||||
float t = min( 0.475 * g, exp2( -9.28 * vdotN ) );
|
||||
return ( t + 0.0275 ) * g + 0.015;
|
||||
}
|
||||
|
||||
half a0r( half g, half vdotN )
|
||||
float a0r( float g, float vdotN )
|
||||
{
|
||||
return ( ( a004( g, vdotN ) - a1vf( g ) * 0.04 ) / 0.96 );
|
||||
}
|
||||
|
||||
float3 EnvironmentBRDF( half g, half vdotN, float3 rf0 )
|
||||
float3 EnvironmentBRDF( float g, float vdotN, float3 rf0 )
|
||||
{
|
||||
float4 t = float4( 1.0 / 0.96, 0.475, ( 0.0275 - 0.25 * 0.04 ) / 0.96, 0.25 );
|
||||
t *= float4( g, g, g, g );
|
||||
t += float4( 0.0, 0.0, ( 0.015 - 0.75 * 0.04 ) / 0.96, 0.75 );
|
||||
half a0 = t.x * min( t.y, exp2( -9.28 * vdotN ) ) + t.z;
|
||||
half a1 = t.w;
|
||||
float a0 = t.x * min( t.y, exp2( -9.28 * vdotN ) ) + t.z;
|
||||
float a1 = t.w;
|
||||
|
||||
return saturate( a0 + rf0 * ( a1 - a0 ) );
|
||||
}
|
||||
|
||||
|
||||
half3 EnvironmentBRDFApprox( half roughness, half vdotN, half3 specularColor )
|
||||
float3 EnvironmentBRDFApprox( float roughness, float vdotN, float3 specularColor )
|
||||
{
|
||||
const half4 c0 = half4( -1, -0.0275, -0.572, 0.022 );
|
||||
const half4 c1 = half4( 1, 0.0425, 1.04, -0.04 );
|
||||
const float4 c0 = float4( -1, -0.0275, -0.572, 0.022 );
|
||||
const float4 c1 = float4( 1, 0.0425, 1.04, -0.04 );
|
||||
|
||||
half4 r = roughness * c0 + c1;
|
||||
half a004 = min( r.x * r.x, exp2( -9.28 * vdotN ) ) * r.x + r.y;
|
||||
half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
|
||||
float4 r = roughness * c0 + c1;
|
||||
float a004 = min( r.x * r.x, exp2( -9.28 * vdotN ) ) * r.x + r.y;
|
||||
float2 AB = float2( -1.04, 1.04 ) * a004 + r.zw;
|
||||
|
||||
return specularColor * AB.x + AB.y;
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ float3 reconstructCSPosition( float2 S, float depth )
|
|||
csP.w = dot4( rpModelMatrixW, clip );
|
||||
|
||||
csP.xyz /= csP.w;
|
||||
//csP.z = abs( csP.z ); // this is still negative Z like for OpenGL
|
||||
|
||||
return csP.xyz;
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ void main( VS_IN vertex, out VS_OUT result )
|
|||
//result.texcoord1.z = dot3( toEye, rpModelMatrixZ );
|
||||
|
||||
#if 1
|
||||
// rotate into world space
|
||||
// rotate from tangent space into world space
|
||||
result.texcoord2.x = dot3( tangent, rpModelMatrixX );
|
||||
result.texcoord3.x = dot3( tangent, rpModelMatrixY );
|
||||
result.texcoord4.x = dot3( tangent, rpModelMatrixZ );
|
||||
|
@ -171,7 +171,7 @@ void main( VS_IN vertex, out VS_OUT result )
|
|||
result.texcoord4.z = dot3( normal, rpModelMatrixZ );
|
||||
|
||||
#else
|
||||
// rotate into view space
|
||||
// rotate from tangent space into view space
|
||||
result.texcoord2.x = dot3( tangent, rpModelViewMatrixX );
|
||||
result.texcoord3.x = dot3( tangent, rpModelViewMatrixY );
|
||||
result.texcoord4.x = dot3( tangent, rpModelViewMatrixZ );
|
||||
|
|
491
neo/shaders/builtin/legacy/bumpyenvironment2.ps.hlsl
Normal file
491
neo/shaders/builtin/legacy/bumpyenvironment2.ps.hlsl
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2024 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 "global_inc.hlsl"
|
||||
|
||||
|
||||
// *INDENT-OFF*
|
||||
Texture2D t_NormalMap : register( t0 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_ScreenColor : register( t1 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_ScreenNormals : register( t2 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_Depth : register( t3 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_RadianceCubeMap1 : register( t4 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_RadianceCubeMap2 : register( t5 VK_DESCRIPTOR_SET( 1 ) );
|
||||
Texture2D t_RadianceCubeMap3 : register( t6 VK_DESCRIPTOR_SET( 1 ) );
|
||||
|
||||
SamplerState s_Material : register( s0 VK_DESCRIPTOR_SET( 2 ) );
|
||||
SamplerState s_LinearClamp : register( s1 VK_DESCRIPTOR_SET( 2 ) );
|
||||
|
||||
struct PS_IN
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float2 texcoord0 : TEXCOORD0_centroid;
|
||||
float3 texcoord1 : TEXCOORD1_centroid;
|
||||
float3 texcoord2 : TEXCOORD2_centroid;
|
||||
float3 texcoord3 : TEXCOORD3_centroid;
|
||||
float3 texcoord4 : TEXCOORD4_centroid;
|
||||
float4 texcoord5 : TEXCOORD5_centroid;
|
||||
float4 color : COLOR0;
|
||||
};
|
||||
|
||||
struct PS_OUT
|
||||
{
|
||||
float4 color : SV_Target0;
|
||||
};
|
||||
// *INDENT-ON*
|
||||
|
||||
|
||||
float3 ReconstructPositionCS( int2 hitPixel )
|
||||
{
|
||||
// Load returns 0 for any value accessed out of bounds
|
||||
float depth = texelFetch( t_Depth, hitPixel, 0 ).r;
|
||||
|
||||
float2 uv = hitPixel * rpWindowCoord.xy;
|
||||
|
||||
// derive clip space from the depth buffer and screen position
|
||||
float3 ndc = float3( uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, depth );
|
||||
float clipW = -rpProjectionMatrixZ.w / ( -rpProjectionMatrixZ.z - ndc.z );
|
||||
|
||||
float4 clip = float4( ndc * clipW, clipW );
|
||||
|
||||
// camera space position
|
||||
float4 csP;
|
||||
csP.x = dot4( rpShadowMatrices[0], clip );
|
||||
csP.y = dot4( rpShadowMatrices[1], clip );
|
||||
csP.z = dot4( rpShadowMatrices[2], clip );
|
||||
csP.w = dot4( rpShadowMatrices[3], clip );
|
||||
|
||||
csP.xyz /= csP.w;
|
||||
//csP.z = abs( csP.z ); // this is still negative Z like for OpenGL
|
||||
|
||||
return csP.xyz;
|
||||
}
|
||||
|
||||
|
||||
float DistanceSquared( float2 a, float2 b )
|
||||
{
|
||||
a -= b;
|
||||
return dot( a, a );
|
||||
}
|
||||
|
||||
void Swap( inout float a, inout float b )
|
||||
{
|
||||
float t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
bool IntersectsDepthBuffer( float z, float minZ, float maxZ, float zThickness )
|
||||
{
|
||||
/*
|
||||
* Based on how far away from the camera the depth is,
|
||||
* adding a bit of extra thickness can help improve some
|
||||
* artifacts. Driving this value up too high can cause
|
||||
* artifacts of its own.
|
||||
*/
|
||||
const float strideZCutoff = 100.0 * METERS_TO_DOOM;
|
||||
|
||||
//float depthScale = min( 1.0, z * strideZCutoff );
|
||||
//z += zThickness + lerp( 0.0, 2.0, depthScale );
|
||||
|
||||
//return ( maxZ >= z ) && ( minZ - zThickness <= z );
|
||||
|
||||
// like original version with negative linear Z
|
||||
return ( maxZ >= z - zThickness ) && ( minZ <= z );
|
||||
}
|
||||
|
||||
// From the Efficient GPU Screen-Space Ray Tracing paper
|
||||
// By Morgan McGuire and Michael Mara at Williams College 2014
|
||||
// Released as open source under the BSD 2-Clause License
|
||||
// http://opensource.org/licenses/BSD-2-Clause
|
||||
|
||||
// Returns true if the ray hit something
|
||||
bool TraceScreenSpaceRay(
|
||||
// Camera-space ray origin, which must be within the view volume
|
||||
float3 rayStart,
|
||||
|
||||
// Unit length camera-space ray direction
|
||||
float3 rayDir,
|
||||
|
||||
// Camera space thickness to ascribe to each pixel in the depth buffer
|
||||
float zThickness,
|
||||
|
||||
// Stride samples trades quality for performance
|
||||
float _stride,
|
||||
|
||||
// Number between 0 and 1 for how far to bump the ray in stride units
|
||||
// to conceal banding artifacts. Not needed if stride == 1.
|
||||
float jitter,
|
||||
|
||||
// Maximum number of iterations. Higher gives better images but may be slow
|
||||
const float maxSteps,
|
||||
|
||||
// Maximum camera-space distance to trace before returning a miss
|
||||
const float maxDistance,
|
||||
|
||||
// Pixel coordinates of the first intersection with the scene
|
||||
out float2 hitPixel,
|
||||
|
||||
// Camera space location of the ray hit
|
||||
out float3 hitPoint,
|
||||
|
||||
out float3 rayDebug )
|
||||
{
|
||||
const float nearPlaneZ = 3.0;
|
||||
|
||||
// Clip to the near plane
|
||||
float rayLength = ( ( rayStart.z + rayDir.z * maxDistance ) < nearPlaneZ ) ?
|
||||
( nearPlaneZ - rayStart.z ) / rayDir.z : maxDistance;
|
||||
|
||||
//float rayLength = 10000;
|
||||
float4 rayEnd = float4( rayStart + rayDir * rayLength, 1.0 );
|
||||
|
||||
// Project into homogeneous clip space
|
||||
float4 ray4D = float4( rayStart, 1.0 );
|
||||
float4 H0;
|
||||
H0.x = dot4( ray4D, rpShadowMatrices[4] );
|
||||
H0.y = dot4( ray4D, rpShadowMatrices[5] );
|
||||
H0.z = dot4( ray4D, rpShadowMatrices[6] );
|
||||
H0.w = dot4( ray4D, rpShadowMatrices[7] );
|
||||
|
||||
float4 H1;
|
||||
H1.x = dot4( rayEnd, rpShadowMatrices[4] );
|
||||
H1.y = dot4( rayEnd, rpShadowMatrices[5] );
|
||||
H1.z = dot4( rayEnd, rpShadowMatrices[6] );
|
||||
H1.w = dot4( rayEnd, rpShadowMatrices[7] );
|
||||
|
||||
float k0 = 1.0f / H0.w;
|
||||
float k1 = 1.0f / H1.w;
|
||||
|
||||
// Switch the original points to values that interpolate linearly in 2D
|
||||
float3 Q0 = rayStart * k0;
|
||||
float3 Q1 = rayEnd.xyz * k1;
|
||||
|
||||
// Screen-space endpoints
|
||||
float2 P0 = H0.xy * k0;
|
||||
float2 P1 = H1.xy * k1;
|
||||
|
||||
// Initialize to off screen
|
||||
hitPixel = float2( -1.0, -1.0 );
|
||||
|
||||
// If the line is degenerate, make it cover at least one pixel
|
||||
// to avoid handling zero-pixel extent as a special case later
|
||||
P1 += ( DistanceSquared( P0, P1 ) < 0.0001 ) ? float2( 0.01, 0.01 ) : 0.0;
|
||||
float2 delta = P1 - P0;
|
||||
|
||||
// Permute so that the primary iteration is in x to collapse
|
||||
// all quadrant-specific DDA cases later
|
||||
bool permute = false;
|
||||
if( abs( delta.x ) < abs( delta.y ) )
|
||||
{
|
||||
// This is a more-vertical line
|
||||
permute = true;
|
||||
delta = delta.yx;
|
||||
P0 = P0.yx;
|
||||
P1 = P1.yx;
|
||||
}
|
||||
|
||||
// From now on, "x" is the primary iteration direction and "y" is the secondary one
|
||||
float stepDir = sign( delta.x );
|
||||
float invdx = stepDir / delta.x;
|
||||
float2 dP = float2( stepDir, delta.y * invdx );
|
||||
|
||||
// Track the derivatives of Q and k
|
||||
float3 dQ = ( Q1 - Q0 ) * invdx;
|
||||
float dk = ( k1 - k0 ) * invdx;
|
||||
|
||||
const float strideZCutoff = 100.0 * METERS_TO_DOOM;
|
||||
|
||||
// Scale derivatives by the desired pixel stride and then
|
||||
// offset the starting values by the jitter fraction
|
||||
//float strideScale = 1.0f - min( 1.0f, rayStart.z * strideZCutoff );
|
||||
//float stride = 1.0f + strideScale * _stride;
|
||||
float stride = _stride;
|
||||
dP *= stride;
|
||||
dQ *= stride;
|
||||
dk *= stride;
|
||||
|
||||
P0 += dP * jitter;
|
||||
Q0 += dQ * jitter;
|
||||
k0 += dk * jitter;
|
||||
|
||||
// Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, k from k0 to k1
|
||||
float3 Q = Q0;
|
||||
float k = k0;
|
||||
|
||||
// We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid
|
||||
// voxels. Because the depth at -1/2 for a given pixel will be the same as at
|
||||
// +1/2 for the previous iteration, we actually only have to compute one value
|
||||
// per iteration.
|
||||
float stepCount = 0.0;
|
||||
float prevZMaxEstimate = rayStart.z;
|
||||
float rayZMin = prevZMaxEstimate;
|
||||
float rayZMax = prevZMaxEstimate;
|
||||
float sceneZMax = rayZMax + 1.0 * METERS_TO_DOOM;
|
||||
|
||||
// P1.x is never modified after this point, so pre-scale it by
|
||||
// the step direction for a signed comparison
|
||||
float end = P1.x * stepDir;
|
||||
|
||||
// We only advance the z field of Q in the inner loop, since
|
||||
// Q.xy is never used until after the loop terminates.
|
||||
|
||||
for( float2 P = P0;
|
||||
( ( P.x * stepDir ) <= end ) &&
|
||||
( stepCount < maxSteps ) &&
|
||||
//!IntersectsDepthBuffer( sceneZMax, rayZMin, rayZMax, zThickness ) &&
|
||||
( ( rayZMax < sceneZMax - zThickness ) || ( rayZMin > sceneZMax ) ) &&
|
||||
( sceneZMax != 0.0f );
|
||||
P += dP, Q.z += dQ.z, k += dk, stepCount += 1.0 )
|
||||
{
|
||||
hitPixel = permute ? P.yx : P;
|
||||
|
||||
// The depth range that the ray covers within this loop
|
||||
// iteration. Assume that the ray is moving in increasing z
|
||||
// and swap if backwards. Because one end of the interval is
|
||||
// shared between adjacent iterations, we track the previous
|
||||
// value and then swap as needed to ensure correct ordering
|
||||
rayZMin = prevZMaxEstimate;
|
||||
|
||||
// Compute the value at 1/2 pixel into the future
|
||||
rayZMax = ( dQ.z * 0.5 + Q.z ) / ( dk * 0.5 + k );
|
||||
prevZMaxEstimate = rayZMax;
|
||||
|
||||
if( rayZMin > rayZMax )
|
||||
{
|
||||
Swap( rayZMin, rayZMax );
|
||||
}
|
||||
|
||||
// You may need hitPixel.y = depthBufferSize.y - hitPixel.y; here if your vertical axis
|
||||
// is different than ours in screen space
|
||||
//hitPixel.x = rpWindowCoord.z - hitPixel.x;
|
||||
//hitPixel.y = rpWindowCoord.w - hitPixel.y;
|
||||
|
||||
sceneZMax = ReconstructPositionCS( hitPixel ).z;
|
||||
}
|
||||
|
||||
// Advance Q based on the number of steps
|
||||
Q.xy += dQ.xy * stepCount;
|
||||
hitPoint = Q * ( 1.0f / k );
|
||||
|
||||
//rayDebug.xyz = _float3( stepCount );
|
||||
|
||||
return IntersectsDepthBuffer( sceneZMax, rayZMin, rayZMax, zThickness );
|
||||
}
|
||||
|
||||
|
||||
float2 GetSampleVector( float3 reflectionVector )
|
||||
{
|
||||
float2 normalizedOctCoord = octEncode( reflectionVector );
|
||||
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + _float2( 1.0 ) ) * 0.5;
|
||||
|
||||
return normalizedOctCoordZeroOne;
|
||||
}
|
||||
|
||||
void main( PS_IN fragment, out PS_OUT result )
|
||||
{
|
||||
float4 bump = t_NormalMap.Sample( s_Material, fragment.texcoord0 ) * 2.0f - 1.0f;
|
||||
|
||||
// RB begin
|
||||
float3 localNormal;
|
||||
#if defined(USE_NORMAL_FMT_RGB8)
|
||||
localNormal = float3( bump.rg, 0.0f );
|
||||
#else
|
||||
localNormal = float3( bump.wy, 0.0f );
|
||||
#endif
|
||||
// RB end
|
||||
localNormal.z = sqrt( 1.0f - dot3( localNormal, localNormal ) );
|
||||
|
||||
float3 globalNormal;
|
||||
|
||||
globalNormal.x = dot3( localNormal, fragment.texcoord2 );
|
||||
globalNormal.y = dot3( localNormal, fragment.texcoord3 );
|
||||
globalNormal.z = dot3( localNormal, fragment.texcoord4 );
|
||||
|
||||
float3 screenNormalWS = ( ( 2.0 * t_ScreenNormals.Sample( s_LinearClamp, fragment.position.xy * rpWindowCoord.xy ).rgb ) - 1.0 );
|
||||
|
||||
// https://blog.selfshadow.com/publications/blending-in-detail/
|
||||
|
||||
// UDN blending
|
||||
//globalNormal = normalize( float3( screenNormalWS.xy + globalNormal.xy, screenNormalWS.z ) );
|
||||
|
||||
// Whiteout blending
|
||||
globalNormal = normalize( float3( screenNormalWS.xy + globalNormal.xy, screenNormalWS.z * globalNormal.z ) );
|
||||
|
||||
|
||||
float3 globalPosition = fragment.texcoord5.xyz;
|
||||
|
||||
float3 globalView = normalize( globalPosition - rpGlobalEyePos.xyz );
|
||||
|
||||
float3 reflectionVector = reflect( globalView, globalNormal );
|
||||
reflectionVector = normalize( reflectionVector );
|
||||
|
||||
float2 octCoord0 = GetSampleVector( reflectionVector );
|
||||
float2 octCoord1 = octCoord0;
|
||||
float2 octCoord2 = octCoord0;
|
||||
|
||||
float3 rayStart = globalPosition;
|
||||
|
||||
#if 1
|
||||
// parallax box correction using portal area bounds
|
||||
float hitScale = 0.0;
|
||||
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;
|
||||
|
||||
// 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
|
||||
#if 1
|
||||
reflectionVector = hitPoint - rpWobbleSkyZ.xyz;
|
||||
octCoord0 = octCoord1 = octCoord2 = GetSampleVector( reflectionVector );
|
||||
#else
|
||||
// this should look better but only works in the case all 3 probes are in this area bbox
|
||||
octCoord0 = GetSampleVector( hitPoint - rpTexGen0S.xyz );
|
||||
octCoord1 = GetSampleVector( hitPoint - rpTexGen0T.xyz );
|
||||
octCoord2 = GetSampleVector( hitPoint - rpTexGen0Q.xyz );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
const float mip = 0;
|
||||
float3 radiance = t_RadianceCubeMap1.SampleLevel( s_LinearClamp, octCoord0, mip ).rgb * rpLocalLightOrigin.x;
|
||||
radiance += t_RadianceCubeMap2.SampleLevel( s_LinearClamp, octCoord1, mip ).rgb * rpLocalLightOrigin.y;
|
||||
radiance += t_RadianceCubeMap3.SampleLevel( s_LinearClamp, octCoord2, mip ).rgb * rpLocalLightOrigin.z;
|
||||
|
||||
#if 1
|
||||
// Screen Space Reflections
|
||||
|
||||
float3 rayDir;
|
||||
|
||||
float3 viewNormal;
|
||||
|
||||
// TODO this should be rpViewMatrixX
|
||||
viewNormal.x = dot3( rpModelViewMatrixX, globalNormal );
|
||||
viewNormal.y = dot3( rpModelViewMatrixY, globalNormal );
|
||||
viewNormal.z = dot3( rpModelViewMatrixZ, globalNormal );
|
||||
|
||||
rayStart = ReconstructPositionCS( fragment.position.xy );
|
||||
|
||||
float3 V;
|
||||
V = normalize( rayStart );
|
||||
reflectionVector = reflect( V, viewNormal );
|
||||
rayDir = normalize( reflectionVector );
|
||||
|
||||
// use forward vector instead of V to avoid bending
|
||||
float vDotR = ( dot3( float3( 0, 0, 1 ), reflectionVector ) );
|
||||
|
||||
const float maxSteps = rpJitterTexScale.x;
|
||||
|
||||
float2 hitPixel;
|
||||
float3 hitPoint;
|
||||
float3 rayDebug = float3( 0, 0, 1 );
|
||||
bool intersection = false;
|
||||
|
||||
float jitter = 1.0;
|
||||
//jitter = ( int( fragment.position.x + fragment.position.y) & 1 ) * 0.5; // like in the paper but sucks
|
||||
jitter = InterleavedGradientNoise( fragment.position.xy );
|
||||
//jitter = InterleavedGradientNoiseAnim( fragment.position.xy, rpJitterTexOffset.w );
|
||||
|
||||
jitter = lerp( 1.0, jitter, rpGlobalLightOrigin.w );
|
||||
|
||||
// using the same jitter on probe fallback to make it seamless
|
||||
// looks kinda bad because on close ups you don't want to see the noise
|
||||
//radiance *= jitter;
|
||||
|
||||
if( vDotR <= 0 )
|
||||
{
|
||||
intersection = TraceScreenSpaceRay(
|
||||
rayStart,
|
||||
rayDir,
|
||||
rpGlobalLightOrigin.z, // zThickness 0.5
|
||||
rpGlobalLightOrigin.x, // stride
|
||||
jitter, // jitter
|
||||
maxSteps, // max steps
|
||||
rpGlobalLightOrigin.y * METERS_TO_DOOM, // max Distance
|
||||
hitPixel,
|
||||
hitPoint,
|
||||
rayDebug );
|
||||
}
|
||||
|
||||
float2 delta = ( hitPixel * rpWindowCoord.xy ) - ( fragment.position.xy * rpWindowCoord.xy );
|
||||
float deltaLen = length( delta );
|
||||
|
||||
if( ( hitPixel.x > rpWindowCoord.z || hitPixel.x < 0.0 || hitPixel.y > rpWindowCoord.w || hitPixel.y < 0.0 ) )
|
||||
{
|
||||
intersection = false;
|
||||
}
|
||||
|
||||
if( intersection )
|
||||
{
|
||||
radiance = float3( 0, 1, 0 );
|
||||
radiance = t_ScreenColor.Sample( s_LinearClamp, hitPixel * rpWindowCoord.xy ).rgb;
|
||||
|
||||
//radiance = float3( delta, 0 );
|
||||
//radiance = float3( 0, deltaLen, 0 );
|
||||
//radiance = rayDebug / maxSteps;
|
||||
|
||||
//radiance = float3( hitPixel * rpWindowCoord.xy, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
if( vDotR > 0.0 )
|
||||
{
|
||||
radiance = float3( 1, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
radiance = float3( 0, 0, 1 );
|
||||
}
|
||||
*/
|
||||
//radiance = rayDebug;
|
||||
//discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
// give it a red blood tint
|
||||
//radiance *= float3( 0.5, 0.25, 0.25 );
|
||||
|
||||
// make this really dark although it is already in linear RGB
|
||||
radiance = sRGBToLinearRGB( radiance.xyz );
|
||||
|
||||
result.color = float4( radiance, 1.0 ) * fragment.color;
|
||||
}
|
179
neo/shaders/builtin/legacy/bumpyenvironment2.vs.hlsl
Normal file
179
neo/shaders/builtin/legacy/bumpyenvironment2.vs.hlsl
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2024 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 "global_inc.hlsl"
|
||||
|
||||
// *INDENT-OFF*
|
||||
#if USE_GPU_SKINNING
|
||||
StructuredBuffer<float4> matrices : register(t11);
|
||||
#endif
|
||||
|
||||
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 : SV_Position;
|
||||
float2 texcoord0 : TEXCOORD0_centroid;
|
||||
float3 texcoord1 : TEXCOORD1_centroid;
|
||||
float3 texcoord2 : TEXCOORD2_centroid;
|
||||
float3 texcoord3 : TEXCOORD3_centroid;
|
||||
float3 texcoord4 : TEXCOORD4_centroid;
|
||||
float4 texcoord5 : TEXCOORD5_centroid;
|
||||
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 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 );
|
||||
|
||||
result.position.xyz = psxVertexJitter( result.position );
|
||||
|
||||
result.texcoord0 = vertex.texcoord.xy;
|
||||
|
||||
// PSX affine texture mapping
|
||||
#if 0
|
||||
if( rpPSXDistortions.z > 0.0 )
|
||||
{
|
||||
float distance = length( rpLocalViewOrigin - modelPosition );
|
||||
float warp = psxAffineWarp( distance );
|
||||
|
||||
result.texcoord0.z = warp;
|
||||
result.texcoord0.xy *= warp;
|
||||
result.texcoord1.xy *= warp;
|
||||
result.texcoord2.xy *= warp;
|
||||
}
|
||||
#endif
|
||||
|
||||
float4 toEye = rpLocalViewOrigin - modelPosition;
|
||||
|
||||
result.texcoord1.x = dot3( toEye, rpModelMatrixX );
|
||||
result.texcoord1.y = dot3( toEye, rpModelMatrixY );
|
||||
result.texcoord1.z = dot3( toEye, rpModelMatrixZ );
|
||||
|
||||
// rotate from tangent space into world space
|
||||
result.texcoord2.x = dot3( tangent, rpModelMatrixX );
|
||||
result.texcoord3.x = dot3( tangent, rpModelMatrixY );
|
||||
result.texcoord4.x = dot3( tangent, rpModelMatrixZ );
|
||||
|
||||
result.texcoord2.y = dot3( bitangent, rpModelMatrixX );
|
||||
result.texcoord3.y = dot3( bitangent, rpModelMatrixY );
|
||||
result.texcoord4.y = dot3( bitangent, rpModelMatrixZ );
|
||||
|
||||
result.texcoord2.z = dot3( normal, rpModelMatrixX );
|
||||
result.texcoord3.z = dot3( normal, rpModelMatrixY );
|
||||
result.texcoord4.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.texcoord5 = worldPosition;
|
||||
|
||||
result.color = rpColor;
|
||||
}
|
|
@ -69,61 +69,7 @@ struct PS_OUT
|
|||
// *INDENT-ON*
|
||||
|
||||
|
||||
// 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 )
|
||||
{
|
||||
|
@ -223,11 +169,20 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );
|
||||
float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic );
|
||||
|
||||
#else
|
||||
|
||||
#if KENNY_PBR
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor;
|
||||
float roughness;
|
||||
|
||||
PBRFromSpecmap( specMapSRGB.rgb, specularColor, roughness );
|
||||
#else
|
||||
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor = specMap.rgb;
|
||||
#endif
|
||||
|
||||
#if defined( DEBUG_PBR )
|
||||
diffuseColor = float3( 0.0, 0.0, 0.0 );
|
||||
|
|
|
@ -69,61 +69,6 @@ struct PS_OUT
|
|||
// *INDENT-ON*
|
||||
|
||||
|
||||
// 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] );
|
||||
}
|
||||
|
||||
|
||||
float2 OctTexCoord( float3 worldDir )
|
||||
|
@ -243,11 +188,20 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float3 kS = Fresnel_SchlickRoughness( specularColor, vDotN, roughness );
|
||||
float3 kD = ( float3( 1.0, 1.0, 1.0 ) - kS ) * ( 1.0 - metallic );
|
||||
|
||||
#else
|
||||
|
||||
#if KENNY_PBR
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor;
|
||||
float roughness;
|
||||
|
||||
PBRFromSpecmap( specMapSRGB.rgb, specularColor, roughness );
|
||||
#else
|
||||
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor = specMap.rgb;
|
||||
#endif
|
||||
|
||||
#if defined( DEBUG_PBR )
|
||||
diffuseColor = float3( 0.0, 0.0, 0.0 );
|
||||
|
|
|
@ -116,9 +116,9 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float hdotN = clamp( dot3( halfAngleVector, localNormal ), 0.0, 1.0 );
|
||||
|
||||
#if USE_PBR
|
||||
// RB: roughness 0 somehow is not shiny so we clamp it
|
||||
float roughness = max( 0.05, specMapSRGB.r );
|
||||
const float metallic = specMapSRGB.g;
|
||||
const float roughness = specMapSRGB.r;
|
||||
const float 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)
|
||||
|
@ -131,6 +131,13 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
|
||||
float3 diffuseColor = baseColor * ( 1.0 - metallic );
|
||||
float3 specularColor = lerp( dielectricColor, baseColor, metallic );
|
||||
|
||||
#elif KENNY_PBR
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor;
|
||||
float roughness;
|
||||
|
||||
PBRFromSpecmap( specMapSRGB.rgb, specularColor, roughness );
|
||||
#else
|
||||
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
|
||||
|
@ -139,8 +146,10 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
#endif
|
||||
|
||||
|
||||
// RB: compensate r_lightScale 3 and the division of Pi
|
||||
// RB FIXME or not: compensate r_lightScale 3 and the division of Pi
|
||||
//lambert *= 1.3;
|
||||
// see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
||||
//lambert /= PI;
|
||||
|
||||
// rpDiffuseModifier contains light color multiplier
|
||||
float3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );
|
||||
|
@ -149,8 +158,8 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float vdotH = clamp( dot3( viewVector, halfAngleVector ), 0.0, 1.0 );
|
||||
float ldotH = clamp( dot3( lightVector, halfAngleVector ), 0.0, 1.0 );
|
||||
|
||||
// compensate r_lightScale 3 * 2
|
||||
float3 reflectColor = specularColor * rpSpecularModifier.rgb * 1.0;// * 0.5;
|
||||
// keep in mind this is r_lightScale 3 * 2
|
||||
float3 reflectColor = specularColor * rpSpecularModifier.rgb;
|
||||
|
||||
// cheap approximation by ARM with only one division
|
||||
// http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
|
||||
|
@ -162,17 +171,19 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
// disney GGX
|
||||
float D = ( hdotN * hdotN ) * ( rrrr - 1.0 ) + 1.0;
|
||||
float VFapprox = ( ldotH * ldotH ) * ( roughness + 0.5 );
|
||||
|
||||
#if KENNY_PBR
|
||||
float3 specularLight = ( rrrr / ( 4.0 * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
#else
|
||||
float3 specularLight = ( rrrr / ( 4.0 * PI * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
//specularLight = float3( 0.0 );
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
result.color = float4( _float3( VFapprox ), 1.0 );
|
||||
return;
|
||||
#endif
|
||||
|
||||
// see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
||||
//lambert /= PI;
|
||||
|
||||
//float3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz;
|
||||
float3 diffuseLight = diffuseColor * lambert * ( rpDiffuseModifier.xyz );
|
||||
|
||||
|
|
|
@ -474,9 +474,9 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float hdotN = clamp( dot3( halfAngleVector, localNormal ), 0.0, 1.0 );
|
||||
|
||||
#if USE_PBR
|
||||
// RB: roughness 0 somehow is not shiny so we clamp it
|
||||
float roughness = max( 0.05, specMapSRGB.r );
|
||||
const float metallic = specMapSRGB.g;
|
||||
const float roughness = specMapSRGB.r;
|
||||
const float 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)
|
||||
|
@ -489,16 +489,34 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
|
||||
float3 diffuseColor = baseColor * ( 1.0 - metallic );
|
||||
float3 specularColor = lerp( dielectricColor, baseColor, metallic );
|
||||
|
||||
#elif KENNY_PBR
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor;
|
||||
float roughness;
|
||||
|
||||
PBRFromSpecmap( specMapSRGB.rgb, specularColor, roughness );
|
||||
#else
|
||||
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// specular AA - https://yusuketokuyoshi.com/papers/2021/Tokuyoshi2021SAA.pdf
|
||||
|
||||
// RB: compensate r_lightScale 3 and the division of Pi
|
||||
//roughness = IsotropicNDFFiltering( localNormal, roughness * roughness );
|
||||
|
||||
float r2 = roughness * roughness;
|
||||
roughness = AxisAlignedNDFFiltering( halfAngleVector, float2( r2, r2 ) ).x;
|
||||
#endif
|
||||
|
||||
|
||||
// RB FIXME or not: compensate r_lightScale 3 and the division of Pi
|
||||
//lambert *= 1.3;
|
||||
// see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
||||
//lambert /= PI;
|
||||
|
||||
// rpDiffuseModifier contains light color multiplier
|
||||
float3 lightColor = sRGBToLinearRGB( lightProj.xyz * lightFalloff.xyz );
|
||||
|
@ -507,8 +525,8 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float vdotH = clamp( dot3( viewVector, halfAngleVector ), 0.0, 1.0 );
|
||||
float ldotH = clamp( dot3( lightVector, halfAngleVector ), 0.0, 1.0 );
|
||||
|
||||
// compensate r_lightScale 3 * 2
|
||||
float3 reflectColor = specularColor * rpSpecularModifier.rgb * 1.0;// * 0.5;
|
||||
// keep in mind this is r_lightScale 3 * 2
|
||||
float3 reflectColor = specularColor * rpSpecularModifier.rgb;
|
||||
|
||||
// cheap approximation by ARM with only one division
|
||||
// http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
|
||||
|
@ -520,17 +538,25 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
// disney GGX
|
||||
float D = ( hdotN * hdotN ) * ( rrrr - 1.0 ) + 1.0;
|
||||
float VFapprox = ( ldotH * ldotH ) * ( roughness + 0.5 );
|
||||
|
||||
#if KENNY_PBR
|
||||
// specular cook-torrance brdf (visibility, geo and denom in one)
|
||||
//float D = Distribution_GGX_Disney( hdotN, rr );
|
||||
//float Vis = Visibility_Schlick( vdotN, lambert, rr );
|
||||
//float3 F = Fresnel_Schlick( reflectColor, vdotH );
|
||||
//float3 specularLight = D * Vis * F;
|
||||
|
||||
float3 specularLight = ( rrrr / ( 4.0 * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
#else
|
||||
float3 specularLight = ( rrrr / ( 4.0 * PI * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
//specularLight = float3( 0.0 );
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
result.color = float4( _float3( VFapprox ), 1.0 );
|
||||
return;
|
||||
#endif
|
||||
|
||||
// see http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
||||
//lambert /= PI;
|
||||
|
||||
//float3 diffuseColor = mix( diffuseMap, F0, metal ) * rpDiffuseModifier.xyz;
|
||||
float3 diffuseLight = diffuseColor * lambert * ( rpDiffuseModifier.xyz );
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2013-2020 Robert Beckebans
|
||||
Copyright (C) 2013-2024 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -492,6 +492,10 @@ static float2 vposToScreenPosTexCoord( float2 vpos )
|
|||
return vpos.xy * rpWindowCoord.xy;
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// PSX rendering
|
||||
// ----------------------
|
||||
|
||||
// a very useful resource with many examples about the PS1 look:
|
||||
// https://www.david-colson.com/2021/11/30/ps1-style-renderer.html
|
||||
|
||||
|
@ -532,6 +536,12 @@ static float psxAffineWarp( float distance )
|
|||
#define BRANCH
|
||||
#define IFANY
|
||||
|
||||
|
||||
// ----------------------
|
||||
// Noise tricks
|
||||
// ----------------------
|
||||
|
||||
|
||||
//note: works for structured patterns too
|
||||
// [0;1[
|
||||
float RemapNoiseTriErp( const float v )
|
||||
|
@ -604,3 +614,63 @@ float DitherArray8x8Anim( float2 pos, int frameIndexMod4 )
|
|||
}
|
||||
|
||||
|
||||
// ----------------------
|
||||
// COLLISION DETECTION
|
||||
// ----------------------
|
||||
|
||||
// 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] );
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ builtin/legacy/environment.vs.hlsl -T vs -D USE_GPU_SKINNING={0,1}
|
|||
builtin/legacy/environment.ps.hlsl -T ps -D USE_GPU_SKINNING={0,1}
|
||||
builtin/legacy/bumpyenvironment.vs.hlsl -T vs -D USE_GPU_SKINNING={0,1}
|
||||
builtin/legacy/bumpyenvironment.ps.hlsl -T ps -D USE_GPU_SKINNING={0,1}
|
||||
builtin/legacy/bumpyenvironment2.vs.hlsl -T vs -D USE_GPU_SKINNING={0,1}
|
||||
builtin/legacy/bumpyenvironment2.ps.hlsl -T ps -D USE_GPU_SKINNING={0,1}
|
||||
builtin/legacy/skybox.vs.hlsl -T vs
|
||||
builtin/legacy/skybox.ps.hlsl -T ps
|
||||
builtin/legacy/wobblesky.vs.hlsl -T vs
|
||||
|
|
Loading…
Reference in a new issue