Created
December 23, 2013 22:55
-
-
Save roxlu/8106237 to your computer and use it in GitHub Desktop.
Water simulation v0.0.0.16
This file contains 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
#include "HeightField.h" | |
HeightField::HeightField() | |
:vert(0) | |
,frag(0) | |
,prog(0) | |
,vao(0) | |
,vbo_els(0) | |
,vbo(0) | |
,fbo(0) | |
,tex_u0(0) | |
,tex_u1(0) | |
,tex_v0(0) | |
,tex_v1(0) | |
,tex_norm(0) | |
,tex_pos(0) | |
,tex_texcoord(0) | |
,tex_gradient(0) | |
,tex_forces(0) | |
,state_diffuse(0) | |
,fbo_forces(0) | |
,frag_forces(0) | |
,prog_forces(0) | |
,vao_draw(0) | |
,vert_draw(0) | |
,frag_draw(0) | |
,prog_draw(0) | |
,vert_pos(0) | |
,frag_pos(0) | |
,prog_pos(0) | |
,prog_render(0) | |
,vert_render(0) | |
,frag_render(0) | |
,vert_norm(0) | |
,frag_norm(0) | |
,prog_norm(0) | |
{ | |
} | |
bool HeightField::setup() { | |
pm.perspective(60.0f, float(W)/H, 0.01, 100.0); | |
#if 0 | |
vm.lookAt(vec3(0.0, 10.0, 0.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0)); | |
#else | |
vm.rotateX(DEG_TO_RAD * 15); | |
vm.translate(0.0, -4.0, -14.0); | |
#endif | |
// initial data | |
float init_v[NN]; | |
float init_u[NN]; | |
int upper = N * 0.60; | |
int lower = N * 0.30; | |
for(int i = 0; i < N; ++i) { | |
for(int j = 0; j < N; ++j) { | |
int dx = j * N + i; | |
init_v[dx] = 0.0f; | |
init_u[dx] = 0.0f; | |
if(i > lower && i < upper && j > lower && j < upper) { | |
init_u[dx] = 0.0f; | |
init_v[dx] = 0.0f; | |
} | |
} | |
} | |
// create diffuse shader | |
vert = rx_create_shader(GL_VERTEX_SHADER, HF_DIFFUSE_VERT); | |
frag = rx_create_shader(GL_FRAGMENT_SHADER, HF_DIFFUSE_FRAG); | |
prog = rx_create_program(vert, frag); | |
glBindAttribLocation(prog, 0, "a_tex"); // tex | |
glBindFragDataLocation(prog, 0, "u_out"); // new velocity value | |
glBindFragDataLocation(prog, 1, "v_out"); // new height value | |
glLinkProgram(prog); | |
rx_print_shader_link_info(prog); | |
glUseProgram(prog); | |
glUniform1i(glGetUniformLocation(prog, "u_tex_u"), 0); | |
glUniform1i(glGetUniformLocation(prog, "u_tex_v"), 1); | |
glUniform1i(glGetUniformLocation(prog, "u_tex_forces"), 2); | |
// create draw shader for debugging | |
vert_draw = rx_create_shader(GL_VERTEX_SHADER, HF_TEXTURE_VS); | |
frag_draw = rx_create_shader(GL_FRAGMENT_SHADER, HF_DEBUG_FLOAT_FS); | |
prog_draw = rx_create_program(vert_draw, frag_draw); | |
glLinkProgram(prog_draw); | |
rx_print_shader_link_info(prog_draw); | |
glUseProgram(prog_draw); | |
glUniform1i(glGetUniformLocation(prog_draw, "u_tex"), 0); | |
// create render shader for final result. | |
vert_render = rx_create_shader(GL_VERTEX_SHADER, HF_RENDER_VS); | |
frag_render = rx_create_shader(GL_FRAGMENT_SHADER, HF_RENDER_FS); | |
prog_render = rx_create_program(vert_render, frag_render); | |
glBindAttribLocation(prog_render, 0, "a_tex"); | |
glLinkProgram(prog_render); | |
rx_print_shader_link_info(prog_render); | |
glUseProgram(prog_render); | |
glUniformMatrix4fv(glGetUniformLocation(prog_render, "u_pm"), 1, GL_FALSE, pm.ptr()); | |
glUniformMatrix4fv(glGetUniformLocation(prog_render, "u_vm"), 1, GL_FALSE, vm.ptr()); | |
glUniform1i(glGetUniformLocation(prog_render, "u_tex_u"), 0); | |
glUniform1i(glGetUniformLocation(prog_render, "u_tex_norm"), 1); | |
// create normal shader | |
vert_norm = rx_create_shader(GL_VERTEX_SHADER, HF_NORMALS_VS); | |
frag_norm = rx_create_shader(GL_FRAGMENT_SHADER, HF_NORMALS_FS); | |
prog_norm = rx_create_program(vert_norm, frag_norm); | |
glBindAttribLocation(prog_norm, 0, "a_tex"); | |
glBindFragDataLocation(prog_norm, 0, "norm_out"); | |
glBindFragDataLocation(prog_norm, 1, "grad_out"); | |
glLinkProgram(prog_norm); | |
rx_print_shader_link_info(prog_norm); | |
glUseProgram(prog_norm); | |
glUniform1i(glGetUniformLocation(prog_norm, "u_tex_u"), 0); | |
glUniform1i(glGetUniformLocation(prog_norm, "u_tex_pos"), 1); | |
/* create position/texcoord shader */ | |
vert_pos = rx_create_shader(GL_VERTEX_SHADER, HF_POSITION_VS); | |
frag_pos = rx_create_shader(GL_FRAGMENT_SHADER, HF_POSITION_FS); | |
prog_pos = rx_create_program(vert_pos, frag_pos); | |
glBindFragDataLocation(prog_pos, 0, "pos_out"); | |
glBindFragDataLocation(prog_pos, 1, "tex_out"); | |
glBindAttribLocation(prog_pos, 0, "a_pos"); | |
glLinkProgram(prog_pos); | |
rx_print_shader_link_info(prog_pos); | |
glUseProgram(prog_pos); | |
glUniform1i(glGetUniformLocation(prog_pos, "u_tex_u"), 0); | |
/* create shader that is used to draw "force textures" */ | |
frag_forces = rx_create_shader(GL_FRAGMENT_SHADER, HF_FORCES_FS); | |
prog_forces = rx_create_program(vert_draw, frag_forces); | |
glLinkProgram(prog_forces); | |
rx_print_shader_link_info(prog_forces); | |
glUseProgram(prog_forces); | |
glUniform1i(glGetUniformLocation(prog_forces, "u_tex"), 0); | |
glGenVertexArrays(1, &vao_draw); | |
// create textures that will hold the height field | |
glGenTextures(1, &tex_u0); | |
glBindTexture(GL_TEXTURE_2D, tex_u0); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, N, N, 0, GL_RED, GL_FLOAT, init_u); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_u1); | |
glBindTexture(GL_TEXTURE_2D, tex_u1); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, N, N, 0, GL_RED, GL_FLOAT, init_u); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
float forces[NN * 2]; | |
memset(forces, 0, sizeof(forces)); | |
glGenTextures(1, &tex_forces); | |
glBindTexture(GL_TEXTURE_2D, tex_forces); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, N, N, 0, GL_RG, GL_FLOAT, forces); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_v0); | |
glBindTexture(GL_TEXTURE_2D, tex_v0); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, N, N, 0, GL_RED, GL_FLOAT, init_v); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_v1); | |
glBindTexture(GL_TEXTURE_2D, tex_v1); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, N, N, 0, GL_RED, GL_FLOAT, init_v); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_norm); | |
glBindTexture(GL_TEXTURE_2D, tex_norm); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, N, N, 0, GL_RGB, GL_FLOAT, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_pos); | |
glBindTexture(GL_TEXTURE_2D, tex_pos); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, N, N, 0, GL_RGB, GL_FLOAT, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_texcoord); | |
glBindTexture(GL_TEXTURE_2D, tex_texcoord); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, N, N, 0, GL_RG, GL_FLOAT, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glGenTextures(1, &tex_gradient); | |
glBindTexture(GL_TEXTURE_2D, tex_gradient); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, N, N, 0, GL_RGB, GL_FLOAT, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
// fbo for the diffuse math, normals, positions, etc.. | |
glGenFramebuffers(1, &fbo); | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_u0, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex_u1, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, tex_v0, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, tex_v1, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, tex_norm, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, tex_pos, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT6, GL_TEXTURE_2D, tex_texcoord, 0); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT7, GL_TEXTURE_2D, tex_gradient, 0); | |
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | |
printf("Error: framebuffer is not complete.\n"); | |
::exit(EXIT_FAILURE); | |
} | |
// custom forces (fbo + tex) | |
glGenFramebuffers(1, &fbo_forces); | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo_forces); | |
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_forces, 0); | |
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | |
printf("Framebuffer for custom forces step not complete.\n"); | |
::exit(EXIT_FAILURE); | |
} | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
// create buffer | |
std::vector<FieldVertex> field_vertices(NN, FieldVertex()); | |
for(int i = 0; i < N; ++i) { | |
for(int j = 0; j < N; ++j) { | |
int dx = j * N + i; | |
field_vertices[dx].set(i, j); | |
} | |
} | |
// triangle indices | |
for(int i = 1; i < N - 1; ++i) { | |
for(int j = 1; j < N - 1; ++j) { | |
int a = (j + 0) * N + (i + 0); // bottom left | |
int b = (j + 0) * N + (i + 1); // bottom right | |
int c = (j + 1) * N + (i + 1); // top right | |
int d = (j + 1) * N + (i + 0); // top left | |
indices.push_back(a); | |
indices.push_back(b); | |
indices.push_back(c); | |
indices.push_back(a); | |
indices.push_back(c); | |
indices.push_back(d); | |
} | |
} | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(FieldVertex) * field_vertices.size(), &field_vertices[0].tex[0], GL_STATIC_DRAW); | |
glEnableVertexAttribArray(0); // tex | |
glVertexAttribIPointer(0, 2, GL_INT, sizeof(FieldVertex), (GLvoid*)0); // tex | |
glGenBuffers(1, &vbo_els); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_els); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * indices.size(), &indices[0], GL_STATIC_DRAW); | |
printf("height_field.tex_u0: %d\n", tex_u0); | |
printf("height_field.tex_u1: %d\n", tex_u1); | |
printf("height_field.tex_v0: %d\n", tex_v0); | |
printf("height_field.tex_v1: %d\n", tex_v1); | |
printf("height_field.tex_norm: %d\n", tex_norm); | |
return true; | |
} | |
void HeightField::drawTexture(GLuint tex, float x, float y, float w, float h) { | |
mat4 lpm; | |
mat4 lmm; | |
float hw = w * 0.5; | |
float hh = h * 0.5; | |
lpm.ortho(0, W, H, 0, 0.0f, 100.0f); | |
lmm.translate(x + hw, y + hh, 0.0f); | |
lmm.scale(hw, hh, 1.0); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glBindVertexArray(vao_draw); | |
glUseProgram(prog_draw); | |
glUniformMatrix4fv(glGetUniformLocation(prog_draw, "u_pm"), 1, GL_FALSE, lpm.ptr()); | |
glUniformMatrix4fv(glGetUniformLocation(prog_draw, "u_mm"), 1, GL_FALSE, lmm.ptr()); | |
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
} | |
// Renders the calculated heights/normls/etc.. to screens | |
void HeightField::render() { | |
glUseProgram(prog_render); | |
glEnable(GL_DEPTH_TEST); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_u0); | |
glActiveTexture(GL_TEXTURE1); | |
glBindTexture(GL_TEXTURE_2D, tex_norm); | |
glBindVertexArray(vao); | |
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | |
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, NULL); | |
} | |
// Diffuses the heights | |
void HeightField::diffuse() { | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
glViewport(0, 0, N, N); | |
glUseProgram(prog); | |
glBindVertexArray(vao); | |
state_diffuse = 1 - state_diffuse; | |
glActiveTexture(GL_TEXTURE2); | |
glBindTexture(GL_TEXTURE_2D, tex_forces); | |
if(state_diffuse == 0) { | |
// read from u0, write to u1 | |
// read from v0, write to v1 | |
GLenum draw_bufs[] = { GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT3 } ; | |
glDrawBuffers(2, draw_bufs); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_u0); | |
glActiveTexture(GL_TEXTURE1); | |
glBindTexture(GL_TEXTURE_2D, tex_v0); | |
} | |
else { | |
// read from u1, write to u0 | |
// read from v1, write to v0 | |
GLenum draw_bufs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT2 } ; | |
glDrawBuffers(2, draw_bufs); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_u1); | |
glActiveTexture(GL_TEXTURE1); | |
glBindTexture(GL_TEXTURE_2D, tex_v1); | |
} | |
glDrawArrays(GL_POINTS, 0, NN); | |
// clear the forces buffer. | |
GLenum forces_bufs[] = { GL_COLOR_ATTACHMENT0 } ; | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo_forces); | |
glDrawBuffers(1, forces_bufs); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
glViewport(0, 0, W, H); | |
} | |
void HeightField::calculatePositions() { | |
glViewport(0, 0, N, N); | |
GLenum drawbufs[] = { GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6 } ; | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
glDrawBuffers(2, drawbufs); | |
glUseProgram(prog_pos); | |
glBindVertexArray(vao); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_u0); | |
glDrawArrays(GL_POINTS, 0, NN); | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
glViewport(0, 0, W, H); | |
} | |
// This uses the current height values to produce a texture that will contain the normals | |
void HeightField::calculateNormals() { | |
GLenum drawbufs[] = { GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT7 } ; | |
glViewport(0, 0, N, N); | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
glDrawBuffers(2, drawbufs); | |
glUseProgram(prog_norm); | |
glBindVertexArray(vao); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_u0); | |
glActiveTexture(GL_TEXTURE1); | |
glBindTexture(GL_TEXTURE_2D, tex_pos); | |
glDrawArrays(GL_POINTS, 0, NN); | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
glViewport(0, 0, W, H); | |
} | |
void HeightField::beginDrawForces() { | |
GLenum drawbufs[] = { GL_COLOR_ATTACHMENT0 } ; | |
glBindFramebuffer(GL_FRAMEBUFFER, fbo_forces); | |
glDrawBuffers(1, drawbufs); | |
glClear(GL_COLOR_BUFFER_BIT); | |
glViewport(0, 0, N, N); | |
} | |
void HeightField::endDrawForces() { | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
glViewport(0, 0, W, H); | |
} | |
void HeightField::drawForceTexture(GLuint tex, float px, float py, float pw, float ph) { | |
mat4 lpm; | |
mat4 lmm; | |
float hw = 0.5 * N * pw; | |
float hh = 0.5 * N * ph; | |
#if 0 | |
lpm.ortho(0, W, H, 0, 0.0f, 100.0f); | |
lmm.translate( (px * N) + hw, (py * N) + hh, 0.0f); | |
lmm.scale(hw, hh, 1.0); | |
#else | |
/* | |
lpm.ortho(0, N, N, 0, 0.0f, 100.0f); | |
lmm.translate( px + hw, py + hh, 0.0f); | |
lmm.scale(N, N, 1.0); | |
*/ | |
lpm.ortho(0, N, N, 0, 0.0f, 100.0f); | |
lmm.translate(px * N, py * N, 0.0f); | |
lmm.scale(pw * N, ph * N, 1.0); | |
//printf("%f, %f, %d, %f\n", pw * N, ph * N, N, pw); | |
#endif | |
// glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
// glViewport(0, 0, N, N); | |
glUseProgram(prog_forces); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glBindVertexArray(vao_draw); | |
glUniformMatrix4fv(glGetUniformLocation(prog_forces, "u_pm"), 1, GL_FALSE, lpm.ptr()); | |
glUniformMatrix4fv(glGetUniformLocation(prog_forces, "u_mm"), 1, GL_FALSE, lmm.ptr()); | |
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
//glViewport(0, 0, W, H); | |
} |
This file contains 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 HEIGHTFIELD_H | |
#define HEIGHTFIELD_H | |
#define W 1280 | |
#define H 720 | |
#define N 128 | |
#define NN (N * N) | |
#define DRAW_WIDTH 35.0 | |
#define DRAW_HEIGHT 35.0 | |
#define QUOTE_E(x) # x | |
#define QUOTE(x) QUOTE_E(x) | |
#define ROXLU_USE_OPENGL | |
#define ROXLU_USE_MATH | |
#define ROXLU_USE_PNG | |
#include <tinylib.h> | |
#include <vector> | |
/* | |
Versions: | |
v.0.0.0.4 - added position buffer - https://gist.github.com/roxlu/2c8a964700cb806df0e0 | |
v.0.0.0.3.3 - rendering/normals - https://gist.github.com/roxlu/e85690f04be0968f316b | |
v.0.0.0.3.2 - rendering - https://gist.github.com/roxlu/aabcf9decfd6a1f30d9b | |
v.0.0.0.3.1 - diffuse + normals - https://gist.github.com/roxlu/ddbc776af57e98c5b6a0 | |
v.0.0.0.3 - diffuse working - https://gist.github.com/roxlu/8b49a9932c158ac9bd16 | |
v.0.0.0.2 - first diffuse test - https://gist.github.com/roxlu/904865ede5d32e10ff24 | |
v.0.0.0.1 - initial version - https://gist.github.com/roxlu/b0cf42bfdad3550565c1 | |
*/ | |
// Awesome WebGL fluid sim: http://www.youtube.com/watch?v=f_6aTwP2lMg | |
// "" "" demo: http://skeelogy.github.io/skunami.js/examples/skunami_twoWayCoupling.html | |
// Diffuses the height field | |
static const char* HF_DIFFUSE_VERT = "" | |
"#version 150\n" | |
"in ivec2 a_tex; " | |
"uniform sampler2D u_tex_u; " | |
"uniform sampler2D u_tex_forces;" | |
"uniform sampler2D u_tex_v; " | |
"const float dt = 0.17; " | |
"out float v_new_u_value; " | |
"out float v_new_v_value; " | |
"float get_force(int i, int j) {" | |
" float f0 = texelFetch(u_tex_u, ivec2(a_tex.s + i, a_tex.t + j), 0).r;" | |
" vec2 f1 = texelFetch(u_tex_forces, ivec2(a_tex.s + i, a_tex.t + j), 0).rg;" | |
" return f0 + (f1.r * 5.2) - (f1.g * 9.2);" | |
"}" | |
"void main() { " | |
" gl_Position = vec4(-1.0 + float(a_tex.x) * (1.0 / " QUOTE(N) ") * 2.0, -1.0 + float(a_tex.y) * (1.0 / " QUOTE(N) ") * 2.0, 0.0, 1.0);" | |
#if 0 | |
" float u_center = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t + 0), 0).r;" | |
" float u_left = texelFetch(u_tex_u, ivec2(a_tex.s - 1, a_tex.t + 0), 0).r;" | |
" float u_right = texelFetch(u_tex_u, ivec2(a_tex.s + 1, a_tex.t + 0), 0).r;" | |
" float u_top = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t - 1), 0).r;" | |
" float u_bottom = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t + 1), 0).r;" | |
#else | |
" float u_center = get_force( 0, 0);" | |
" float u_left = get_force(-1, 0);" | |
" float u_right = get_force( 1, 0);" | |
" float u_top = get_force( 0, -1);" | |
" float u_bottom = get_force( 0, 1);" | |
#endif | |
" float f = 8.4 * ((u_right + u_left + u_bottom + u_top) - (4.0 * u_center));" | |
" { " | |
" float max = 0.5;" | |
" if(f > max) { f = max; } else if( f < -max) { f = -max; } " | |
" } " | |
" float v = texelFetch(u_tex_v, a_tex, 0).r;" | |
" v_new_v_value = (v + f * dt); " | |
" v_new_u_value = u_center + v_new_v_value * dt;" | |
" v_new_v_value = v_new_v_value * 0.975;" | |
"}" | |
""; | |
static const char* HF_DIFFUSE_FRAG = "" | |
"#version 150\n" | |
"out vec4 v_out; " | |
"out vec4 u_out; " | |
"in float v_new_u_value; " | |
"in float v_new_v_value; " | |
"void main() {" | |
" v_out = vec4(v_new_v_value);" | |
" u_out = vec4(v_new_u_value);" | |
"}" | |
""; | |
// Positions: renders the positions (later gradients too?) | |
// ----------------------------------------------------------- | |
static const char* HF_POSITION_VS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex_u;" | |
"in ivec2 a_tex;" | |
"out vec3 v_pos;" | |
"out vec2 v_tex;" | |
"const float size_y = " QUOTE(DRAW_WIDTH) ";" | |
"const float size_x = " QUOTE(DRAW_HEIGHT) ";" | |
"const float step_y = size_y / " QUOTE(N) ";" | |
"const float step_x = size_x / " QUOTE(N) ";" | |
"const float hx = size_x * 0.5;" | |
"const float hy = size_y * 0.5;" | |
"const float step_size = 2.0 * (1.0 / " QUOTE(N) ");" | |
"void main() {" | |
" gl_Position = vec4(-1.0 + float(a_tex.s) * step_size, -1.0 + a_tex.t * step_size, 0.0, 1.0);" | |
" float current_height = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t + 0), 0).r;" | |
" v_pos = vec3(-hx + (a_tex.s + 0) * step_x, current_height, -hy + a_tex.t * step_y + 0);" | |
" v_tex = vec2(a_tex.s * (1.0 / " QUOTE(N) "), a_tex.t * (1.0 / " QUOTE(N) "));" | |
"}" | |
""; | |
static const char* HF_POSITION_FS = "" | |
"#version 150\n" | |
"in vec3 v_pos;" | |
"in vec2 v_tex;" | |
"out vec4 pos_out;" | |
"out vec4 tex_out;" | |
"void main() {" | |
" pos_out = vec4(v_pos, 1.0);" | |
" tex_out = vec4(v_tex, 0.0, 1.0);" | |
"}" | |
""; | |
// Normals | |
// ----------------------------------------------------------- | |
static const char* HF_NORMALS_VS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex_u;" | |
"uniform sampler2D u_tex_pos;" | |
"in ivec2 a_tex;" | |
"out vec3 v_norm;" | |
"const float size_y = " QUOTE(DRAW_WIDTH) ";" | |
"const float size_x = " QUOTE(DRAW_HEIGHT) ";" | |
"const float step_y = size_y / " QUOTE(N) ";" | |
"const float step_x = size_x / " QUOTE(N) ";" | |
"const float hx = size_x * 0.5;" | |
"const float hy = size_y * 0.5;" | |
"const float step_size = 2.0 * (1.0 / " QUOTE(N) ");" | |
"void main() {" | |
" gl_Position = vec4(-1.0 + float(a_tex.s) * step_size, -1.0 + a_tex.t * step_size, 0.0, 1.0);" | |
" v_norm = vec3(0.0, 1.0, 0.0);" | |
#if 0 | |
" float current_height = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t + 0), 0).r;" | |
" float right_height = texelFetch(u_tex_u, ivec2(a_tex.s + 1, a_tex.t + 0), 0).r;" | |
" float top_height = texelFetch(u_tex_u, ivec2(a_tex.s + 0, a_tex.t - 1), 0).r;" | |
" vec3 current_pos = vec3(-hx + (a_tex.s + 0) * step_x, current_height, -hy + a_tex.t * step_y + 0);" | |
" vec3 right_pos = vec3(-hx + (a_tex.s + 1) * step_x, right_height, -hy + a_tex.t * step_y + 0);" | |
" vec3 top_pos = vec3(-hx + (a_tex.s + 0) * step_x, top_height, -hy + a_tex.t * step_y - 1);" | |
" vec3 to_right = right_pos - current_pos; " | |
" vec3 to_top = top_pos - current_pos;" | |
#else | |
" vec3 current_pos = texelFetch(u_tex_pos, ivec2(a_tex.s + 0, a_tex.t + 0), 0).rgb;" | |
" vec3 right_pos = texelFetch(u_tex_pos, ivec2(a_tex.s + 1, a_tex.t + 0), 0).rgb;" | |
" vec3 top_pos = texelFetch(u_tex_pos, ivec2(a_tex.s + 0, a_tex.t - 1), 0).rgb;" | |
" vec3 to_right = right_pos - current_pos; " | |
" vec3 to_top = top_pos - current_pos;" | |
#endif | |
" v_norm = normalize(cross(to_right, to_top));" | |
"}" | |
""; | |
static const char* HF_NORMALS_FS = "" | |
"#version 150\n" | |
"in vec3 v_norm;" | |
"out vec4 norm_out;" | |
"out vec4 grad_out;" | |
"void main() {" | |
" norm_out = vec4(v_norm, 1.0);" | |
" float a = atan(v_norm.z, v_norm.x);" | |
" vec3 up = vec3(0.0, 1.0, 0.0);" | |
" vec3 grad = cross(cross(v_norm, up),up);" | |
" grad_out = vec4(grad, 1.0);" | |
"}" | |
""; | |
// Renders the height field | |
// ----------------------------------------------------------- | |
static const char* HF_RENDER_VS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex_u;" | |
"uniform sampler2D u_tex_norm;" | |
"uniform mat4 u_pm;" | |
"uniform mat4 u_vm;" | |
"in ivec2 a_tex;" | |
"out vec3 v_norm;" | |
"const float size_y = " QUOTE(DRAW_WIDTH) ";" | |
"const float size_x = " QUOTE(DRAW_HEIGHT) ";" | |
"const float step_y = size_y / " QUOTE(N) ";" | |
"const float step_x = size_x / " QUOTE(N) ";" | |
"const float hx = size_x * 0.5;" | |
"const float hy = size_y * 0.5;" | |
"void main() {" | |
" float height = texelFetch(u_tex_u, a_tex, 0).r;" | |
" vec4 v = vec4(-hx + a_tex.s * step_x, height, -hy + a_tex.t * step_y, 1.0);" | |
" gl_Position = u_pm * u_vm * v;" | |
" v_norm = texelFetch(u_tex_norm, a_tex, 0).rgb;" | |
"}" | |
""; | |
static const char* HF_RENDER_FS = "" | |
"#version 150\n" | |
"in vec3 v_norm;" | |
"out vec4 fragcolor;" | |
"void main() {" | |
" fragcolor = vec4(1.0, 0.0, 0.0, 1.0);" | |
" fragcolor.rgb = 0.5 + 0.5 * v_norm;" | |
"}" | |
""; | |
// Debug drawing | |
// ----------------------------------------------------------- | |
static const char* HF_TEXTURE_VS = "" // also used for the forces program | |
"#version 150\n" | |
"uniform mat4 u_pm;" | |
"uniform mat4 u_mm;" | |
"const vec2 verts[4] = vec2[](" | |
" vec2(-1.0, 1.0), " | |
" vec2(-1.0, -1.0), " | |
" vec2( 1.0, 1.0), " | |
" vec2( 1.0, -1.0) " | |
");" | |
"const vec2 tex[4] = vec2[](" | |
" vec2(0.0, 1.0), " | |
" vec2(0.0, 0.0), " | |
" vec2(1.0, 1.0), " | |
" vec2(1.0, 0.0)" | |
");" | |
"out vec2 v_tex;" | |
"void main() {" | |
" vec4 vert = vec4(verts[gl_VertexID], 0.0, 1.0);" | |
" gl_Position = u_pm * u_mm * vert;" | |
" v_tex = tex[gl_VertexID];" | |
"}" | |
""; | |
static const char* HF_DEBUG_FLOAT_FS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex;" | |
"in vec2 v_tex;" | |
"out vec4 fragcolor;" | |
"void main() {" | |
" fragcolor.rgb = texture(u_tex, v_tex).rgb;" | |
" fragcolor.a = 0.0;" | |
"}" | |
""; | |
// Shader that is used to draw custom forces, these forces are added to the height field | |
// ------------------------------------------------------------------------------------- | |
static const char* HF_FORCES_FS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex;" | |
"in vec2 v_tex;" | |
"out vec4 fragcolor;" | |
"void main() {" | |
" fragcolor = vec4(texture(u_tex, v_tex).rg, 0.0, 1.0);" | |
"}" | |
""; | |
struct FieldVertex { | |
FieldVertex(){ tex[0] = 0; tex[1] = 0; } | |
FieldVertex(int i, int j) { tex[0] = i; tex[1] = j; } | |
void set(int i, int j) { tex[0] = i; tex[1] = j; } | |
GLint tex[2]; | |
}; | |
class HeightField { | |
public: | |
HeightField(); | |
bool setup(); | |
void diffuse(); /* diffuse step */ | |
void calculatePositions(); /* after the new heights have been diffused we can update the position buffer */ | |
void calculateNormals(); /* after calling diffuse() you need to diffuse the normals */ | |
void drawTexture(GLuint tex, float x, float y, float w, float h); | |
void render(); | |
void beginDrawForces(); | |
void drawForceTexture(GLuint tex, float px, float py, float pw, float ph); // all in percentages | |
void endDrawForces(); | |
public: | |
/* Shared */ | |
GLuint vao; /* generic VAO that is used to render FieldVertices */ | |
GLuint vbo_els; /* element array buffer */ | |
std::vector<GLint> indices; /* indices to render triangles */ | |
/* Diffuse the height field */ | |
GLuint vert; /* vertex shader which performns the diffuse step */ | |
GLuint frag; /* fragment shader which writes/sets the diffused values + velocity */ | |
GLuint prog; /* program which does the diffuse/velocity updates */ | |
GLuint vbo; /* contains the FieldVertex data that is used to sample from the correct location in the shader */ | |
GLuint fbo; /* we use a FBO with a couple of destination/source texture into which we write normals, u0, u1, velocities etc.. */ | |
GLuint tex_u0; /* contains the height values for state 0 */ | |
GLuint tex_u1; /* contains the height values for state 1 */ | |
GLuint tex_v0; /* contains the velocity values for state 0 */ | |
GLuint tex_v1; /* contains the velocity values for state 1 */ | |
GLuint tex_norm; /* contains the normals of the height field */ | |
GLuint tex_pos; /* contains the positions in world space of the vertices */ | |
GLuint tex_texcoord; /* contains the texture coords in a range from 0-1 for the final render, see the position shader */ | |
GLuint tex_gradient; /* contains the gradients for the current positions */ | |
int state_diffuse; /* toggles between 0 and 1 to ping/pong the read/write buffers */ | |
/* Custom forces (testing) */ | |
GLuint fbo_forces; | |
GLuint tex_forces; /* texture that is used to add custom forces; this works by drawing something into the force texture */ | |
GLuint frag_forces; /* fragment shader for the step where we add custom forces, we use the vert_draw vertex shader */ | |
GLuint prog_forces; | |
/* Debug drawing */ | |
GLuint vao_draw; /* vao used to draw attribute less vertices for a texture */ | |
GLuint vert_draw; /* vertex shader to draw the u/v textures */ | |
GLuint frag_draw; /* fragment shader to draw the u/v textures */ | |
GLuint prog_draw; /* program to draw the u/v textures */ | |
/* Position (info) shader */ | |
GLuint vert_pos; /* vertex shader used to write the (world) positions of the grid */ | |
GLuint frag_pos; /* fragment shader to write the (world) positions */ | |
GLuint prog_pos; /* program to write positions (later maybe more info) */ | |
/* Normal shader */ | |
GLuint vert_norm; /* vertex shader that calculates the normals */ | |
GLuint frag_norm; /* fragment shader that writes the normals */ | |
GLuint prog_norm; /* the program that writes the normals */ | |
/* Draw the height field */ | |
GLuint prog_render; /* program that is used to render/show the result of the height field */ | |
GLuint vert_render; /* vertex shader that is used to render the height field */ | |
GLuint frag_render; /* fragment shader that is used to render the height field */ | |
mat4 pm; /* projection matrix */ | |
mat4 vm; /* view matrix */ | |
}; | |
#endif |
This file contains 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
#include <assert.h> | |
#include "Water.h" | |
#include "HeightField.h" | |
Water::Water(HeightField& hf) | |
:height_field(hf) | |
,win_w(0) | |
,win_h(0) | |
,prog(0) | |
,vert(0) | |
,frag(0) | |
,flow_tex(0) | |
,normals_tex(0) | |
,noise_tex(0) | |
,diffuse_tex(0) | |
,foam_tex(0) | |
,force_tex0(0) | |
{ | |
} | |
GLuint Water::createTexture(std::string filename) { | |
int w, h, n; | |
unsigned char* pix; | |
if(!rx_load_png(rx_to_data_path(filename), &pix, w, h, n)) { | |
printf("Error: cannot find: %s\n", filename.c_str()); | |
return 0; | |
} | |
GLuint tex; | |
GLenum format = GL_RGB; | |
if(n == 4) { | |
format = GL_RGBA; | |
} | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, format, GL_UNSIGNED_BYTE, pix); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
printf("Texture, w: %d, h: %d, n: %d\n", w, h, n); | |
delete[] pix; | |
pix = NULL; | |
return tex; | |
} | |
bool Water::setup(int w, int h) { | |
assert(w && h); | |
win_w = w; | |
win_h = h; | |
// create shader | |
vert = rx_create_shader(GL_VERTEX_SHADER, WATER_VS); | |
frag = rx_create_shader(GL_FRAGMENT_SHADER, WATER_FS); | |
prog = rx_create_program(vert, frag); | |
glBindAttribLocation(prog, 0, "a_tex"); | |
glLinkProgram(prog); | |
rx_print_shader_link_info(prog); | |
glUseProgram(prog); | |
glUniform1i(glGetUniformLocation(prog, "u_tex_pos"), 0); // VS | |
glUniform1i(glGetUniformLocation(prog, "u_tex_norm"), 1); // VS | |
glUniform1i(glGetUniformLocation(prog, "u_tex_texcoord"), 2); // VS | |
glUniform1i(glGetUniformLocation(prog, "u_noise_tex"), 3); // FS | |
glUniform1i(glGetUniformLocation(prog, "u_norm_tex"), 4); // FS | |
glUniform1i(glGetUniformLocation(prog, "u_flow_tex"), 5); // FS | |
glUniform1i(glGetUniformLocation(prog, "u_diffuse_tex"), 6); // FS | |
glUniform1i(glGetUniformLocation(prog, "u_foam_tex"), 7); // FS | |
glUniformMatrix4fv(glGetUniformLocation(prog, "u_pm"), 1, GL_FALSE, height_field.pm.ptr()); | |
glUniformMatrix4fv(glGetUniformLocation(prog, "u_vm"), 1, GL_FALSE, height_field.vm.ptr()); | |
// load textures | |
normals_tex = createTexture("water_normals.png"); | |
flow_tex = createTexture("water_flow.png"); | |
noise_tex = createTexture("water_noise.png"); | |
diffuse_tex = createTexture("water_diffuse.png"); | |
foam_tex = createTexture("water_foam.png"); | |
force_tex0 = createTexture("force.png"); | |
return true; | |
} | |
void Water::update(float dt) { | |
} | |
void Water::draw() { | |
glEnable(GL_DEPTH_TEST); | |
glUseProgram(prog); | |
{ | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, height_field.tex_pos); | |
glActiveTexture(GL_TEXTURE1); | |
glBindTexture(GL_TEXTURE_2D, height_field.tex_norm); | |
glActiveTexture(GL_TEXTURE2); | |
glBindTexture(GL_TEXTURE_2D, height_field.tex_texcoord); | |
glActiveTexture(GL_TEXTURE3); | |
glBindTexture(GL_TEXTURE_2D, noise_tex); | |
glActiveTexture(GL_TEXTURE4); | |
glBindTexture(GL_TEXTURE_2D, normals_tex); | |
glActiveTexture(GL_TEXTURE5); | |
glBindTexture(GL_TEXTURE_2D, flow_tex); | |
glActiveTexture(GL_TEXTURE6); | |
glBindTexture(GL_TEXTURE_2D, diffuse_tex); | |
glActiveTexture(GL_TEXTURE7); | |
glBindTexture(GL_TEXTURE_2D, foam_tex); | |
} | |
static float t = 0.0; | |
float time0 = fmod(t, 1.0); | |
float time1 = fmod(t + 0.5, 1.0); | |
t += 0.002; | |
glUniform1f(glGetUniformLocation(prog, "u_time"), t); | |
glUniform1f(glGetUniformLocation(prog, "u_time0"), time0); | |
glUniform1f(glGetUniformLocation(prog, "u_time1"), time1); | |
glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
glBindVertexArray(height_field.vao); | |
glDrawElements(GL_TRIANGLES, height_field.indices.size(), GL_UNSIGNED_INT, NULL); | |
} |
This file contains 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
/* | |
Water | |
------ | |
This class renders the given height fied (using most of the | |
internal types of this HeightField class) using a flow map | |
to simulate the flow of water. | |
*/ | |
#ifndef WATER_H | |
#define WATER_H | |
#define ROXLU_USE_OPENGL | |
#define ROXLU_USE_MATH | |
#define ROXLU_USE_PNG | |
#include <tinylib.h> | |
#include <vector> | |
#include <string> | |
// ------------------------------------------------------ | |
static const char* WATER_VS = "" | |
"#version 150\n" | |
"uniform mat4 u_pm;" | |
"uniform mat4 u_vm;" | |
"uniform sampler2D u_tex_pos;" | |
"uniform sampler2D u_tex_norm;" | |
"uniform sampler2D u_tex_texcoord;" | |
"in ivec3 a_tex;" | |
"out vec3 v_norm;" | |
"out vec3 v_pos;" | |
"out vec2 v_tex;" | |
"void main() {" | |
" v_pos = texelFetch(u_tex_pos, ivec2(a_tex), 0).rgb;" | |
" v_norm = texelFetch(u_tex_norm, ivec2(a_tex), 0).rgb;" | |
" v_tex = texelFetch(u_tex_texcoord, ivec2(a_tex), 0).rg;" | |
" gl_Position = u_pm * u_vm * vec4(v_pos, 1.0);" | |
"}" | |
""; | |
static const char* WATER_FS = "" | |
"#version 150\n" | |
"uniform float u_time;" | |
"uniform float u_time0;" | |
"uniform float u_time1;" | |
"uniform sampler2D u_noise_tex;" | |
"uniform sampler2D u_flow_tex;" | |
"uniform sampler2D u_norm_tex;" // not the same as the norm in WATER_VS | |
"uniform sampler2D u_diffuse_tex;" | |
"uniform sampler2D u_foam_tex;" | |
"in vec3 v_norm;" | |
"in vec3 v_pos;" | |
"in vec2 v_tex;" | |
"out vec4 fragcolor;" | |
"void main() {" | |
" vec2 flow_color = texture(u_flow_tex, v_tex).rg;" | |
" vec3 normal_color = texture(u_norm_tex, v_tex).rgb;" // bump mapping | |
" vec3 diffuse_color = texture(u_diffuse_tex, v_tex).rgb;" | |
" float noise_color = texture(u_noise_tex, v_tex).r;" | |
" float gradient = 1.0 - dot(v_norm, vec3(0,1,0));" | |
" float phase0 = (noise_color * 0.4 + u_time0);" | |
" float phase1 = (noise_color * 0.4 + u_time1);" | |
// " flow_color = normalize(v_norm.xz + flow_color);" // move the texture in the direction of the normal | |
" flow_color = (v_norm.xz * 0.4 + flow_color * 0.7);" // move the texture in the direction of the normal | |
" float tex_scale = 1.0;" | |
" float flow_k = 0.4;" | |
" vec2 texcoord0 = (v_tex * tex_scale) + (flow_color * phase0 * flow_k);" | |
" vec2 texcoord1 = (v_tex * tex_scale) + (flow_color * phase1 * flow_k);" | |
" vec3 normal0 = texture(u_norm_tex, texcoord0).rgb;" | |
" vec3 normal1 = texture(u_norm_tex, texcoord1).rgb;" | |
" float lerp = abs(0.5 - u_time0) / 0.5;" | |
" vec3 moved_normal = mix(normal0, normal1, lerp);" | |
" vec3 diffuse0 = texture(u_diffuse_tex, texcoord0).rgb;" | |
" vec3 diffuse1 = texture(u_diffuse_tex, texcoord1).rgb;" | |
" vec3 moved_diffuse = mix(diffuse0, diffuse1, lerp);" | |
" vec3 foam0 = texture(u_foam_tex, texcoord0 * 4.0).rgb;" | |
" vec3 foam1 = texture(u_foam_tex, texcoord1 * 4.0).rgb;" | |
" vec3 moved_foam = mix(foam0, foam1, lerp);" | |
" vec3 L = vec3(-5,1,0);" | |
" float ndl = max(dot(v_norm, L), 0.0);" | |
" fragcolor = vec4(v_norm * 0.5 + 0.5, 1.0);" | |
" fragcolor.rgb = moved_normal;" | |
" fragcolor.rgb = diffuse_color;" | |
" float height = v_pos.y / 0.1;" | |
" float foam_k = (height + gradient) * 0.4; " | |
" foam_k = v_pos.y;" | |
" if(foam_k > 1.0) { foam_k = 1.0; } else if (foam_k < 0.2) { foam_k = 0.2; } " | |
" fragcolor.rgb = moved_foam * foam_k + (1.0 - foam_k) * moved_diffuse + 0.4 * (ndl * vec3(0.0, 0.0, 0.0));" | |
#if 0 | |
" if(gl_FragCoord.x < 640) {" | |
" fragcolor.rgb = vec3(ndl);" | |
// " fragcolor.rgb = v_norm * 0.5 + 0.5;" | |
" fragcolor.rgb = vec3(gradient);" | |
" }" | |
#endif | |
"}" | |
""; | |
// ------------------------------------------------------ | |
class HeightField; | |
class Water { | |
public: | |
Water(HeightField& heightField); | |
bool setup(int winW, int winH); | |
void update(float dt); | |
void draw(); | |
private: | |
GLuint createTexture(std::string filename); | |
public: | |
HeightField& height_field; | |
int win_w; | |
int win_h; | |
GLuint prog; | |
GLuint vert; | |
GLuint frag; | |
GLuint flow_tex; | |
GLuint normals_tex; | |
GLuint noise_tex; | |
GLuint diffuse_tex; | |
GLuint foam_tex; | |
GLuint force_tex0; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
http://distilleryvesper5-1.ak.instagram.com/a89ecaa66c2311e3b1ac0ebfbcba2f55_101.mp4