Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
use the shading code from fftWaterPre
  • Loading branch information
iamyoukou committed Oct 21, 2020
1 parent e69c834 commit d5bfc55
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 46 deletions.
45 changes: 24 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,6 @@ It will have features as following:

- and so on.

# A specially designed IFFT

Using standard FFT codes (e.g. [Cooley–Tukey FFT](https://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B)) results in incorrect geometry changes.
Generally, standard FFT assumes that the sampling position is non-negative.
However, the wave vectors used in [1] have negative components.
This constraint guarantees the variety of wave directions.
For example, if a wave vector only has non-negative components,
its direction will always reside in `[+x, +z]` and `[-x, -z]` orthants, and hence,
waves with directions within `[-x, +z]` and `[+x, -z]` orthants are lost.

Furthermore, a standard FFT assumes that the range of summation is also non-negative.
Based on this constraint, it designs the complex exponent set and iterations.
However, the range used in [1] is `[-N/2, N/2)`, with `N` representing the number of sampling points.
It means that a different set of complex exponents should be used.
Therefore, a special IFFT must be designed for [1].

# Result

I have modified [Keith Lantz's code](https://github.com/klantz81/ocean-simulation/tree/master/src) and it can be run on `OSX` now.
Expand All @@ -67,6 +51,15 @@ The shading code is based on [4].

![withLOD](./withLOD.gif)

## Periodic artifacts

Generally, the wide ocean area is created by tiling an FFT water quad.
As a result, when the field of view is large enough,
periodic artifacts can be observed at the far place.

According to [5], there are two ways to reduce periodic (or tiling) artifacts.
I have tried the one that blends the result with some noise [6, 7] and it works well.

![withLOD2](./withLOD2.gif)

## Underwater
Expand Down Expand Up @@ -97,15 +90,25 @@ But this is not enough for realtime purpose.

A GPU-based parallelization is needed.

## Periodic artifact
## Shading

According to [5], there are two ways to reduce the periodic (or tiling) artifact.
I would like to try the BRDF shading method proposed by [8] in the future.

I have tried the one that blends the result with some noise [6, 7] and it actually can reduce the periodic artifact a little bit.
# Note

## Shading
Using standard FFT codes (e.g. [Cooley–Tukey FFT](https://rosettacode.org/wiki/Fast_Fourier_transform#C.2B.2B)) results in incorrect geometry changes.
Generally, standard FFT assumes that the sampling position is non-negative.
However, the wave vectors used in [1] have negative components.
This constraint guarantees the variety of wave directions.
For example, if a wave vector only has non-negative components,
its direction will always reside in `[+x, +z]` and `[-x, -z]` orthants, and hence,
waves with directions within `[-x, +z]` and `[+x, -z]` orthants are lost.

I would like to try the BRDF shading method proposed by [8] in the future.
Furthermore, a standard FFT assumes that the range of summation is also non-negative.
Based on this constraint, it designs the complex exponent set and iterations.
However, the range used in [1] is `[-N/2, N/2)`, with `N` representing the number of sampling points.
It means that a different set of complex exponents should be used.
Therefore, a special IFFT must be designed for [1].

# Reference

Expand Down
5 changes: 3 additions & 2 deletions header/ocean.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,18 @@ class cOcean {
const aiScene *scene;

static const float BASELINE;
static vec2 dudvMove;

vector<GLuint> vboVtxs, vboUvs, vboNmls;
vector<GLuint> vaos;

GLuint shader;
GLuint tboDisp, tboNormal, tboFresnel;
GLuint tboPerlin;
GLuint tboPerlin, tboPerlinN, tboPerlinDudv;
GLint uniM, uniV, uniP;
GLint uniLightColor, uniLightPos;
GLint uniTexReflect, uniTexRefract, uniTexDisp, uniTexNormal, uniTexSkybox;
GLint uniTexPerlin, uniTexFresnel;
GLint uniTexPerlin, uniTexPerlinN, uniTexPerlinDudv, uniTexFresnel;
GLint uniEyePoint;
GLint uniDudvMove;
GLuint tboRefract, tboReflect;
Expand Down
Binary file modified image/perlin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/perlinDudv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/perlinNormal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 51 additions & 14 deletions shader/fsOcean.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,92 @@ in vec3 worldN;

uniform sampler2D texReflect;
uniform sampler2D texRefract;
uniform sampler2D texNormal, texHeight, texFresnel;
uniform sampler2D texNormal, texHeight, texFresnel, texPerlinN;
uniform sampler2D texPerlinDudv;
uniform samplerCube texSkybox;
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 eyePoint;
uniform vec2 dudvMove;

out vec4 fragColor;

const float alpha = 0.02;

void main() {
vec2 ndc = vec2(clipSpace.x / clipSpace.w, clipSpace.y / clipSpace.w);
ndc = ndc / 2.0 + 0.5;

vec2 texCoordRefract = vec2(ndc.x, ndc.y);
vec2 texCoordReflect = vec2(ndc.x, -ndc.y);

// Distorting the reflection or refraction texture
// produces a better effect.
// This method is from the dudvWater project.
// Note: the difference between only using texPerlinDudv
// and blending texPerlinDudv with texNormalDudv is very small.
vec2 distortion1 =
texture(texPerlinDudv, vec2(uv.x + dudvMove.x, uv.y)).rg * 2.0 - 1.0;
distortion1 *= alpha;

vec2 distortion2 =
texture(texPerlinDudv, vec2(-uv.x, uv.y + dudvMove.y)).rg * 2.0 - 1.0;
distortion2 *= alpha;

vec2 distortion = distortion1 + distortion2;

texCoordReflect += distortion;
texCoordReflect.x = clamp(texCoordReflect.x, 0.001, 0.999);
texCoordReflect.y = clamp(texCoordReflect.y, -0.999, -0.001);

texCoordRefract += distortion;
texCoordRefract = clamp(texCoordRefract, 0.001, 0.999);

vec4 refl = texture(texReflect, texCoordReflect);
// vec4 refr = texture(texRefract, texCoordRefract);
// vec4 refl = vec4(0.69, 0.84, 1, 0);
vec4 refr = vec4(0.168, 0.267, 0.255, 0);
float dist = length(lightPos - worldPos);
// float sunAtten = 1.0 / (dist * dist);

// farther: N more close to vec3(0, 1, 0)
// this can significantly reduce artifacts due to the normal map at far place
float nFrac = exp(0.075 * dist) - 1.0;
vec3 warpN = vec3(0, 1.0, 0) * nFrac;
vec3 N = texture(texNormal, mod(uv + dudvMove, 1.0)).rgb * 2.0 - 1.0;

float pFrac = min(exp(0.03 * dist) - 1.0, 1.0);
vec3 perlinN = texture(texPerlinN, (uv + dudvMove) / 16.0).rgb * 2.0 - 1.0;
perlinN *= pFrac;

N = normalize(N + warpN + perlinN);
// end warping normal

vec3 N = texture(texNormal, mod(uv, 1.0)).rgb * 2.0 - 1.0;
vec3 L = normalize(lightPos - worldPos);
vec3 V = normalize(eyePoint - worldPos);
vec3 H = normalize(L + V);
vec3 R = reflect(-L, N);

// two kinds of fresnel effect
// vec2 fresUv = vec2(1.0 - max(dot(N, V), 0), 0.0);
vec2 fresUv = vec2(max(dot(N, R), 0), 0.0);
float fresnel = texture(texFresnel, fresUv).r;

vec4 sunColor = vec4(1.0, 1.0, 1.0, 1.0);
float sunFactor = 20.0;

float dist = length(lightPos - worldPos);
dist = 1.0 / (dist * dist);
vec4 sun = sunColor * sunFactor * max(pow(dot(N, H), 130.0), 0.0) * dist;
vec4 refl = texture(texReflect, texCoordReflect);
vec4 refr = mix(texture(texRefract, texCoordRefract),
vec4(0.168, 0.267, 0.255, 0), 0.9);
// vec4 refl = vec4(0.69, 0.84, 1, 0);
// vec4 refr = vec4(0.168, 0.267, 0.255, 0);

vec4 sun = sunColor * sunFactor * max(pow(dot(N, H), 300.0), 0.0);
vec4 sky = texture(texSkybox, R);

fragColor = mix(sky, refl, 0.5);
fragColor = mix(refr, fragColor, fresnel);
fragColor += sun;

// farther the ocean, flatter the appearance
float dist2 = max(length(eyePoint - worldPos), 0.01);
dist2 = exp(-0.1 * dist2);

fragColor = mix(fragColor, refr, 1 - dist2);
// compensation for far place
// can slightly reduce periodic artifacts at far place
float cFrac = min(exp(0.02 * dist) - 1.0, 0.8);
vec4 compen = mix(sky, refl, 0.5);
fragColor = mix(fragColor, compen, cFrac);
}
12 changes: 5 additions & 7 deletions shader/tesQuad.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,22 @@ void main() {
vec3 scale = vec3(0.75, 0.5, 0.5);

// perlin noise
float perlinZ = texture(texPerlin, uv.xy / 16.0).r * 2.0 - 1.0;
float perlinX = texture(texPerlin, uv.yx / 16.0).r * 2.0 - 1.0;
// blend this noise with height field can slightly reduce periodic artifacts
float perlinY = texture(texPerlin, (uv.xy + dudvMove) / 16.0).r * 2.0 - 1.0;

vec3 disp = texture(texDisp, uv).rgb;
disp = disp * 10.0 - 2.0;
disp *= distAtten;
disp *= scale;

float noiseY = (perlinX + perlinZ) * 0.5 * 10.0 * distAtten;
float noiseY = perlinY * 5.0 * distAtten;
worldPos.y += mix(disp.y, noiseY, 0.35);

// x-displacement
float noiseX = perlinX * 5.0 * distAtten;
worldPos.x += mix(disp.x, noiseX, 0.35);
worldPos.x += disp.x;

// z-displacement
float noiseZ = perlinZ * 5.0 * distAtten;
worldPos.z += mix(disp.z, noiseZ, 0.35);
worldPos.z += disp.z;

gl_Position = P * V * vec4(worldPos, 1.0);

Expand Down
2 changes: 2 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ int main(int argc, char *argv[]) {
/* Poll for and process events */
glfwPollEvents();

cOcean::dudvMove += vec2(0.001, 0.001);

// save frame
if (saveTrigger) {
string dir = "./result/output";
Expand Down
12 changes: 10 additions & 2 deletions src/ocean.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "common.h"

const float cOcean::BASELINE = 0.f;
vec2 cOcean::dudvMove = vec2(0.f, 0.f);

cOcean::cOcean(const int N, const float A, const vec2 w, const float length)
: g(9.81), N(N), Nplus1(N + 1), A(A), w(w), length(length), vertices(0),
Expand Down Expand Up @@ -154,6 +155,8 @@ void cOcean::initTexture() {
setTexture(tboNormal, 12, "./image/normal.png", FIF_PNG);
setTexture(tboFresnel, 13, "./image/fresnel.png", FIF_PNG);
setTexture(tboPerlin, 14, "./image/perlin.png", FIF_PNG);
setTexture(tboPerlinN, 15, "./image/perlinNormal.png", FIF_PNG);
setTexture(tboPerlinDudv, 16, "./image/perlinDudv.png", FIF_PNG);
}

void cOcean::initUniform() {
Expand All @@ -172,11 +175,15 @@ void cOcean::initUniform() {
uniTexSkybox = myGetUniformLocation(shader, "texSkybox");
uniTexFresnel = myGetUniformLocation(shader, "texFresnel");
uniTexPerlin = myGetUniformLocation(shader, "texPerlin");
uniTexPerlinN = myGetUniformLocation(shader, "texPerlinN");
uniTexPerlinDudv = myGetUniformLocation(shader, "texPerlinDudv");

glUniform1i(uniTexDisp, 11);
glUniform1i(uniTexNormal, 12);
glUniform1i(uniTexFresnel, 13);
glUniform1i(uniTexPerlin, 14);
glUniform1i(uniTexPerlinN, 15);
glUniform1i(uniTexPerlinDudv, 16);
glUniform1i(uniTexReflect, 3);
glUniform1i(uniTexRefract, 2);

Expand All @@ -185,6 +192,7 @@ void cOcean::initUniform() {
uniLightPos = myGetUniformLocation(shader, "lightPos");

// other
uniDudvMove = myGetUniformLocation(shader, "dudvMove");
uniEyePoint = myGetUniformLocation(shader, "eyePoint");
}

Expand Down Expand Up @@ -395,8 +403,6 @@ void cOcean::render(float t, mat4 M, mat4 V, mat4 P, vec3 eyePoint,
// update maps
setTexture(tboDisp, 11, "./image/disp.png", FIF_PNG);
setTexture(tboNormal, 12, "./image/normal.png", FIF_PNG);
// setTexture(tboDispX, 13, "./image/xDisp.png", FIF_PNG);
// setTexture(tboDispZ, 14, "./image/zDisp.png", FIF_PNG);

// update transform matrix
glUseProgram(shader);
Expand All @@ -409,6 +415,8 @@ void cOcean::render(float t, mat4 M, mat4 V, mat4 P, vec3 eyePoint,
glUniform3fv(uniLightColor, 1, value_ptr(lightColor));
glUniform3fv(uniLightPos, 1, value_ptr(lightPos));

glUniform2fv(uniDudvMove, 1, value_ptr(dudvMove));

// duplicated
for (int j = 0; j < 1; j++) {
for (int i = 0; i < 1; i++) {
Expand Down
Binary file modified withLOD2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d5bfc55

Please sign in to comment.