Skip to main content

Overview

The Hydra fluid system provides dynamic water surfaces that capture real-time reflections and refractions, render Gerstner-style waves, and support custom textures for normal mapping and flow animation.

Basic Water Surface

Create a simple water plane:
#include "hydra/fluid.h"

// Create water surface
Fluid water;
water.create(Size2d(100.0f, 100.0f), Color(0.1, 0.3, 0.6, 0.8));
water.setPosition(Position3d(0.0f, -2.0f, 0.0f));

// Initialize and add to scene
water.initialize();
window.addObject(&water);

Real Example from Atlas Engine

Here’s the WaterPot component from the Atlas test suite (test/main.cpp:79-114):
class WaterPot : public CompoundObject {
    CoreObject pot;
    Fluid water;

  public:
    void init() override {
        // Create pot walls
        pot = createBox({1.0f, 0.25f, 0.25f}, Color(0.6f, 0.4f, 0.2f));

        Instance &potRight = pot.createInstance();
        potRight.move({0.0f, 0.0f, 1.0f});
        Instance &potDown = pot.createInstance();
        potDown.rotate({0.0f, 90.0f, 0.0f});
        potDown.move({-0.5f, 0.0f, 0.5f});
        Instance &potUp = pot.createInstance();
        potUp.rotate({0.0f, -90.0f, 0.0f});
        potUp.move({0.5f, 0.0f, 0.5f});
        pot.initialize();
        this->addObject(&pot);

        // Create water surface with textures
        Texture waterDUDV =
            Texture::fromResource(Workspace::get().createResource(
                "water_dudv.png", "WaterDUDV", ResourceType::Image));

        Texture waterNormal =
            Texture::fromResource(Workspace::get().createResource(
                "water_normal.png", "WaterNormal", ResourceType::Image));

        water = Fluid();
        water.create({0.9, 0.9}, Color::blue());
        water.setPosition({0.0f, 0.10f, 0.5f});
        water.movementTexture = waterDUDV;
        water.normalTexture = waterNormal;
        water.initialize();
        this->addObject(&water);
    }
};

Wave Animation

Control wave movement speed:
// Set wave velocity
water.setWaveVelocity(0.5f); // 0.0 = static, higher = faster waves

// Direct property access
water.waveVelocity = 0.3f;

Texture Mapping

Normal Maps

Add surface detail with normal maps:
// Load and apply normal texture
Workspace::get().createResource("water_normal.png", "WaterNormal",
                                ResourceType::Image);
water.normalTexture =
    Texture::fromResourceName("WaterNormal", TextureType::Normal);

Flow Maps (DU/DV)

Animate water movement with distortion maps:
// Load and apply movement texture
Workspace::get().createResource("water_flow.png", "WaterFlow",
                                ResourceType::Image);
water.movementTexture =
    Texture::fromResourceName("WaterFlow", TextureType::Color);

Complete Texture Setup

// Create fluid with full texturing
Fluid ocean;
ocean.create(Size2d(200.0f, 200.0f), Color(0.05, 0.15, 0.3, 0.9));

// Load resources
Texture oceanDUDV = Texture::fromResource(
    Workspace::get().createResource(
        "textures/ocean_dudv.png", "OceanDUDV", ResourceType::Image));

Texture oceanNormal = Texture::fromResource(
    Workspace::get().createResource(
        "textures/ocean_normal.png", "OceanNormal", ResourceType::Image));

// Apply textures
ocean.movementTexture = oceanDUDV;
ocean.normalTexture = oceanNormal;
ocean.setWaveVelocity(0.4f);

ocean.initialize();
window.addObject(&ocean);

Appearance Configuration

Water Color

// Set water color and transparency
water.setWaterColor(Color(0.1, 0.3, 0.5, 0.85));

// Tropical water
water.setWaterColor(Color(0.0, 0.4, 0.6, 0.7));

// Murky water
water.setWaterColor(Color(0.2, 0.3, 0.2, 0.95));

Extent (Size)

// Change water plane dimensions
water.setExtent(Size2d(50.0f, 75.0f)); // Width x Height

Transform Operations

Position

// Set absolute position
water.setPosition(Position3d(0.0f, -5.0f, 10.0f));

// Move by delta
water.move(Position3d(1.0f, 0.0f, 0.0f));

// Get current position
Position3d pos = water.getPosition();

Rotation

// Set absolute rotation (Euler angles)
water.setRotation(Rotation3d(0.0f, 45.0f, 0.0f));

// Rotate incrementally
water.rotate(Rotation3d(0.0f, 10.0f, 0.0f));

