mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-08-04 11:55:07 -04:00
Three separate faults were keeping the water's edge dry-looking. The spray was being painted over. Water moved into a pass of its own today so the refraction copy could be taken before it, but the swim effects still recorded into the scene pass, which now runs first — so the droplets ended up under the sheet. Shallow shore water hid them only partly, because its alpha sits near the 0.15 floor; the deeper water you swim in hid them completely. The spray now draws in the continuation pass right after the water, with its pipelines built for that pass (single-sampled in both arrangements) and a flag so a mode change cannot record them into a pass they do not match. The wading spray never spawned at all. It shared rippleSpawnAccum with the swimming spray, whose else-branch zeroes that accumulator on every frame it is not swimming — so a 30/s rate could only ever reach 0.5 in a frame and never crossed the threshold. It has its own accumulator now. Its travel direction was also rotated 90 degrees: forward from yaw is (cos, sin), as the camera controller derives it, not (sin, -cos). Neither of those puts froth on the water, though, which is what churned water actually looks like. Wake points are laid down along the path and handed to the water shader, where they read as aerated white water broken up by the same cellular octaves the shoreline foam uses. Wading drops one churned patch per stride; swimming emits a pair off the shoulders that drift apart as they age, which is the V. Points age out, spread as they go, and carry a bounding circle so every other water pixel on screen rejects the trail in one test.
118 lines
3.7 KiB
C++
118 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#include <vk_mem_alloc.h>
|
|
#include <glm/glm.hpp>
|
|
#include <vector>
|
|
|
|
namespace wowee {
|
|
namespace rendering {
|
|
|
|
class Camera;
|
|
class CameraController;
|
|
class WaterRenderer;
|
|
class M2Renderer;
|
|
class VkContext;
|
|
|
|
class SwimEffects {
|
|
public:
|
|
SwimEffects();
|
|
~SwimEffects();
|
|
|
|
[[nodiscard]] bool initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLayout);
|
|
void shutdown();
|
|
void recreatePipelines();
|
|
|
|
/// Select the render pass these particles will be recorded into. Water now
|
|
/// draws after them in a pass of its own, so the spray has to move into that
|
|
/// pass too or the water sheet is painted straight over it. Call before
|
|
/// initialize() or recreatePipelines().
|
|
void setTargetPass(VkRenderPass pass, VkSampleCountFlagBits samples) {
|
|
targetPass_ = pass;
|
|
targetSamples_ = samples;
|
|
}
|
|
void update(const Camera& camera, const CameraController& cc,
|
|
const WaterRenderer& water, float deltaTime);
|
|
void render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet);
|
|
void spawnFootSplash(const glm::vec3& footPos, float waterH);
|
|
void setM2Renderer(M2Renderer* renderer) { m2Renderer = renderer; }
|
|
|
|
private:
|
|
struct Particle {
|
|
glm::vec3 position;
|
|
glm::vec3 velocity;
|
|
float lifetime;
|
|
float maxLifetime;
|
|
float size;
|
|
float alpha;
|
|
};
|
|
|
|
struct InsectParticle {
|
|
glm::vec3 position;
|
|
glm::vec3 orbitCenter; // vegetation position to orbit around
|
|
float lifetime;
|
|
float maxLifetime;
|
|
float size;
|
|
float alpha;
|
|
float phase; // random phase offset for erratic motion
|
|
float orbitRadius;
|
|
float orbitSpeed;
|
|
float heightOffset; // height above plant
|
|
};
|
|
|
|
static constexpr int MAX_RIPPLE_PARTICLES = 200;
|
|
static constexpr int MAX_BUBBLE_PARTICLES = 150;
|
|
static constexpr int MAX_INSECT_PARTICLES = 50;
|
|
|
|
std::vector<Particle> ripples;
|
|
std::vector<Particle> bubbles;
|
|
std::vector<InsectParticle> insects;
|
|
|
|
// Vulkan objects
|
|
VkContext* vkCtx = nullptr;
|
|
M2Renderer* m2Renderer = nullptr;
|
|
|
|
// Ripple pipeline + dynamic buffer
|
|
VkPipeline ripplePipeline = VK_NULL_HANDLE;
|
|
VkPipelineLayout ripplePipelineLayout = VK_NULL_HANDLE;
|
|
::VkBuffer rippleDynamicVB = VK_NULL_HANDLE;
|
|
VmaAllocation rippleDynamicVBAlloc = VK_NULL_HANDLE;
|
|
VmaAllocationInfo rippleDynamicVBAllocInfo{};
|
|
VkDeviceSize rippleDynamicVBSize = 0;
|
|
|
|
// Bubble pipeline + dynamic buffer
|
|
VkPipeline bubblePipeline = VK_NULL_HANDLE;
|
|
VkPipelineLayout bubblePipelineLayout = VK_NULL_HANDLE;
|
|
::VkBuffer bubbleDynamicVB = VK_NULL_HANDLE;
|
|
VmaAllocation bubbleDynamicVBAlloc = VK_NULL_HANDLE;
|
|
VmaAllocationInfo bubbleDynamicVBAllocInfo{};
|
|
VkDeviceSize bubbleDynamicVBSize = 0;
|
|
|
|
// Insect pipeline + dynamic buffer
|
|
VkPipeline insectPipeline = VK_NULL_HANDLE;
|
|
VkPipelineLayout insectPipelineLayout = VK_NULL_HANDLE;
|
|
::VkBuffer insectDynamicVB = VK_NULL_HANDLE;
|
|
VmaAllocation insectDynamicVBAlloc = VK_NULL_HANDLE;
|
|
VmaAllocationInfo insectDynamicVBAllocInfo{};
|
|
VkDeviceSize insectDynamicVBSize = 0;
|
|
|
|
std::vector<float> rippleVertexData;
|
|
std::vector<float> bubbleVertexData;
|
|
std::vector<float> insectVertexData;
|
|
|
|
VkRenderPass targetPass_ = VK_NULL_HANDLE;
|
|
VkSampleCountFlagBits targetSamples_ = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
float wadeSpawnAccum = 0.0f;
|
|
float rippleSpawnAccum = 0.0f;
|
|
float bubbleSpawnAccum = 0.0f;
|
|
float insectSpawnAccum = 0.0f;
|
|
|
|
void spawnRipple(const glm::vec3& pos, const glm::vec3& moveDir, float waterH);
|
|
void spawnBubble(const glm::vec3& pos, float waterH);
|
|
void spawnInsect(const glm::vec3& vegPos);
|
|
};
|
|
|
|
} // namespace rendering
|
|
} // namespace wowee
|