mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
Fix WMO wall collision, normal mapping, POM backfill, and M2/WMO rendering performance
- Fix MOPY flag check (0x08 not 0x01) for proper wall collision detection - Cap MAX_PUSH to PLAYER_RADIUS to prevent gradual clip-through - Fix WMO doodad quaternion component ordering (X/Y swap) - Linear normal map strength blend in shader for smooth slider control - Enable shadow sampling for interior WMO groups (covered outdoor areas) - Backfill deferred normal/height maps after streaming with descriptor rebind - M2: prepareRender only iterates animated instances, bone dirty flag - M2: remove worker thread VMA allocation, skip unready bone instances - WMO: persistent visibility vectors, sequential culling - Add FSR EASU/RCAS shaders
This commit is contained in:
parent
16c6c2b6a0
commit
a4966e486f
25 changed files with 1467 additions and 352 deletions
|
|
@ -236,6 +236,11 @@ private:
|
|||
std::optional<PendingWorldEntry> pendingWorldEntry_; // Deferred world entry during loading
|
||||
float taxiLandingClampTimer_ = 0.0f;
|
||||
float worldEntryMovementGraceTimer_ = 0.0f;
|
||||
|
||||
// Hearth teleport: freeze player until terrain loads at destination
|
||||
bool hearthTeleportPending_ = false;
|
||||
glm::vec3 hearthTeleportPos_{0.0f}; // render coords
|
||||
float hearthTeleportTimer_ = 0.0f; // timeout safety
|
||||
float facingSendCooldown_ = 0.0f; // Rate-limits MSG_MOVE_SET_FACING
|
||||
float lastSentCanonicalYaw_ = 1000.0f; // Sentinel — triggers first send
|
||||
float taxiStreamCooldown_ = 0.0f;
|
||||
|
|
|
|||
|
|
@ -565,6 +565,8 @@ public:
|
|||
void unstuck();
|
||||
void setUnstuckGyCallback(UnstuckCallback cb) { unstuckGyCallback_ = std::move(cb); }
|
||||
void unstuckGy();
|
||||
void setUnstuckHearthCallback(UnstuckCallback cb) { unstuckHearthCallback_ = std::move(cb); }
|
||||
void unstuckHearth();
|
||||
using BindPointCallback = std::function<void(uint32_t mapId, float x, float y, float z)>;
|
||||
void setBindPointCallback(BindPointCallback cb) { bindPointCallback_ = std::move(cb); }
|
||||
|
||||
|
|
@ -1445,6 +1447,7 @@ private:
|
|||
WorldEntryCallback worldEntryCallback_;
|
||||
UnstuckCallback unstuckCallback_;
|
||||
UnstuckCallback unstuckGyCallback_;
|
||||
UnstuckCallback unstuckHearthCallback_;
|
||||
BindPointCallback bindPointCallback_;
|
||||
CreatureSpawnCallback creatureSpawnCallback_;
|
||||
CreatureDespawnCallback creatureDespawnCallback_;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ public:
|
|||
|
||||
void update(float deltaTime, const glm::vec3& cameraPos = glm::vec3(0.0f));
|
||||
|
||||
/** Pre-allocate GPU resources (bone SSBOs, descriptors) on main thread before parallel render. */
|
||||
void prepareRender(uint32_t frameIndex);
|
||||
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera);
|
||||
void recreatePipelines();
|
||||
bool initializeShadow(VkRenderPass shadowRenderPass);
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ struct M2ModelGPU {
|
|||
bool isKoboldFlame = false; // Model name matches kobold+(candle/torch/mine) (precomputed)
|
||||
bool isLavaModel = false; // Model name contains lava/molten/magma (UV scroll fallback)
|
||||
bool hasTextureAnimation = false; // True if any batch has UV animation
|
||||
uint8_t availableLODs = 0; // Bitmask: bit N set if any batch has submeshLevel==N
|
||||
|
||||
// Particle emitter data (kept from M2Model)
|
||||
std::vector<pipeline::M2ParticleEmitter> particleEmitters;
|
||||
|
|
@ -193,6 +194,7 @@ struct M2Instance {
|
|||
|
||||
// Frame-skip optimization (update distant animations less frequently)
|
||||
uint8_t frameSkipCounter = 0;
|
||||
bool bonesDirty = false; // Set when bones recomputed, cleared after upload
|
||||
|
||||
// Per-instance bone SSBO (double-buffered)
|
||||
::VkBuffer boneBuffer[2] = {};
|
||||
|
|
@ -265,6 +267,8 @@ public:
|
|||
/**
|
||||
* Render all visible instances (Vulkan)
|
||||
*/
|
||||
/** Pre-allocate GPU resources (bone SSBOs, descriptors) on main thread before parallel render. */
|
||||
void prepareRender(uint32_t frameIndex, const Camera& camera);
|
||||
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <glm/glm.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include "rendering/vk_frame_data.hpp"
|
||||
#include "rendering/vk_utils.hpp"
|
||||
#include "rendering/sky_system.hpp"
|
||||
|
||||
namespace wowee {
|
||||
|
|
@ -259,6 +261,14 @@ public:
|
|||
float getShadowDistance() const { return shadowDistance_; }
|
||||
void setMsaaSamples(VkSampleCountFlagBits samples);
|
||||
|
||||
// FSR 1.0 (FidelityFX Super Resolution) upscaling
|
||||
void setFSREnabled(bool enabled);
|
||||
bool isFSREnabled() const { return fsr_.enabled; }
|
||||
void setFSRQuality(float scaleFactor); // 0.50=Perf, 0.59=Balanced, 0.67=Quality, 0.77=UltraQuality
|
||||
void setFSRSharpness(float sharpness); // 0.0 - 2.0
|
||||
float getFSRScaleFactor() const { return fsr_.scaleFactor; }
|
||||
float getFSRSharpness() const { return fsr_.sharpness; }
|
||||
|
||||
void setWaterRefractionEnabled(bool enabled);
|
||||
bool isWaterRefractionEnabled() const;
|
||||
|
||||
|
|
@ -312,7 +322,7 @@ private:
|
|||
VmaAllocation selCircleIdxAlloc = VK_NULL_HANDLE;
|
||||
int selCircleVertCount = 0;
|
||||
void initSelectionCircle();
|
||||
void renderSelectionCircle(const glm::mat4& view, const glm::mat4& projection);
|
||||
void renderSelectionCircle(const glm::mat4& view, const glm::mat4& projection, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
|
||||
glm::vec3 selCirclePos{0.0f};
|
||||
glm::vec3 selCircleColor{1.0f, 0.0f, 0.0f};
|
||||
float selCircleRadius = 1.5f;
|
||||
|
|
@ -322,7 +332,36 @@ private:
|
|||
VkPipeline overlayPipeline = VK_NULL_HANDLE;
|
||||
VkPipelineLayout overlayPipelineLayout = VK_NULL_HANDLE;
|
||||
void initOverlayPipeline();
|
||||
void renderOverlay(const glm::vec4& color);
|
||||
void renderOverlay(const glm::vec4& color, VkCommandBuffer overrideCmd = VK_NULL_HANDLE);
|
||||
|
||||
// FSR 1.0 upscaling state
|
||||
struct FSRState {
|
||||
bool enabled = false;
|
||||
bool needsRecreate = false;
|
||||
float scaleFactor = 0.77f; // Ultra Quality default
|
||||
float sharpness = 0.5f;
|
||||
uint32_t internalWidth = 0;
|
||||
uint32_t internalHeight = 0;
|
||||
|
||||
// Off-screen scene target (reduced resolution)
|
||||
AllocatedImage sceneColor{}; // 1x color (non-MSAA render target / MSAA resolve target)
|
||||
AllocatedImage sceneDepth{}; // Depth (matches current MSAA sample count)
|
||||
AllocatedImage sceneMsaaColor{}; // MSAA color target (only when MSAA > 1x)
|
||||
AllocatedImage sceneDepthResolve{}; // Depth resolve (only when MSAA + depth resolve)
|
||||
VkFramebuffer sceneFramebuffer = VK_NULL_HANDLE;
|
||||
VkSampler sceneSampler = VK_NULL_HANDLE;
|
||||
|
||||
// Upscale pipeline
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descSetLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descPool = VK_NULL_HANDLE;
|
||||
VkDescriptorSet descSet = VK_NULL_HANDLE;
|
||||
};
|
||||
FSRState fsr_;
|
||||
bool initFSRResources();
|
||||
void destroyFSRResources();
|
||||
void renderFSRUpscale();
|
||||
|
||||
// Footstep event tracking (animation-driven)
|
||||
uint32_t footstepLastAnimationId = 0;
|
||||
|
|
@ -411,6 +450,36 @@ private:
|
|||
void setupWater1xPass();
|
||||
void renderReflectionPass();
|
||||
|
||||
// ── Multithreaded secondary command buffer recording ──
|
||||
// Indices into secondaryCmds_ arrays
|
||||
static constexpr uint32_t SEC_SKY = 0; // sky (main thread)
|
||||
static constexpr uint32_t SEC_TERRAIN = 1; // terrain (worker 0)
|
||||
static constexpr uint32_t SEC_WMO = 2; // WMO (worker 1)
|
||||
static constexpr uint32_t SEC_CHARS = 3; // selection circle + characters (main thread)
|
||||
static constexpr uint32_t SEC_M2 = 4; // M2 + particles + glow (worker 2)
|
||||
static constexpr uint32_t SEC_POST = 5; // water + weather + effects (main thread)
|
||||
static constexpr uint32_t SEC_IMGUI = 6; // ImGui (main thread, non-FSR only)
|
||||
static constexpr uint32_t NUM_SECONDARIES = 7;
|
||||
static constexpr uint32_t NUM_WORKERS = 3; // terrain, WMO, M2
|
||||
|
||||
// Per-worker command pools (thread-safe: one pool per thread)
|
||||
VkCommandPool workerCmdPools_[NUM_WORKERS] = {};
|
||||
// Main-thread command pool for its secondary buffers
|
||||
VkCommandPool mainSecondaryCmdPool_ = VK_NULL_HANDLE;
|
||||
// Pre-allocated secondary command buffers [secondaryIndex][frameInFlight]
|
||||
VkCommandBuffer secondaryCmds_[NUM_SECONDARIES][MAX_FRAMES] = {};
|
||||
|
||||
bool parallelRecordingEnabled_ = false; // set true after pools/buffers created
|
||||
bool createSecondaryCommandResources();
|
||||
void destroySecondaryCommandResources();
|
||||
VkCommandBuffer beginSecondary(uint32_t secondaryIndex);
|
||||
void setSecondaryViewportScissor(VkCommandBuffer cmd);
|
||||
|
||||
// Cached render pass state for secondary buffer inheritance
|
||||
VkRenderPass activeRenderPass_ = VK_NULL_HANDLE;
|
||||
VkFramebuffer activeFramebuffer_ = VK_NULL_HANDLE;
|
||||
VkExtent2D activeRenderExtent_ = {0, 0};
|
||||
|
||||
// Active character previews for off-screen rendering
|
||||
std::vector<CharacterPreview*> activePreviews_;
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,10 @@ public:
|
|||
bool isSwapchainDirty() const { return swapchainDirty; }
|
||||
void markSwapchainDirty() { swapchainDirty = true; }
|
||||
|
||||
// VSync (present mode)
|
||||
bool isVsyncEnabled() const { return vsync_; }
|
||||
void setVsync(bool enabled) { vsync_ = enabled; }
|
||||
|
||||
bool isDeviceLost() const { return deviceLost_; }
|
||||
|
||||
// MSAA
|
||||
|
|
@ -145,6 +149,7 @@ private:
|
|||
std::vector<VkFramebuffer> swapchainFramebuffers;
|
||||
bool swapchainDirty = false;
|
||||
bool deviceLost_ = false;
|
||||
bool vsync_ = true;
|
||||
|
||||
// Per-frame resources
|
||||
FrameData frames[MAX_FRAMES_IN_FLIGHT];
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ public:
|
|||
* @param perFrameSet Per-frame descriptor set (set 0)
|
||||
* @param camera Camera for frustum culling
|
||||
*/
|
||||
/** Pre-update mutable state (frame ID, material UBOs) on main thread before parallel render. */
|
||||
void prepareRender();
|
||||
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera);
|
||||
|
||||
/**
|
||||
|
|
@ -332,6 +334,9 @@ public:
|
|||
// Defer normal/height map generation during streaming to avoid CPU stalls
|
||||
void setDeferNormalMaps(bool defer) { deferNormalMaps_ = defer; }
|
||||
|
||||
// Generate normal/height maps for cached textures that were loaded while deferred
|
||||
void backfillNormalMaps();
|
||||
|
||||
private:
|
||||
// WMO material UBO — matches WMOMaterial in wmo.frag.glsl
|
||||
struct WMOMaterialUBO {
|
||||
|
|
@ -720,6 +725,8 @@ private:
|
|||
uint32_t distanceCulled = 0;
|
||||
};
|
||||
std::vector<std::future<void>> cullFutures_;
|
||||
std::vector<size_t> visibleInstances_; // reused per frame
|
||||
std::vector<InstanceDrawList> drawLists_; // reused per frame
|
||||
|
||||
// Collision query profiling (per frame).
|
||||
mutable double queryTimeMs = 0.0;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,10 @@ private:
|
|||
float pendingNormalMapStrength = 0.8f; // 0.0-2.0
|
||||
bool pendingPOM = true; // on by default
|
||||
int pendingPOMQuality = 1; // 0=Low(16), 1=Medium(32), 2=High(64)
|
||||
bool pendingFSR = false;
|
||||
int pendingFSRQuality = 0; // 0=UltraQuality, 1=Quality, 2=Balanced, 3=Performance
|
||||
float pendingFSRSharpness = 0.5f;
|
||||
bool fsrSettingsApplied_ = false;
|
||||
|
||||
// UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)
|
||||
float uiOpacity_ = 0.65f;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue