Last active
August 5, 2021 13:59
-
-
Save SabinT/d354f59c4cf385316b30a207349ccfc2 to your computer and use it in GitHub Desktop.
A water shader in Unity (generates vertex displacement and per-pixel normasl)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef WaterSineSeries | |
#define WaterSineSeries | |
// Based on GPU GEMS, Chapter 1: Effective Water Simulation from Physical Models | |
// https://developer.download.nvidia.com/books/HTML/gpugems/gpugems_ch01.html | |
#define TWO_PI 6.2831853 | |
/** | |
* x,y: coordinates | |
* t: time | |
* L: wavelength | |
* A: amplitude | |
* dir: direction of wavefront | |
* speed: wavelengths per second | |
* Outputs: h (displacement), derivatives along X and Y | |
*/ | |
void singleWave( | |
float2 xy, | |
float t, | |
float L, | |
float A, | |
float2 dir, | |
float speed, | |
out float h, | |
out float2 derivatives) | |
{ | |
float w = TWO_PI / L; // frequency | |
float phi = speed * w; | |
float freqFactor = dot(dir, xy) * w; | |
float phase = t * phi; | |
h = A * sin(freqFactor + phase); | |
float dX = w * dir.x * A * cos(freqFactor + phase); | |
float dY = w * dir.y * A * cos(freqFactor + phase); | |
derivatives = float2(dX, dY); | |
} | |
/** | |
* Returns the displacement of water surface on a 2-D plane. | |
* The wave is modeled as a sum of sine series. | |
* Direction of waves is the normalized vector outwards from UV origin. | |
* Use UV co-ordinates as (x, y) for consistent per-pixel normal calculations. | |
* Params: | |
* xy: 2-D Coordinates on water surface | |
* center: center of waves | |
* scale: scale.xz is multiplied with "xy", scale.y is multiplied with amplitude. | |
* t: Time in seconds | |
* wavelengthMultiplier: Gets multiplied to the wavelengths of all harmonics/constituent waves. | |
* Default primary wavelength is 0.1 units. | |
* speedMultiplier: Gets multiplied to the speed of all harmonics. | |
Default reference speed is 1 wavelength/second. | |
* displacement (out): The units by which to raise the vertex at position. | |
* normal (out): The normal of the displaced surface. Note: You may have to rotate this normal according to | |
* the object's orientation. | |
*/ | |
void water_float( | |
float2 xy, | |
float2 center, | |
float3 scale, | |
float t, | |
float waveLengthMultiplier, | |
float speedMultiplier, | |
out float displacement, | |
out float3 normal) | |
{ | |
// xy = (xy - center)* scale.xz; // Scale the plane | |
float ampMultiplier = scale.y; | |
// TODO make constituent waves customizable | |
// TODO add 3D scaler | |
// Accumulators | |
float h = 0; | |
float2 derivatives = float2(0,0); | |
float2 xyTransformed = (xy - center) * scale.xz; | |
float2 dir = normalize(xyTransformed); | |
// Wave 1 | |
float A1 = ampMultiplier * 0.1; | |
float L1 = waveLengthMultiplier * 1.0; | |
float speed1 = speedMultiplier * 1.0; | |
float h1; | |
float2 derivatives1; | |
singleWave( | |
xyTransformed, | |
t, | |
L1, | |
A1, | |
dir, | |
speed1, | |
h1, // out | |
derivatives1 // out | |
); | |
h = h + h1; | |
derivatives = derivatives + derivatives1; | |
// Wave 2 | |
float A2 = ampMultiplier * 0.09; | |
float L2 = waveLengthMultiplier * 0.5; | |
float speed2 = speedMultiplier * 2; | |
float h2; | |
float2 derivatives2; | |
singleWave( | |
xyTransformed - float2(0.0, 0.0), | |
t, | |
L2, | |
A2, | |
dir, | |
speed2, | |
h2, // out | |
derivatives2 // out | |
); | |
h = h + h2; | |
derivatives = derivatives + derivatives2; | |
displacement = h; | |
normal = normalize(float3(-derivatives.x, -derivatives.y, 1)); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment