mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-05 00:33:51 +00:00
fix(rendering): disable HiZ pyramid, fix WMO interior shadow clamping
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
HiZ occlusion culling built ~11 mip levels with per-level barriers behind a blocking vkWaitForFences every frame — the main frame-rate bottleneck. Disable the pyramid build and fall back to GPU frustum- only culling which is nearly free behind the fence. WMO interiors now receive full-strength directional shadows but clamp minimum brightness at 0.45 with a 0.35 ambient floor, so interiors get real shadow contrast without going too dark.
This commit is contained in:
parent
4dcea08b90
commit
0a33e3081c
2 changed files with 20 additions and 41 deletions
|
|
@ -163,11 +163,11 @@ void main() {
|
|||
|
||||
vec3 result;
|
||||
|
||||
// Sample shadow map — skip entirely for interior groups (flag 0x2000).
|
||||
// Interior surfaces rely on pre-baked MOCV vertex-color lighting and the
|
||||
// directional shadow map only makes them darker without any benefit.
|
||||
// Sample shadow map for all groups. Interior groups receive attenuated
|
||||
// shadow (30%) so they get subtle light/shadow variation without the full
|
||||
// outdoor darkening that makes them look wrong.
|
||||
float shadow = 1.0;
|
||||
if (isInterior == 0 && shadowParams.x > 0.5) {
|
||||
if (shadowParams.x > 0.5) {
|
||||
vec3 ldir = normalize(-lightDir.xyz);
|
||||
float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir)));
|
||||
vec3 biasedPos = FragPos + norm * normalOffset;
|
||||
|
|
@ -188,15 +188,14 @@ void main() {
|
|||
result = texColor.rgb * 1.5;
|
||||
} else if (isInterior != 0) {
|
||||
// WMO interior: vertex colors (MOCV) are pre-baked lighting from the artist.
|
||||
// The MOHD ambient color tints/floors the vertex colors so dark spots don't
|
||||
// go completely black, matching the WoW client's interior shading.
|
||||
// We handle BOTH lit and unlit interior materials — directional
|
||||
// sun shadows and lighting are skipped for all interior groups.
|
||||
// The MOHD ambient color floors the vertex colors so dark spots don't go
|
||||
// completely black. Full shadow strength is applied but clamped so
|
||||
// interiors never go darker than a minimum brightness.
|
||||
vec3 wmoAmbient = vec3(wmoAmbientR, wmoAmbientG, wmoAmbientB);
|
||||
// Clamp ambient to at least 0.3 to avoid total darkness when MOHD color is zero
|
||||
wmoAmbient = max(wmoAmbient, vec3(0.3));
|
||||
wmoAmbient = max(wmoAmbient, vec3(0.35));
|
||||
vec3 mocv = max(VertColor.rgb, wmoAmbient);
|
||||
result = texColor.rgb * mocv;
|
||||
float clampedShadow = max(shadow, 0.45);
|
||||
result = texColor.rgb * mocv * clampedShadow;
|
||||
} else if (unlit != 0) {
|
||||
// Outdoor unlit surface — still receives directional shadows
|
||||
result = texColor.rgb * shadow;
|
||||
|
|
|
|||
|
|
@ -894,29 +894,21 @@ void Renderer::beginFrame() {
|
|||
// Update per-frame UBO with current camera/lighting state
|
||||
updatePerFrameUBO();
|
||||
|
||||
// ── Early compute: HiZ pyramid build + M2 frustum/occlusion cull ──
|
||||
// These run in a SEPARATE command buffer submission so the GPU executes
|
||||
// them immediately. The CPU then reads the fresh visibility results
|
||||
// before recording the main render pass — eliminating the 2-frame
|
||||
// staleness that occurs when compute + render share one submission.
|
||||
// ── Early compute: M2 frustum culling ──
|
||||
// GPU frustum cull keeps draw call counts low. The HiZ occlusion pyramid
|
||||
// is skipped for now — building ~11 mip levels with per-level barriers
|
||||
// behind a blocking fence was the main frame-rate bottleneck. Frustum-
|
||||
// only culling is fast enough that the fence wait is negligible.
|
||||
if (m2Renderer && camera && vkCtx) {
|
||||
VkCommandBuffer computeCmd = vkCtx->beginSingleTimeCommands();
|
||||
uint32_t frame = vkCtx->getCurrentFrame();
|
||||
|
||||
// Build HiZ depth pyramid from previous frame's depth buffer
|
||||
if (hizSystem_ && hizSystem_->isReady()) {
|
||||
VkImage depthSrc = vkCtx->getDepthCopySourceImage();
|
||||
hizSystem_->buildPyramid(computeCmd, frame, depthSrc);
|
||||
}
|
||||
|
||||
// Dispatch GPU frustum + HiZ occlusion culling
|
||||
// Dispatch GPU frustum culling (HiZ disabled → frustum-only pipeline)
|
||||
m2Renderer->dispatchCullCompute(computeCmd, frame, *camera);
|
||||
|
||||
vkCtx->endSingleTimeCommands(computeCmd);
|
||||
|
||||
// Ensure GPU→CPU buffer writes are visible to host (non-coherent memory).
|
||||
m2Renderer->invalidateCullOutput(frame);
|
||||
// Visibility results are now in cullOutputMapped_[frame], readable by CPU.
|
||||
}
|
||||
|
||||
// --- Off-screen pre-passes ---
|
||||
|
|
@ -1948,22 +1940,10 @@ bool Renderer::initializeRenderers(pipeline::AssetManager* assetManager, const s
|
|||
}
|
||||
}
|
||||
|
||||
// HiZ occlusion culling — temporal reprojection.
|
||||
// The HiZ pyramid is built from the previous frame's depth buffer. The cull
|
||||
// compute shader uses prevViewProj to project objects into the previous frame's
|
||||
// screen space so that depth samples match the pyramid, eliminating flicker
|
||||
// caused by camera movement between frames.
|
||||
if (!hizSystem_ && m2Renderer && vkCtx) {
|
||||
hizSystem_ = std::make_unique<HiZSystem>();
|
||||
auto extent = vkCtx->getSwapchainExtent();
|
||||
if (hizSystem_->initialize(vkCtx, extent.width, extent.height)) {
|
||||
m2Renderer->setHiZSystem(hizSystem_.get());
|
||||
LOG_INFO("HiZ occlusion culling initialized (", extent.width, "x", extent.height, ")");
|
||||
} else {
|
||||
LOG_WARNING("HiZ occlusion culling unavailable — falling back to frustum-only culling");
|
||||
hizSystem_.reset();
|
||||
}
|
||||
}
|
||||
// HiZ occlusion culling disabled — the pyramid build + blocking fence was
|
||||
// the main frame-rate bottleneck. GPU frustum culling alone provides good
|
||||
// draw-call reduction without the per-frame GPU stall. HiZ can be re-
|
||||
// enabled once the pyramid build is moved to an async compute queue.
|
||||
if (!wmoRenderer) {
|
||||
wmoRenderer = std::make_unique<WMORenderer>();
|
||||
if (!wmoRenderer->initialize(vkCtx, perFrameSetLayout, assetManager))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue