Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion D3D11Engine/D3D12Engine/D3D12GraphicsEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,10 @@ class D3D12GraphicsEngine : public BaseGraphicsEngine {
// them, so DrawGhostVobs draws them later. ONLY the main-view animated-skeletal call passes true — it is the
// D3D12 stand-in for the reroute D3D11 does in GothicAPI::DrawWorldMeshNaive (:1394), which this backend
// never calls. Shadow callers must leave it false: ghosts cast no shadows on either backend.
// playerFocusVob: the interact/melee-focus highlight vob (see ComputeSkeletalFocusVob in D3D12Scene.cpp).
void PrepareFrameSkeletals( std::vector<SkeletalVobInfo*>& vobs, const Frustum* cullFrustum = nullptr, int shadowCascade = -1,
const DirectX::XMFLOAT3* sphereCenter = nullptr, float sphereRange = 0.0f, UINT cascadeCount = 1,
bool collectGhosts = false );
bool collectGhosts = false, const zCVob* playerFocusVob = nullptr );
void DrawSkeletalDepthPrepass(); // lay down skeletal base + node-attachment depth into the Forward+ prepass
void DrawSkeletalColor(); // draw the collected skeletal base meshes + node attachments (post-cull, lit)
// Turn this frame's g_FrameSkelDraws/g_FrameAttachDraws into the two main-view ExecuteIndirect argument
Expand Down
5 changes: 4 additions & 1 deletion D3D11Engine/D3D12Engine/D3D12PipelineState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,8 @@ bool D3D12PipelineState::CreateDepthPrepass() {
{ "INSTANCE_WORLD_MATRIX", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 128, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_WINDFLUENCE", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 132, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
// VSDepthAttach takes the full VS_IN (Vob.hlsl), which declares INSTANCE_GP_SLOT — required here too.
{ "INSTANCE_GP_SLOT", 0, DXGI_FORMAT_R32_UINT, 1, 140, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
};
pso.VS = { World.DepthPrepassVobAttachVsBlob->GetBufferPointer(), World.DepthPrepassVobAttachVsBlob->GetBufferSize() };
pso.PS = { World.DepthPrepassVobIndirectPsBlob->GetBufferPointer(), World.DepthPrepassVobIndirectPsBlob->GetBufferSize() };
Expand Down Expand Up @@ -1196,7 +1198,7 @@ bool D3D12PipelineState::CreateVob() {

// Slot 0 = ExVertexStruct (Position@0, Normal@12, TexCoord0@24); slot 1 = per-instance data
// read from VobInstanceInfo (stride 144): world matrix rows @0/16/32/48, instance color @128,
// {windStrenth, canBeAffectedByPlayer} @132 (see Vob.hlsl's wind sway — VSMain only, not the depth prepass).
// {windStrenth, canBeAffectedByPlayer} @132, GP_Slot @140 (bit 31 = focus highlight).
const D3D12_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
Expand All @@ -1207,6 +1209,7 @@ bool D3D12PipelineState::CreateVob() {
{ "INSTANCE_WORLD_MATRIX", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 128, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_WINDFLUENCE", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 132, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_GP_SLOT", 0, DXGI_FORMAT_R32_UINT, 1, 140, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
};

// Reuse the world root signature (b0 ViewProj + t0 SRV + static sampler s0 — identical needs).
Expand Down
50 changes: 46 additions & 4 deletions D3D11Engine/D3D12Engine/D3D12Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "../zFont.h"
#include "../zCCamera.h"
#include "../oCGame.h"
#include "../oCNPC.h"
#include "../oCMobInter.h"
#include "../zCParser.h"
#include "../oCVisFX.h"
#include "../DXGIHelpers.h"
#include "../WindAnimation.h"
Expand Down Expand Up @@ -270,6 +273,40 @@ namespace {
}


// Mirrors D3D11GraphicsEngine's DrawSkeletalMeshVobs playerFocusVob filtering.
const zCVob* ComputeSkeletalFocusVob() {
const bool interactiveFocusEnabled = oCGame::GetHighlightInteractFocus();
const bool meleeFocusEnabled = oCGame::GetHighlightMeleeFocus() >= 2 && oCGame::GetNpcFocusIsHighlightActive();
zCVob* playerFocusVob = oCGame::GetPlayer() ? oCGame::GetPlayer()->GetFocusVob() : nullptr;
if ( !playerFocusVob ) return nullptr;

if ( auto npc = playerFocusVob->As<oCNPC>() ) {
#ifdef BUILD_GOTHIC_1_CLASSIC
static int idxZsTalk = -2;
if ( idxZsTalk == -2 ) { idxZsTalk = zCParser::GetParser()->GetIndex( "ZS_TALK" ); }
if ( npc->GetStates()->IsInState( idxZsTalk ) ) {
return nullptr;
}
#endif
if ( !meleeFocusEnabled ) {
return nullptr;
}
} else if ( !interactiveFocusEnabled ) {
return nullptr;
} else {
if ( oCMobInter* mobInter = playerFocusVob->As<oCMobInter>() ) {
if ( mobInter->IsInteractingWith( oCGame::GetPlayer() ) || !mobInter->HasName() ) {
return nullptr;
}
} else if ( oCMob* mob = playerFocusVob->As<oCMob>() ) {
if ( !mob->HasName() ) {
return nullptr;
}
}
}
return playerFocusVob;
}

gtl::flat_hash_map<BaseVisualInfo*, int16_t> g_vobInfoVisualToBucket;
std::vector<BaseVisualInfo*> g_vobInfoVisualIndexToVisualInfo;
RenderView g_GeometryPassVobs;
Expand Down Expand Up @@ -2176,8 +2213,9 @@ XRESULT D3D12GraphicsEngine::OnStartWorldRendering() {
// collectGhosts=true ONLY here: this is the list D3D11's GothicAPI::DrawWorldMeshNaive walks, and the
// reroute of ghost NPCs into TransparencyVobs is that function's job. Static MOBs (g_FrameMobs) keep the
// plain drop — D3D11 does not reroute them either.
PrepareFrameSkeletals( Engine::GAPI->GetAnimatedSkeletalMeshVobs(), nullptr, -1, nullptr, 0.0f, 1, true );
PrepareFrameSkeletals( g_FrameMobs );
const zCVob* skeletalFocusVob = ComputeSkeletalFocusVob();
PrepareFrameSkeletals( Engine::GAPI->GetAnimatedSkeletalMeshVobs(), nullptr, -1, nullptr, 0.0f, 1, true, skeletalFocusVob );
PrepareFrameSkeletals( g_FrameMobs, nullptr, -1, nullptr, 0.0f, 1, false, skeletalFocusVob );

// Refresh the wind CB's player position ONCE here (before shadows/prepass/color all run this frame) — windDir/
// globalTime were already advanced once in OnBeginFrame; minHeight/maxHeight are refreshed per-visual right
Expand Down Expand Up @@ -4340,7 +4378,7 @@ XRESULT D3D12GraphicsEngine::DrawVobsInstanced() {


void D3D12GraphicsEngine::PrepareFrameSkeletals( std::vector<SkeletalVobInfo*>& vobs, const Frustum* cullFrustum, int shadowCascade,
const DirectX::XMFLOAT3* sphereCenter, float sphereRange, UINT cascadeCount, bool collectGhosts ) {
const DirectX::XMFLOAT3* sphereCenter, float sphereRange, UINT cascadeCount, bool collectGhosts, const zCVob* playerFocusVob ) {
// Run each candidate skeletal vob's once-per-frame animation update, upload its instance + bone CBs and
// its attachments' VOB-instance data ONCE (cached in g_SkelUploadCache — the pose is view-independent),
// and record the resulting GPU addresses into the caller's list: the main view's g_FrameSkelDraws/
Expand Down Expand Up @@ -4565,7 +4603,9 @@ void D3D12GraphicsEngine::PrepareFrameSkeletals( std::vector<SkeletalVobInfo*>&

SkeletalInstanceCB inst = {};
XMStoreFloat4x4( &inst.World, xmWorld );
inst.ModelColor = XMFLOAT4( groundLight.x, groundLight.y, groundLight.z, groundLight.w );
// ModelColor.w doubles as the focus-highlight sentinel — Skeletal.hlsl's PSMain reads it as i.col.a.
const float focusSentinel = ( playerFocusVob && playerFocusVob == vi->Vob ) ? 2.0f : groundLight.w;
inst.ModelColor = XMFLOAT4( groundLight.x, groundLight.y, groundLight.z, focusSentinel );
inst.Fatness = model->GetModelFatness();
// StoreVobPreviousTransforms (end of the previous frame) is what fills PrevWorldMatrix; before
// its first run HasValidPrevTransforms is false and the current world doubles as the previous.
Expand Down Expand Up @@ -4706,6 +4746,8 @@ void D3D12GraphicsEngine::PrepareFrameSkeletals( std::vector<SkeletalVobInfo*>&
vii.world = attWorld;
vii.prevWorld = attPrevWorld; // motion vectors — see attPrevWorld above
vii.color = groundLight.ToDWORD();
// Focus-highlight bit for node-attached MOBs (tree-saw trunks, beds) — mirrors Vob.hlsl's VSMainAttach.
vii.GP_Slot |= ( playerFocusVob && playerFocusVob == vi->Vob ) ? ( 1u << 31 ) : 0u;
vii.windStrenth = attFatness; // reinterpreted as Fatness — see VSMainAttach
vii.canBeAffectedByPlayer = attScaling; // reinterpreted as Scaling — see VSMainAttach
const UINT instOffset = m_VobInstanceBufferOffset;
Expand Down
2 changes: 2 additions & 0 deletions D3D11Engine/D3D12Engine/D3D12ShadowMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ bool D3D12ShadowMap::Init() {
{ "INSTANCE_WORLD_MATRIX", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 48, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 128, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
{ "INSTANCE_WINDFLUENCE", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 132, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
// VSDepthAttach takes the full VS_IN (Vob.hlsl), which declares INSTANCE_GP_SLOT — required here too.
{ "INSTANCE_GP_SLOT", 0, DXGI_FORMAT_R32_UINT, 1, 140, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 },
};
pso.pRootSignature = m_E->m_Pipelines.World.RootSig.Get();
pso.VS = { m_E->m_Pipelines.World.DepthPrepassVobAttachVsBlob->GetBufferPointer(), m_E->m_Pipelines.World.DepthPrepassVobAttachVsBlob->GetBufferSize() };
Expand Down
1 change: 1 addition & 0 deletions D3D11Engine/Shaders/D3D12/Skeletal.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ float4 PSMain( VS_OUT i ) : SV_TARGET
rgb *= lerp( 1.0, 0.8, wetness );
rgb += AccumTiledPointLights( i.clip.xyz, i.wpos, N, albedo, orm.g, orm.b ); // dynamic point lights on top (PBR)
rgb += wetSheen * ( 1.0 + shadow ) * SrgbToLinear( SunColor ) * SunIntensity;
rgb *= 1.0f + step( 1.5f, i.col.a ); // focus highlight
float f = saturate( ( i.fogDist - FogNear ) / max( 1.0, FogFar - FogNear ) );
return float4( lerp( rgb, SrgbToLinear( FogColor ), f ), 1.0 );
}
Expand Down
8 changes: 7 additions & 1 deletion D3D11Engine/Shaders/D3D12/Vob.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ struct VS_IN
// VobInstanceInfo::{windStrenth, canBeAffectedByPlayer} (@132/@136) — 0 for non-wind-flagged vobs, so the
// branches below are no-ops for ordinary instances (matches D3D11's per-instance InstanceWind.x/y > 0 gate).
float2 iwind : INSTANCE_WINDFLUENCE;
// VobInstanceInfo::GP_Slot (@140) — bit 31 is the focus-highlight flag.
uint igpslot : INSTANCE_GP_SLOT;
};
struct VS_OUT { float4 clip : SV_POSITION; float2 uv : TEXCOORD0; float4 col : TEXCOORD1; float fogDist : TEXCOORD2; float3 wpos : TEXCOORD3; float3 wnrm : TEXCOORD4; };
struct VS_OUT { float4 clip : SV_POSITION; float2 uv : TEXCOORD0; float4 col : TEXCOORD1; float fogDist : TEXCOORD2; float3 wpos : TEXCOORD3; float3 wnrm : TEXCOORD4; float focus : TEXCOORD5; };

VS_OUT VSMain( VS_IN i )
{
Expand All @@ -127,6 +129,7 @@ VS_OUT VSMain( VS_IN i )
o.wpos = worldPos;
o.wnrm = mul( i.nrm, (float3x3)i.iworld );
o.fogDist = length( worldPos - CamPosWS );
o.focus = ( i.igpslot >> 31u ) ? 2.0f : 0.0f;
return o;
}

Expand Down Expand Up @@ -154,6 +157,7 @@ float4 PSMain( VS_OUT i ) : SV_TARGET
rgb *= lerp( 1.0, 0.8, wetness );
rgb += AccumTiledPointLights( i.clip.xyz, i.wpos, N, albedo, orm.g, orm.b );
rgb += wetSheen * ( 1.0 + shadow ) * SrgbToLinear( SunColor ) * SunIntensity;
rgb *= 1.0f + step( 1.5f, i.focus ); // focus highlight
float f = saturate( ( i.fogDist - FogNear ) / max( 1.0, FogFar - FogNear ) );
return float4( lerp( rgb, SrgbToLinear( FogColor ), f ), 1.0 );
}
Expand Down Expand Up @@ -208,6 +212,7 @@ VS_OUT VSMainAttach( VS_IN i )
o.wpos = worldPos;
o.wnrm = mul( i.nrm, (float3x3)i.iworld );
o.fogDist = length( worldPos - CamPosWS );
o.focus = ( i.igpslot >> 31u ) ? 2.0f : 0.0f;
return o;
}

Expand Down Expand Up @@ -251,6 +256,7 @@ float4 PSMainBindless( VS_OUT i ) : SV_TARGET
rgb *= lerp( 1.0, 0.8, wetness );
rgb += AccumTiledPointLights( i.clip.xyz, i.wpos, N, albedo, orm.g, orm.b );
rgb += wetSheen * ( 1.0 + shadow ) * SrgbToLinear( SunColor ) * SunIntensity;
rgb *= 1.0f + step( 1.5f, i.focus ); // focus highlight
float f = saturate( ( i.fogDist - FogNear ) / max( 1.0, FogFar - FogNear ) );
return float4( lerp( rgb, SrgbToLinear( FogColor ), f ), 1.0 );
}
Expand Down
Loading