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
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
Speed multiplier for texture-driven wave animation. 0.0 = static water.
Normal map used for lighting perturbations and surface detail
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);
Width and height of the water plane
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);
// 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
}
};
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