mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add player water ripples and separate 1x water pass for MSAA compatibility
Player interaction ripples: vertex shader adds radial damped-sine displacement centered on player position, fragment shader adds matching normal perturbation for specular highlights. Player XY packed into shadowParams.zw, ripple strength into fogParams.w. Separate 1x render pass for water when MSAA is active to avoid MSAA-induced darkening — water renders after main pass resolves, using the resolved swapchain image and depth resolve target. Water 1x framebuffers rebuilt on swapchain recreate (window resize).
This commit is contained in:
parent
67e63653a4
commit
03a62526e1
11 changed files with 1306 additions and 115 deletions
|
|
@ -386,9 +386,17 @@ private:
|
|||
GPUPerFrameData currentFrameData{};
|
||||
float globalTime = 0.0f;
|
||||
|
||||
// Per-frame reflection UBO (mirrors camera for planar reflections)
|
||||
VkBuffer reflPerFrameUBO = VK_NULL_HANDLE;
|
||||
VmaAllocation reflPerFrameUBOAlloc = VK_NULL_HANDLE;
|
||||
void* reflPerFrameUBOMapped = nullptr;
|
||||
VkDescriptorSet reflPerFrameDescSet = VK_NULL_HANDLE;
|
||||
|
||||
bool createPerFrameResources();
|
||||
void destroyPerFrameResources();
|
||||
void updatePerFrameUBO();
|
||||
void setupWater1xPass();
|
||||
void renderReflectionPass();
|
||||
|
||||
// Active character previews for off-screen rendering
|
||||
std::vector<CharacterPreview*> activePreviews_;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ public:
|
|||
return (depthResolveImage == VK_NULL_HANDLE) && (msaaSamples_ > VK_SAMPLE_COUNT_1_BIT);
|
||||
}
|
||||
VkFormat getDepthFormat() const { return depthFormat; }
|
||||
VkImageView getDepthResolveImageView() const { return depthResolveImageView; }
|
||||
VkImageView getDepthImageView() const { return depthImageView; }
|
||||
|
||||
// UI texture upload: creates a Vulkan texture from RGBA data and returns
|
||||
// a VkDescriptorSet suitable for use as ImTextureID.
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public:
|
|||
|
||||
// Multisampling
|
||||
PipelineBuilder& setMultisample(VkSampleCountFlagBits samples);
|
||||
PipelineBuilder& setAlphaToCoverage(bool enable);
|
||||
|
||||
// Pipeline layout
|
||||
PipelineBuilder& setLayout(VkPipelineLayout layout);
|
||||
|
|
@ -80,6 +81,7 @@ public:
|
|||
// Common blend states
|
||||
static VkPipelineColorBlendAttachmentState blendDisabled();
|
||||
static VkPipelineColorBlendAttachmentState blendAlpha();
|
||||
static VkPipelineColorBlendAttachmentState blendPremultiplied();
|
||||
static VkPipelineColorBlendAttachmentState blendAdditive();
|
||||
|
||||
private:
|
||||
|
|
@ -98,6 +100,7 @@ private:
|
|||
float depthBiasConstant_ = 0.0f;
|
||||
float depthBiasSlope_ = 0.0f;
|
||||
VkSampleCountFlagBits msaaSamples_ = VK_SAMPLE_COUNT_1_BIT;
|
||||
bool alphaToCoverage_ = false;
|
||||
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachments_;
|
||||
VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
|
||||
VkRenderPass renderPass_ = VK_NULL_HANDLE;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <memory>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
|
@ -61,7 +62,8 @@ struct WaterSurface {
|
|||
};
|
||||
|
||||
/**
|
||||
* Water renderer (Vulkan)
|
||||
* Water renderer (Vulkan) with planar reflections, Gerstner waves,
|
||||
* GGX specular, shoreline foam, and subsurface scattering.
|
||||
*/
|
||||
class WaterRenderer {
|
||||
public:
|
||||
|
|
@ -81,13 +83,44 @@ public:
|
|||
|
||||
void recreatePipelines();
|
||||
|
||||
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera, float time);
|
||||
// Separate 1x pass for MSAA mode — water rendered after MSAA resolve
|
||||
bool createWater1xPass(VkFormat colorFormat, VkFormat depthFormat);
|
||||
void createWater1xFramebuffers(const std::vector<VkImageView>& swapViews,
|
||||
VkImageView depthView, VkExtent2D extent);
|
||||
void destroyWater1xResources();
|
||||
bool beginWater1xPass(VkCommandBuffer cmd, uint32_t imageIndex, VkExtent2D extent);
|
||||
void endWater1xPass(VkCommandBuffer cmd);
|
||||
bool hasWater1xPass() const { return water1xRenderPass != VK_NULL_HANDLE; }
|
||||
VkRenderPass getWater1xRenderPass() const { return water1xRenderPass; }
|
||||
|
||||
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera, float time, bool use1x = false);
|
||||
void captureSceneHistory(VkCommandBuffer cmd,
|
||||
VkImage srcColorImage,
|
||||
VkImage srcDepthImage,
|
||||
VkExtent2D srcExtent,
|
||||
bool srcDepthIsMsaa);
|
||||
|
||||
// --- Planar reflection pass ---
|
||||
// Call sequence: beginReflectionPass → [render scene] → endReflectionPass
|
||||
bool beginReflectionPass(VkCommandBuffer cmd);
|
||||
void endReflectionPass(VkCommandBuffer cmd);
|
||||
|
||||
// Get the dominant water height near a position (for reflection plane)
|
||||
std::optional<float> getDominantWaterHeight(const glm::vec3& cameraPos) const;
|
||||
|
||||
// Compute reflected view matrix for a given water height
|
||||
static glm::mat4 computeReflectedView(const Camera& camera, float waterHeight);
|
||||
// Compute oblique clip projection to clip below-water geometry in reflection
|
||||
static glm::mat4 computeObliqueProjection(const glm::mat4& proj, const glm::mat4& view, float waterHeight);
|
||||
|
||||
// Update the reflection UBO with reflected viewProj matrix
|
||||
void updateReflectionUBO(const glm::mat4& reflViewProj);
|
||||
|
||||
VkRenderPass getReflectionRenderPass() const { return reflectionRenderPass; }
|
||||
VkExtent2D getReflectionExtent() const { return {REFLECTION_WIDTH, REFLECTION_HEIGHT}; }
|
||||
bool hasReflectionPass() const { return reflectionRenderPass != VK_NULL_HANDLE; }
|
||||
bool hasSurfaces() const { return !surfaces.empty(); }
|
||||
|
||||
void setEnabled(bool enabled) { renderingEnabled = enabled; }
|
||||
bool isEnabled() const { return renderingEnabled; }
|
||||
|
||||
|
|
@ -108,6 +141,10 @@ private:
|
|||
void createSceneHistoryResources(VkExtent2D extent, VkFormat colorFormat, VkFormat depthFormat);
|
||||
void destroySceneHistoryResources();
|
||||
|
||||
// Reflection pass resources
|
||||
void createReflectionResources();
|
||||
void destroyReflectionResources();
|
||||
|
||||
VkContext* vkCtx = nullptr;
|
||||
|
||||
// Pipeline
|
||||
|
|
@ -131,6 +168,30 @@ private:
|
|||
VkExtent2D sceneHistoryExtent = {0, 0};
|
||||
bool sceneHistoryReady = false;
|
||||
|
||||
// Planar reflection resources
|
||||
static constexpr uint32_t REFLECTION_WIDTH = 512;
|
||||
static constexpr uint32_t REFLECTION_HEIGHT = 512;
|
||||
VkRenderPass reflectionRenderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer reflectionFramebuffer = VK_NULL_HANDLE;
|
||||
VkImage reflectionColorImage = VK_NULL_HANDLE;
|
||||
VmaAllocation reflectionColorAlloc = VK_NULL_HANDLE;
|
||||
VkImageView reflectionColorView = VK_NULL_HANDLE;
|
||||
VkImage reflectionDepthImage = VK_NULL_HANDLE;
|
||||
VmaAllocation reflectionDepthAlloc = VK_NULL_HANDLE;
|
||||
VkImageView reflectionDepthView = VK_NULL_HANDLE;
|
||||
VkSampler reflectionSampler = VK_NULL_HANDLE;
|
||||
VkImageLayout reflectionColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
// Reflection UBO (mat4 reflViewProj)
|
||||
::VkBuffer reflectionUBO = VK_NULL_HANDLE;
|
||||
VmaAllocation reflectionUBOAlloc = VK_NULL_HANDLE;
|
||||
void* reflectionUBOMapped = nullptr;
|
||||
|
||||
// Separate 1x water pass (used when MSAA is active)
|
||||
VkRenderPass water1xRenderPass = VK_NULL_HANDLE;
|
||||
VkPipeline water1xPipeline = VK_NULL_HANDLE;
|
||||
std::vector<VkFramebuffer> water1xFramebuffers;
|
||||
|
||||
std::vector<WaterSurface> surfaces;
|
||||
bool renderingEnabled = true;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue