From a51b82b23f2ca5b8cd97d0da3d8098a5d991ebaf Mon Sep 17 00:00:00 2001 From: kirides <13602143+kirides@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:32:56 +0200 Subject: [PATCH 1/5] Draw sky after geometry, to make use of early z --- D3D11Engine/D3D11GraphicsEngine.cpp | 184 +++++++++++++++------- D3D11Engine/D3D11ShaderManager.cpp | 8 + D3D11Engine/D3D7/MyDirect3DDevice7.h | 48 ++++-- D3D11Engine/GothicGraphicsState.h | 10 +- D3D11Engine/ShaderIDs.h | 2 + D3D11Engine/Shaders/VS_TransformedEx.hlsl | 9 ++ D3D11Engine/Shaders/VS_XYZRHW_DIF_T1.hlsl | 8 + D3D11Engine/zCMaterial.h | 39 +++-- D3D11Engine/zTypes.h | 13 +- 9 files changed, 234 insertions(+), 87 deletions(-) diff --git a/D3D11Engine/D3D11GraphicsEngine.cpp b/D3D11Engine/D3D11GraphicsEngine.cpp index f95549d5..bc32f449 100644 --- a/D3D11Engine/D3D11GraphicsEngine.cpp +++ b/D3D11Engine/D3D11GraphicsEngine.cpp @@ -3605,66 +3605,97 @@ XRESULT D3D11GraphicsEngine::UnbindTexture( int slot ) { /** Recreates the renderstates */ XRESULT D3D11GraphicsEngine::UpdateRenderStates() { - if ( Engine::GAPI->GetRendererState().BlendState.StateDirty && - Engine::GAPI->GetRendererState().BlendState.Hash != FFBlendStateHash ) { + + auto& states = Engine::GAPI->GetRendererState(); + auto& blendState = states.BlendState; + auto& rasterState = states.RasterizerState; + auto& depthState = states.DepthState; + + blendState.HashThis( reinterpret_cast(&blendState), blendState.StructSize ); + rasterState.HashThis( reinterpret_cast(&rasterState), rasterState.StructSize ); + depthState.HashThis( reinterpret_cast(&depthState), depthState.StructSize ); + + if ( blendState.StateDirty && + blendState.Hash != FFBlendStateHash ) { D3D11BlendStateInfo* state = static_cast - (GothicStateCache::s_BlendStateMap[Engine::GAPI->GetRendererState().BlendState]); + (GothicStateCache::s_BlendStateMap[blendState]); if ( !state ) { // Create new state state = - new D3D11BlendStateInfo( Engine::GAPI->GetRendererState().BlendState ); + new D3D11BlendStateInfo( blendState ); - GothicStateCache::s_BlendStateMap[Engine::GAPI->GetRendererState().BlendState] = state; + GothicStateCache::s_BlendStateMap[blendState] = state; } FFBlendState = state->State.Get(); - FFBlendStateHash = Engine::GAPI->GetRendererState().BlendState.Hash; + FFBlendStateHash = blendState.Hash; - Engine::GAPI->GetRendererState().BlendState.StateDirty = false; + blendState.StateDirty = false; GetContext()->OMSetBlendState( FFBlendState.Get(), float4( 0, 0, 0, 0 ).toPtr(), 0xFFFFFFFF ); } - if ( Engine::GAPI->GetRendererState().RasterizerState.StateDirty && - Engine::GAPI->GetRendererState().RasterizerState.Hash != + if ( rasterState.StateDirty && + rasterState.Hash != FFRasterizerStateHash ) { D3D11RasterizerStateInfo* state = static_cast - (GothicStateCache::s_RasterizerStateMap[Engine::GAPI->GetRendererState().RasterizerState]); + (GothicStateCache::s_RasterizerStateMap[rasterState]); if ( !state ) { // Create new state state = new D3D11RasterizerStateInfo( - Engine::GAPI->GetRendererState().RasterizerState ); + rasterState ); - GothicStateCache::s_RasterizerStateMap[Engine::GAPI->GetRendererState().RasterizerState] = state; + GothicStateCache::s_RasterizerStateMap[rasterState] = state; } FFRasterizerState = state->State.Get(); - FFRasterizerStateHash = Engine::GAPI->GetRendererState().RasterizerState.Hash; + FFRasterizerStateHash = rasterState.Hash; - Engine::GAPI->GetRendererState().RasterizerState.StateDirty = false; + rasterState.StateDirty = false; GetContext()->RSSetState( FFRasterizerState.Get() ); } - if ( Engine::GAPI->GetRendererState().DepthState.StateDirty && - Engine::GAPI->GetRendererState().DepthState.Hash != + if ( depthState.StateDirty && + depthState.Hash != FFDepthStencilStateHash ) { + D3D11DepthBufferState* state = static_cast - (GothicStateCache::s_DepthBufferMap[Engine::GAPI->GetRendererState().DepthState]); + (GothicStateCache::s_DepthBufferMap[depthState]); if ( !state ) { // Create new state state = new D3D11DepthBufferState( - Engine::GAPI->GetRendererState().DepthState ); + depthState ); + + GothicStateCache::s_DepthBufferMap[depthState] = state; +#ifdef DEBUG_D3D11 + std::stringstream ss; + ss << (state->Values.DepthBufferEnabled ? "E1" : "E0") << "|"; + ss << (state->Values.DepthWriteEnabled ? "W1" : "W0") << "|"; + + static const char* strs[9]{ + "NONE", + "NEVER", + "LESS", + "EQUAL", + "LESS_EQUAL", + "GREATER", + "NOT_EQUAL", + "GREATER_EQUAL", + "ALWAYS", + }; + ss << strs[state->Values.DepthBufferCompareFunc]; - GothicStateCache::s_DepthBufferMap[Engine::GAPI->GetRendererState().DepthState] = state; + SetDebugName( state->State.Get(), ss.str() ); +#endif } FFDepthStencilState = state->State.Get(); - FFDepthStencilStateHash = Engine::GAPI->GetRendererState().DepthState.Hash; + FFDepthStencilStateHash = depthState.Hash; - Engine::GAPI->GetRendererState().DepthState.StateDirty = false; + depthState.StateDirty = false; GetContext()->OMSetDepthStencilState( FFDepthStencilState.Get(), 0 ); } @@ -3831,32 +3862,32 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() { GetContext()->ClearRenderTargetView( graph.GetPhysicalTexture( colorResource )->GetRenderTargetView().Get(), reinterpret_cast(&fogColor) ); }; }); - + + RGResourceHandle normalsResource; + RGResourceHandle specularResource; + RGResourceHandle reactiveMaskResource; + // Re-evaluate active renderer each frame (allows runtime switching) + SelectActiveRenderer(); + ActiveSceneRenderer->AddGeometryPasses( graph, *this, + colorResource, velocityBufferHandle, backBufferHandle, + normalsResource, specularResource, reactiveMaskResource ); + if ( rendererState.RendererSettings.DrawSky ) { - graph.AddPass( RG_PASS_NAME("Draw Sky"), [&]( RGBuilder& builder, RenderPass& pass ) { + graph.AddPass( RG_PASS_NAME( "Draw Sky" ), [&]( RGBuilder& builder, RenderPass& pass ) { //// Setup / Declare //RGTextureDesc albedoDesc{ 1920, 1080, 28 /* DXGI_FORMAT_R8G8B8A8_UNORM */, "Albedo" }; //albedoTarget = builder.CreateTexture( albedoDesc ); builder.Write( colorResource ); - pass.m_executeCallback = [this, colorResource](const RenderGraph& graph)->void { + pass.m_executeCallback = [this, colorResource]( const RenderGraph& graph )->void { TracyD3D11ZoneCGX( "D3D11GraphicsEngine::Draw Sky" ); // Draw back of the sky if outdoor - GetContext()->OMSetRenderTargets( 1, graph.GetPhysicalTexture( colorResource )->GetRenderTargetView().GetAddressOf(), nullptr ); - + GetContext()->OMSetRenderTargets( 1, graph.GetPhysicalTexture( colorResource )->GetRenderTargetView().GetAddressOf(), GetDepthBuffer()->GetDepthStencilView().Get() ); + DrawSky(); }; - }); + } ); } - - RGResourceHandle normalsResource; - RGResourceHandle specularResource; - RGResourceHandle reactiveMaskResource; - // Re-evaluate active renderer each frame (allows runtime switching) - SelectActiveRenderer(); - ActiveSceneRenderer->AddGeometryPasses( graph, *this, - colorResource, velocityBufferHandle, backBufferHandle, - normalsResource, specularResource, reactiveMaskResource ); graph.AddPass( RG_PASS_NAME("Draw ParticleFX #1"), [&]( RGBuilder& builder, RenderPass& pass ) { // Setup / Declare @@ -4629,11 +4660,29 @@ XRESULT D3D11GraphicsEngine::DrawMeshInfoListAlphablended( // Check for alphablending on world mesh if ( lastAlphaFunc != alphaFunc ) { - if ( alphaFunc == zMAT_ALPHA_FUNC_BLEND ) + switch ( alphaFunc ) { + case zMAT_ALPHA_FUNC_BLEND: + case zMAT_ALPHA_FUNC_BLEND_TEST: Engine::GAPI->GetRendererState().BlendState.SetAlphaBlending(); + break; - if ( alphaFunc == zMAT_ALPHA_FUNC_ADD ) + case zMAT_ALPHA_FUNC_ADD: Engine::GAPI->GetRendererState().BlendState.SetAdditiveBlending(); + break; + + case zMAT_ALPHA_FUNC_MUL: + Engine::GAPI->GetRendererState().BlendState.SetModulateBlending(); + break; + + case zMAT_ALPHA_FUNC_MUL2: + Engine::GAPI->GetRendererState().BlendState.SetModulate2Blending(); + break; + + default: + auto _wtf = 1; + break; + // continue; + } Engine::GAPI->GetRendererState().BlendState.SetDirty(); @@ -7581,9 +7630,23 @@ XRESULT D3D11GraphicsEngine::DrawSky() { GSky* sky = Engine::GAPI->GetSky(); sky->RenderSky(); - if ( !Engine::GAPI->GetRendererState().RendererSettings.AtmosphericScattering ) { - Engine::GAPI->GetRendererState().DepthState.DepthWriteEnabled = false; - Engine::GAPI->GetRendererState().DepthState.SetDirty(); + auto& rendererState = Engine::GAPI->GetRendererState(); + if ( !rendererState.RendererSettings.AtmosphericScattering ) { + // for engine sky to work with z-buffer after Geometry, we need to override Z-buffer usage and set custom TransformXYZRHW to always set max Z + auto oldStage = rendererState.RendererInfo.RenderStage; + rendererState.RendererInfo.RenderStage = STAGE_DRAW_SKY; + + rendererState.DepthState.DepthBufferEnabled = true; + + // Disable depth-writes so the sky always stays at max distance in the + rendererState.DepthState.DepthWriteEnabled = false; + rendererState.DepthState.DepthBufferCompareFunc = GothicDepthBufferStateInfo::CF_COMPARISON_GREATER_EQUAL; + rendererState.DepthState.SetDirty(); + + + rendererState.RasterizerState.SetDefault(); + rendererState.RasterizerState.CullMode = GothicRasterizerStateInfo::CM_CULL_BACK; + rendererState.RasterizerState.SetDirty(); UpdateRenderStates(); #if defined(BUILD_GOTHIC_1_08k) && !defined(BUILD_1_12F) @@ -7598,8 +7661,10 @@ XRESULT D3D11GraphicsEngine::DrawSky() { ->RenderSkyPre(); #endif Engine::GAPI->SetFarPlane( - Engine::GAPI->GetRendererState().RendererSettings.SectionDrawRadius * + rendererState.RendererSettings.SectionDrawRadius * WORLD_SECTION_SIZE ); + + rendererState.RendererInfo.RenderStage = oldStage; return XR_SUCCESS; } // Create a rotaion only view-matrix @@ -7638,52 +7703,55 @@ XRESULT D3D11GraphicsEngine::DrawSky() { .Update(&cbi) .Bind(); - Engine::GAPI->GetRendererState().BlendState.SetDefault(); - Engine::GAPI->GetRendererState().BlendState.BlendEnabled = true; + rendererState.BlendState.SetDefault(); + rendererState.BlendState.BlendEnabled = true; - Engine::GAPI->GetRendererState().DepthState.SetDefault(); + rendererState.DepthState.SetDefault(); // Allow z-testing - Engine::GAPI->GetRendererState().DepthState.DepthBufferEnabled = true; + rendererState.DepthState.DepthBufferEnabled = true; // Disable depth-writes so the sky always stays at max distance in the // DepthBuffer - Engine::GAPI->GetRendererState().DepthState.DepthWriteEnabled = false; + rendererState.DepthState.DepthWriteEnabled = false; + rendererState.DepthState.DepthBufferCompareFunc = GothicDepthBufferStateInfo::CF_COMPARISON_GREATER_EQUAL; - Engine::GAPI->GetRendererState().RasterizerState.SetDefault(); - Engine::GAPI->GetRendererState().DepthState.SetDirty(); - Engine::GAPI->GetRendererState().BlendState.SetDirty(); + rendererState.RasterizerState.SetDefault(); + rendererState.DepthState.SetDirty(); + rendererState.BlendState.SetDirty(); - Engine::GAPI->GetRendererState().RasterizerState.CullMode = GothicRasterizerStateInfo::CM_CULL_BACK; - Engine::GAPI->GetRendererState().RasterizerState.SetDirty(); + rendererState.RasterizerState.CullMode = GothicRasterizerStateInfo::CM_CULL_BACK; + rendererState.RasterizerState.SetDirty(); SetupVS_ExMeshDrawCall(); SetupVS_ExConstantBuffer(); + ID3D11ShaderResourceView* srvs[2]{}; // Apply sky texture D3D11Texture* cloudsTex = Engine::GAPI->GetSky()->GetCloudTexture(); if ( cloudsTex ) { - cloudsTex->BindToPixelShader( 0 ); + srvs[0] = cloudsTex->GetShaderResourceView().Get(); } D3D11Texture* nightTex = Engine::GAPI->GetSky()->GetNightTexture(); if ( nightTex ) { - nightTex->BindToPixelShader( 1 ); + srvs[1] = nightTex->GetShaderResourceView().Get(); } + GetContext()->PSSetShaderResources( 0, std::size( srvs ), srvs); if ( sky->GetSkyDome() ) sky->GetSkyDome()->DrawMesh(); #if defined(BUILD_GOTHIC_1_08k) && !defined(BUILD_1_12F) { SetDefaultStates(); - Engine::GAPI->GetRendererState().DepthState.DepthWriteEnabled = false; - Engine::GAPI->GetRendererState().DepthState.SetDirty(); + rendererState.DepthState.DepthWriteEnabled = false; + rendererState.DepthState.SetDirty(); UpdateRenderStates(); // Draw barrier after sky - reinterpret_cast( 0x632140 )( Engine::GAPI->GetLoadedWorldInfo()->MainWorld->GetSkyControllerOutdoor() ); + reinterpret_cast(0x632140)(Engine::GAPI->GetLoadedWorldInfo()->MainWorld->GetSkyControllerOutdoor()); Engine::GAPI->SetFarPlane( - Engine::GAPI->GetRendererState().RendererSettings.SectionDrawRadius * + rendererState.RendererSettings.SectionDrawRadius * WORLD_SECTION_SIZE ); } #endif diff --git a/D3D11Engine/D3D11ShaderManager.cpp b/D3D11Engine/D3D11ShaderManager.cpp index b339d711..0b5a807d 100644 --- a/D3D11Engine/D3D11ShaderManager.cpp +++ b/D3D11Engine/D3D11ShaderManager.cpp @@ -157,6 +157,10 @@ XRESULT D3D11ShaderManager::Init() { Shaders.push_back( ShaderInfo::make( "VS_TransformedEx.hlsl" ) .with_layout( VERTEX_INPUT_LAYOUT_1 ) ); + + Shaders.push_back( ShaderInfo::make( "VS_TransformedEx.hlsl" ) + .with_layout( VERTEX_INPUT_LAYOUT_1 ) + .with_macros( { {"OVERRIDE_MAX_Z", "1"} } ) ); Shaders.push_back( ShaderInfo::make( "VS_ExPointLight.hlsl" ) .with_layout( VERTEX_INPUT_LAYOUT_1 ) ); @@ -164,6 +168,10 @@ XRESULT D3D11ShaderManager::Init() { Shaders.push_back( ShaderInfo::make( "VS_XYZRHW_DIF_T1.hlsl" ) .with_layout( VERTEX_INPUT_LAYOUT_7_VS_XYZRHW_DIF_T1 ) ); + Shaders.push_back( ShaderInfo::make( "VS_XYZRHW_DIF_T1.hlsl" ) + .with_layout( VERTEX_INPUT_LAYOUT_7_VS_XYZRHW_DIF_T1 ) + .with_macros( { {"OVERRIDE_MAX_Z", "1"} })); + Shaders.push_back( ShaderInfo::make( "VS_ExInstancedObj.hlsl" ) .with_layout( VERTEX_INPUT_LAYOUT_10_VS_ExInstancedObj ) .with_macros( [](std::vector& list) { diff --git a/D3D11Engine/D3D7/MyDirect3DDevice7.h b/D3D11Engine/D3D7/MyDirect3DDevice7.h index 1bb1074e..98ee974d 100644 --- a/D3D11Engine/D3D7/MyDirect3DDevice7.h +++ b/D3D11Engine/D3D7/MyDirect3DDevice7.h @@ -244,7 +244,15 @@ class MyDirect3DDevice7 final : public IDirect3DDevice7 { } break; - case D3DRENDERSTATE_ZENABLE: state.DepthState.DepthBufferEnabled = Value != 0; state.DepthState.SetDirty(); break; + case D3DRENDERSTATE_ZENABLE: { + if ( state.RendererInfo.RenderStage == STAGE_DRAW_SKY ) { + // we do custom Sky rendering behavior + break; + } + state.DepthState.DepthBufferEnabled = Value != 0; + state.DepthState.SetDirty(); + break; + } case D3DRENDERSTATE_ALPHATESTENABLE: state.GraphicsState.SetGraphicsSwitch( GSWITCH_ALPHAREF, Value != 0 ); break; case D3DRENDERSTATE_SRCBLEND: state.BlendState.SrcBlend = static_cast(Value); state.BlendState.SetDirty(); break; case D3DRENDERSTATE_DESTBLEND: state.BlendState.DestBlend = static_cast(Value); state.BlendState.SetDirty(); break; @@ -497,7 +505,7 @@ class MyDirect3DDevice7 final : public IDirect3DDevice7 { exv.resize( dwVertexCount ); switch ( dwVertexTypeDesc ) { - case GOTHIC_FVF_XYZRHW_DIF_T1: + case GOTHIC_FVF_XYZRHW_DIF_T1: { //return S_OK; for ( unsigned int i = 0; i < dwVertexCount; i++ ) { Gothic_XYZRHW_DIF_T1_Vertex* rhw = reinterpret_cast(lpvVertices); @@ -509,13 +517,20 @@ class MyDirect3DDevice7 final : public IDirect3DDevice7 { } // Gothic wants that for the sky - Engine::GAPI->GetRendererState().RasterizerState.FrontCounterClockwise = true; - Engine::GAPI->GetRendererState().RasterizerState.SetDirty(); - Engine::GraphicsEngine->SetActiveVertexShader( VShaderID::VS_TransformedEx ); - Engine::GraphicsEngine->BindViewportInformation( VShaderID::VS_TransformedEx, 0 ); + auto& state = Engine::GAPI->GetRendererState(); + state.RasterizerState.FrontCounterClockwise = true; + state.RasterizerState.SetDirty(); + + const auto vs = state.RendererInfo.RenderStage == STAGE_DRAW_SKY + ? VShaderID::VS_TransformedEx_MAX_Z + : VShaderID::VS_TransformedEx; + + Engine::GraphicsEngine->SetActiveVertexShader( vs ); + Engine::GraphicsEngine->BindViewportInformation( vs, 0 ); break; + } - case GOTHIC_FVF_XYZRHW_DIF_SPEC_T1: + case GOTHIC_FVF_XYZRHW_DIF_SPEC_T1: { for ( unsigned int i = 0; i < dwVertexCount; i++ ) { Gothic_XYZRHW_DIF_SPEC_T1_Vertex* rhw = reinterpret_cast(lpvVertices); @@ -524,10 +539,14 @@ class MyDirect3DDevice7 final : public IDirect3DDevice7 { exv[i].TexCoord = rhw[i].texCoord; exv[i].Color = rhw[i].color; } + const auto vs = Engine::GAPI->GetRendererState().RendererInfo.RenderStage == STAGE_DRAW_SKY + ? VShaderID::VS_TransformedEx_MAX_Z + : VShaderID::VS_TransformedEx; Engine::GraphicsEngine->SetActiveVertexShader( VShaderID::VS_TransformedEx ); Engine::GraphicsEngine->BindViewportInformation( VShaderID::VS_TransformedEx, 0 ); break; + } default: return S_OK; @@ -566,17 +585,24 @@ class MyDirect3DDevice7 final : public IDirect3DDevice7 { lpd3dVertexBuffer->GetVertexBufferDesc( &desc ); switch ( desc.dwFVF ) { - case GOTHIC_FVF_XYZRHW_DIF_T1: - Engine::GraphicsEngine->SetActiveVertexShader( VShaderID::VS_XYZRHW_DIF_T1 ); - Engine::GraphicsEngine->SetActivePixelShader( PShaderID::PS_FixedFunctionPipe ); + case GOTHIC_FVF_XYZRHW_DIF_T1: { + const auto& state = Engine::GAPI->GetRendererState(); + auto vshader = + state.RendererInfo.RenderStage == STAGE_DRAW_SKY + ? VShaderID::VS_XYZRHW_DIF_T1_MAX_Z + : VShaderID::VS_XYZRHW_DIF_T1; + + Engine::GraphicsEngine->SetActiveVertexShader( vshader ); + Engine::GraphicsEngine->SetActivePixelShader( PShaderID::PS_FixedFunctionPipe ); - Engine::GraphicsEngine->BindViewportInformation( VShaderID::VS_XYZRHW_DIF_T1, 0 ); + Engine::GraphicsEngine->BindViewportInformation( vshader, 0 ); // Gothic wants that for the sky Engine::GAPI->GetRendererState().RasterizerState.FrontCounterClockwise = true; Engine::GAPI->GetRendererState().RasterizerState.SetDirty(); Engine::GraphicsEngine->DrawVertexBufferFF( static_cast(lpd3dVertexBuffer)->GetVertexBuffer(), dwNumVertices, dwStartVertex, sizeof( Gothic_XYZRHW_DIF_T1_Vertex ) ); break; + } default: return S_OK; diff --git a/D3D11Engine/GothicGraphicsState.h b/D3D11Engine/GothicGraphicsState.h index dea13eb1..d62d2d7c 100644 --- a/D3D11Engine/GothicGraphicsState.h +++ b/D3D11Engine/GothicGraphicsState.h @@ -18,6 +18,7 @@ enum RenderStage { _STAGE_DRAW_DX11_START, STAGE_DRAW_WORLD, STAGE_DRAW_SKELETAL, + STAGE_DRAW_SKY, _STAGE_DRAW_DX11_END, STAGE_DRAW_HUD, STAGE_DRAW_SHADOWS, @@ -123,7 +124,7 @@ __declspec(align(4)) struct GothicPipelineState { /** Sets this state dirty, which means that it will be updated before next rendering */ void SetDirty() { StateDirty = true; - HashThis( reinterpret_cast(this), StructSize ); + // HashThis( reinterpret_cast(this), StructSize ); } /** Hashes the whole struct */ @@ -179,7 +180,7 @@ class BaseDepthBufferState; struct GothicDepthBufferStateInfo : public GothicPipelineState { GothicDepthBufferStateInfo() { StructSize = sizeof( GothicDepthBufferStateInfo ); - Padding[0] = Padding[1] = false; + Padding0 = Padding1 = false; } /** Layed out for D3D11 */ @@ -201,12 +202,15 @@ struct GothicDepthBufferStateInfo : public GothicPipelineState { DepthBufferEnabled = true; DepthWriteEnabled = true; DepthBufferCompareFunc = DEFAULT_DEPTH_COMP_STATE; + Padding0 = false; + Padding1 = false; } /** Depthbuffer settings */ bool DepthBufferEnabled; bool DepthWriteEnabled; - bool Padding[2]; + bool Padding0; + bool Padding1; ECompareFunc DepthBufferCompareFunc; /** Deletes all cached states */ diff --git a/D3D11Engine/ShaderIDs.h b/D3D11Engine/ShaderIDs.h index 1d6d31f9..e39f33ad 100644 --- a/D3D11Engine/ShaderIDs.h +++ b/D3D11Engine/ShaderIDs.h @@ -12,8 +12,10 @@ enum class VShaderID : size_t { VS_ExSkeletal, VS_ExSkeletalVN, VS_TransformedEx, + VS_TransformedEx_MAX_Z, VS_ExPointLight, VS_XYZRHW_DIF_T1, + VS_XYZRHW_DIF_T1_MAX_Z, VS_ExInstancedObj, VS_ExInstanced, VS_GrassInstanced, diff --git a/D3D11Engine/Shaders/VS_TransformedEx.hlsl b/D3D11Engine/Shaders/VS_TransformedEx.hlsl index 45a4f68e..6f69cf91 100644 --- a/D3D11Engine/Shaders/VS_TransformedEx.hlsl +++ b/D3D11Engine/Shaders/VS_TransformedEx.hlsl @@ -2,6 +2,10 @@ // Simple vertex shader //-------------------------------------------------------------------------------------- +#ifndef OVERRIDE_MAX_Z +#define OVERRIDE_MAX_Z 0 +#endif + cbuffer Viewport : register( b0 ) { float2 V_ViewportPos; @@ -41,7 +45,12 @@ float4 TransformXYZRHW(float4 xyzrhw) float3 ndc; ndc.x = ((2 * (xyzrhw.x - V_ViewportPos.x)) / V_ViewportSize.x) - 1; ndc.y = 1 - ((2 * (xyzrhw.y - V_ViewportPos.y)) / V_ViewportSize.y); + +#ifdef OVERRIDE_MAX_Z + ndc.z = 0; // for sky we need to override this, so that the sky dome is properly depth clipped if behind geometry. +#else ndc.z = xyzrhw.z; +#endif // Convert to clip-space. rhw is actually 1/w ("reciprocal"). So to undo the devide by w, devide by the given 1/w. float actualW = 1.0f / xyzrhw.w; diff --git a/D3D11Engine/Shaders/VS_XYZRHW_DIF_T1.hlsl b/D3D11Engine/Shaders/VS_XYZRHW_DIF_T1.hlsl index d6116202..133ea7dd 100644 --- a/D3D11Engine/Shaders/VS_XYZRHW_DIF_T1.hlsl +++ b/D3D11Engine/Shaders/VS_XYZRHW_DIF_T1.hlsl @@ -2,6 +2,10 @@ // Simple vertex shader //-------------------------------------------------------------------------------------- +#ifndef OVERRIDE_MAX_Z +#define OVERRIDE_MAX_Z 0 +#endif + cbuffer Viewport : register( b0 ) { float2 V_ViewportPos; @@ -39,7 +43,11 @@ float4 TransformXYZRHW(float4 xyzrhw) float3 ndc; ndc.x = ((2 * (xyzrhw.x - V_ViewportPos.x)) / V_ViewportSize.x) - 1; ndc.y = 1 - ((2 * (xyzrhw.y - V_ViewportPos.y)) / V_ViewportSize.y); +#ifdef OVERRIDE_MAX_Z + ndc.z = 0; // for sky we need to override this, so that the sky dome is properly depth clipped if behind geometry. +#else ndc.z = xyzrhw.z; +#endif // Convert to clip-space. rhw is actually 1/w ("reciprocal"). So to undo the devide by w, devide by the given 1/w. float actualW = 1.0f / xyzrhw.w; diff --git a/D3D11Engine/zCMaterial.h b/D3D11Engine/zCMaterial.h index f6c6ff90..9c5149b4 100644 --- a/D3D11Engine/zCMaterial.h +++ b/D3D11Engine/zCMaterial.h @@ -5,20 +5,11 @@ #include "Engine.h" #include "GothicAPI.h" #include "zCTexture.h" +#include "zTypes.h" const int zMAT_GROUP_WATER = 5; const int zMAT_GROUP_SNOW = 6; -const int zMAT_ALPHA_FUNC_MAT_DEFAULT = 0; -const int zMAT_ALPHA_FUNC_NONE = 1; -const int zMAT_ALPHA_FUNC_BLEND = 2; -const int zMAT_ALPHA_FUNC_ADD = 3; -const int zMAT_ALPHA_FUNC_SUB = 4; -const int zMAT_ALPHA_FUNC_MUL = 5; -const int zMAT_ALPHA_FUNC_MUL2 = 6; -const int zMAT_ALPHA_FUNC_TEST = 7; -const int zMAT_ALPHA_FUNC_BLEND_TEST = 8; - class zCTexAniCtrl { private: int AniChannel; @@ -146,11 +137,31 @@ class zCMaterial { } } - int GetAlphaFunc() { - return static_cast(*reinterpret_cast(THISPTR_OFFSET( GothicMemoryLocations::zCMaterial::Offset_AlphaFunc ))); + struct MaterialFlags { + uint8_t smooth : 1; + uint8_t dontUseLightmaps : 1; + uint8_t texAniMap : 1; + uint8_t lodDontCollapse : 1; + uint8_t noCollDet : 1; + uint8_t forceOccluder : 1; + uint8_t m_bEnvironmentalMapping : 1; + uint8_t polyListNeedsSort : 1; + uint8_t matUsage : 8; + uint8_t libFlag : 8; + zTRnd_AlphaBlendFunc rndAlphaBlendFunc : 8; + uint8_t m_bIgnoreSun : 1; + }; + + __forceinline MaterialFlags& GetFlags() { + return *reinterpret_cast(THISPTR_OFFSET( GothicMemoryLocations::zCMaterial::Offset_Flags )); + } + + zTRnd_AlphaBlendFunc GetAlphaFunc() { + MaterialFlags& flags = GetFlags(); + return flags.rndAlphaBlendFunc; } - void SetAlphaFunc( int func ) { + void SetAlphaFunc( zTRnd_AlphaBlendFunc func ) { *reinterpret_cast(THISPTR_OFFSET( GothicMemoryLocations::zCMaterial::Offset_AlphaFunc )) = static_cast(func); } @@ -159,7 +170,7 @@ class zCMaterial { } bool HasAlphaTest() { - const int f = GetAlphaFunc(); + const zTRnd_AlphaBlendFunc f = GetAlphaFunc(); return f == zMAT_ALPHA_FUNC_TEST || f == zMAT_ALPHA_FUNC_BLEND_TEST; } diff --git a/D3D11Engine/zTypes.h b/D3D11Engine/zTypes.h index b9a81305..5929111c 100644 --- a/D3D11Engine/zTypes.h +++ b/D3D11Engine/zTypes.h @@ -111,7 +111,18 @@ enum zTRnd_AlphaBlendFunc { zRND_ALPHA_FUNC_MUL = 5, zRND_ALPHA_FUNC_MUL2 = 6, zRND_ALPHA_FUNC_TEST = 7, - zRND_ALPHA_FUNC_BLEND_TEST = 8 + zRND_ALPHA_FUNC_BLEND_TEST = 8, + + // aliases for material use + zMAT_ALPHA_FUNC_MAT_DEFAULT = 0, + zMAT_ALPHA_FUNC_NONE = 1, + zMAT_ALPHA_FUNC_BLEND = 2, + zMAT_ALPHA_FUNC_ADD = 3, + zMAT_ALPHA_FUNC_SUB = 4, + zMAT_ALPHA_FUNC_MUL = 5, + zMAT_ALPHA_FUNC_MUL2 = 6, + zMAT_ALPHA_FUNC_TEST = 7, + zMAT_ALPHA_FUNC_BLEND_TEST = 8, }; struct float4; From 3446c400a682bb1068b77c709b02e15ffedf7afa Mon Sep 17 00:00:00 2001 From: kirides <13602143+kirides@users.noreply.github.com> Date: Mon, 8 Jun 2026 13:37:59 +0200 Subject: [PATCH 2/5] hash when SetDirty again --- D3D11Engine/D3D11GraphicsEngine.cpp | 2 ++ D3D11Engine/GothicGraphicsState.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/D3D11Engine/D3D11GraphicsEngine.cpp b/D3D11Engine/D3D11GraphicsEngine.cpp index bc32f449..d79ce72d 100644 --- a/D3D11Engine/D3D11GraphicsEngine.cpp +++ b/D3D11Engine/D3D11GraphicsEngine.cpp @@ -3611,9 +3611,11 @@ XRESULT D3D11GraphicsEngine::UpdateRenderStates() { auto& rasterState = states.RasterizerState; auto& depthState = states.DepthState; + /* blendState.HashThis( reinterpret_cast(&blendState), blendState.StructSize ); rasterState.HashThis( reinterpret_cast(&rasterState), rasterState.StructSize ); depthState.HashThis( reinterpret_cast(&depthState), depthState.StructSize ); + */ if ( blendState.StateDirty && blendState.Hash != FFBlendStateHash ) { diff --git a/D3D11Engine/GothicGraphicsState.h b/D3D11Engine/GothicGraphicsState.h index d62d2d7c..5376ae4f 100644 --- a/D3D11Engine/GothicGraphicsState.h +++ b/D3D11Engine/GothicGraphicsState.h @@ -124,7 +124,7 @@ __declspec(align(4)) struct GothicPipelineState { /** Sets this state dirty, which means that it will be updated before next rendering */ void SetDirty() { StateDirty = true; - // HashThis( reinterpret_cast(this), StructSize ); + HashThis( reinterpret_cast(this), StructSize ); } /** Hashes the whole struct */ From 0aa80030cbb06d792031bb09980824b1696d64f2 Mon Sep 17 00:00:00 2001 From: kirides <13602143+kirides@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:27:05 +0200 Subject: [PATCH 3/5] fix fog clear color for atmospheric scattering --- D3D11Engine/D3D11GraphicsEngine.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/D3D11Engine/D3D11GraphicsEngine.cpp b/D3D11Engine/D3D11GraphicsEngine.cpp index d79ce72d..2e322cd9 100644 --- a/D3D11Engine/D3D11GraphicsEngine.cpp +++ b/D3D11Engine/D3D11GraphicsEngine.cpp @@ -3860,7 +3860,9 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() { context->ClearRenderTargetView( HDRBackBuffer->GetRenderTargetView().Get(), clearColor ); context->ClearRenderTargetView( Backbuffer->GetRenderTargetView().Get(), clearColor ); - float4 fogColor( rendererState.GraphicsState.FF_FogColor, 0.0f ); + float4 fogColor( rendererState.RendererSettings.AtmosphericScattering + ? rendererState.RendererSettings.FogColorMod + : rendererState.GraphicsState.FF_FogColor, 0.0f ); GetContext()->ClearRenderTargetView( graph.GetPhysicalTexture( colorResource )->GetRenderTargetView().Get(), reinterpret_cast(&fogColor) ); }; }); From edda59caa328857e88a77f0185aad3399c249ebb Mon Sep 17 00:00:00 2001 From: kirides <13602143+kirides@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:43:38 +0200 Subject: [PATCH 4/5] draw sky directly onto hdr backbuffer, after lighting pass. --- D3D11Engine/D3D11GraphicsEngine.cpp | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/D3D11Engine/D3D11GraphicsEngine.cpp b/D3D11Engine/D3D11GraphicsEngine.cpp index 2e322cd9..8bd5291c 100644 --- a/D3D11Engine/D3D11GraphicsEngine.cpp +++ b/D3D11Engine/D3D11GraphicsEngine.cpp @@ -3875,23 +3875,6 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() { ActiveSceneRenderer->AddGeometryPasses( graph, *this, colorResource, velocityBufferHandle, backBufferHandle, normalsResource, specularResource, reactiveMaskResource ); - - if ( rendererState.RendererSettings.DrawSky ) { - graph.AddPass( RG_PASS_NAME( "Draw Sky" ), [&]( RGBuilder& builder, RenderPass& pass ) { - //// Setup / Declare - //RGTextureDesc albedoDesc{ 1920, 1080, 28 /* DXGI_FORMAT_R8G8B8A8_UNORM */, "Albedo" }; - //albedoTarget = builder.CreateTexture( albedoDesc ); - builder.Write( colorResource ); - - pass.m_executeCallback = [this, colorResource]( const RenderGraph& graph )->void { - TracyD3D11ZoneCGX( "D3D11GraphicsEngine::Draw Sky" ); - // Draw back of the sky if outdoor - GetContext()->OMSetRenderTargets( 1, graph.GetPhysicalTexture( colorResource )->GetRenderTargetView().GetAddressOf(), GetDepthBuffer()->GetDepthStencilView().Get() ); - - DrawSky(); - }; - } ); - } graph.AddPass( RG_PASS_NAME("Draw ParticleFX #1"), [&]( RGBuilder& builder, RenderPass& pass ) { // Setup / Declare @@ -3928,7 +3911,7 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() { DrawFrameAlphaMeshes(); }; } - ); + ); // Draw Ambient Occlusion // Shared state for PostFX composition pass @@ -3990,6 +3973,23 @@ XRESULT D3D11GraphicsEngine::OnStartWorldRendering() { }; }); } + + if ( rendererState.RendererSettings.DrawSky ) { + graph.AddPass( RG_PASS_NAME( "Draw Sky" ), [&]( RGBuilder& builder, RenderPass& pass ) { + //// Setup / Declare + //RGTextureDesc albedoDesc{ 1920, 1080, 28 /* DXGI_FORMAT_R8G8B8A8_UNORM */, "Albedo" }; + //albedoTarget = builder.CreateTexture( albedoDesc ); + builder.Write( backBufferHandle ); + + pass.m_executeCallback = [this, backBufferHandle]( const RenderGraph& graph )->void { + TracyD3D11ZoneCGX( "D3D11GraphicsEngine::Draw Sky" ); + // Draw back of the sky if outdoor + GetContext()->OMSetRenderTargets( 1, graph.GetPhysicalTexture( backBufferHandle )->GetRenderTargetView().GetAddressOf(), GetDepthBuffer()->GetDepthStencilView().Get() ); + + DrawSky(); + }; + } ); + } graph.AddPass( RG_PASS_NAME("DrawWaterSurfaces"), [&]( RGBuilder& builder, RenderPass& pass ) { builder.Read( backBufferHandle ); From 7e28f457b673006339eebf171b73b6bc0e95928e Mon Sep 17 00:00:00 2001 From: kirides <13602143+kirides@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:43:52 +0200 Subject: [PATCH 5/5] adjust default fog color for addonworld --- D3D11Engine/GothicGraphicsState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/D3D11Engine/GothicGraphicsState.h b/D3D11Engine/GothicGraphicsState.h index 5376ae4f..96947df4 100644 --- a/D3D11Engine/GothicGraphicsState.h +++ b/D3D11Engine/GothicGraphicsState.h @@ -871,7 +871,7 @@ struct GothicRendererSettings { void SetupAddonWorldSpecificValues() { FogGlobalDensity = 0.00004f; FogHeightFalloff = 0.0005f; - FogColorMod = float3::FromColor( 180, 180, 255 ); + FogColorMod = float3::FromColor( 128, 173, 239 ); FogHeight = 0; }