Scale

// Set scale
water.setScale(Scale3d(2.0f, 1.0f, 2.0f));

// Get current scale
Size3d scale = water.getScale();

Reflections & Refractions

Fluids automatically capture reflections and refractions during rendering:
// Update capture for dynamic objects
water.updateCapture(window);

// The system automatically:
// - Renders scene above water for reflections
// - Renders scene below water for refractions
// - Blends results based on viewing angle

Properties Reference

waveVelocity
float
default:"0.0f"
Speed multiplier for texture-driven wave animation. 0.0 = static water.
normalTexture
Texture
Normal map used for lighting perturbations and surface detail
movementTexture
Texture
Flow map (DU/DV) used to animate surface movement and distortion

Methods Reference

create()

Builds the fluid mesh with specified extent and color:
void create(Size2d extent, Color color);
extent
Size2d
Width and height of the water plane
color
Color
Base color and transparency (RGBA)

initialize()

Allocates GPU buffers and prepares render targets:
void initialize() override;

update()

Advances water simulation state:
void update(Window &window) override;

render()

Draws the water surface with effects:
void render(float dt, std::shared_ptr<opal::CommandBuffer> commandBuffer,
            bool updatePipeline = false) override;

updateCapture()

Manually triggers reflection/refraction capture:
void updateCapture(Window &window,
    const std::shared_ptr<opal::CommandBuffer> &commandBuffer = nullptr);

Transform Methods

// Position
void setPosition(const Position3d &pos);
void move(const Position3d &delta);
Position3d getPosition() const;

// Rotation
void setRotation(const Rotation3d &rot);
void rotate(const Rotation3d &delta);

// Scale
void setScale(const Scale3d &scale);
Size3d getScale() const;

// Appearance
void setExtent(const Size2d &ext);
void setWaterColor(const Color &color);
void setWaveVelocity(float velocity);

Advanced Example: Ocean Scene

#include "hydra/fluid.h"
#include "hydra/atmosphere.h"

class OceanScene : public Scene {
    Fluid ocean;
    Atmosphere atmosphere;

  public:
    void initialize(Window &window) override {
        // Create large ocean
        ocean.create(Size2d(500.0f, 500.0f), Color(0.05, 0.15, 0.35, 0.85));
        ocean.setPosition(Position3d(0.0f, 0.0f, 0.0f));

        // Load ocean textures
        Texture oceanDUDV = Texture::fromResource(
            Workspace::get().createResource(
                "ocean_dudv.png", "OceanDUDV", ResourceType::Image));

        Texture oceanNormal = Texture::fromResource(
            Workspace::get().createResource(
                "ocean_normal.png", "OceanNormal", ResourceType::Image));

        ocean.movementTexture = oceanDUDV;
        ocean.normalTexture = oceanNormal;
        ocean.setWaveVelocity(0.3f);

        ocean.initialize();
        window.addObject(&ocean);

        // Add atmosphere for realistic lighting
        atmosphere.timeOfDay = 15.0f; // 3 PM
        atmosphere.cycle = true;
        atmosphere.enable();

        // Add clouds for reflections
        atmosphere.addClouds();
        atmosphere.clouds->position = Position3d(0.0f, 80.0f, 0.0f);
    }

    void update(Window &window) override {
        atmosphere.update(window.getDeltaTime());
        
        // Water automatically updates reflections/refractions
    }
};

Performance Considerations

Reflection and refraction rendering can be expensive. The system automatically throttles capture updates to maintain performance.
Fluids always use forward rendering and cannot use deferred rendering paths, regardless of window settings.

Common Use Cases

Lake

Fluid lake;
lake.create(Size2d(80.0f, 60.0f), Color(0.15, 0.25, 0.4, 0.8));
lake.setWaveVelocity(0.15f); // Calm water

River

Fluid river;
river.create(Size2d(200.0f, 20.0f), Color(0.2, 0.3, 0.35, 0.75));
river.setWaveVelocity(0.6f); // Fast flowing

Pool

Fluid pool;
pool.create(Size2d(10.0f, 5.0f), Color(0.1, 0.5, 0.8, 0.7));
pool.setWaveVelocity(0.1f); // Nearly still

Ocean

Fluid ocean;
ocean.create(Size2d(1000.0f, 1000.0f), Color(0.05, 0.15, 0.3, 0.9));
ocean.setWaveVelocity(0.4f); // Active waves

See Also

  • Atmosphere - Sky and lighting that reflects in water
  • Terrain - Terrain systems that can include water features

Build docs developers (and LLMs) love