3D C/C++ tutorials -> OpenGL 2.1 -> Water waves GPU algorithm
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
opengl_21_tutorials_win32_framework.h
...
#define WMR 128 // water mesh resolution
#define WHMR 128 // water height map resolution
#define WNMR 256 // water normal map resolution
class COpenGLRenderer
{
protected:
int Width, Height;
mat3x3 NormalMatrix;
mat4x4 ModelMatrix, ViewMatrix, ViewMatrixInverse, ProjectionMatrix, ProjectionBiasMatrixInverse;
protected:
CTexture PoolSkyCubeMap;
GLuint WaterHeightMaps[2], WHMID, WaterNormalMap, PoolSkyVBO, WaterVBO, FBO;
CShaderProgram WaterAddDropProgram, WaterHeightMapProgram, WaterNormalMapProgram, PoolSkyProgram, WaterProgram;
int QuadsVerticesCount;
public:
bool WireFrame, Pause;
float DropRadius;
public:
CString Text;
public:
COpenGLRenderer();
~COpenGLRenderer();
bool Init();
void Render(float FrameTime);
void Resize(int Width, int Height);
void Destroy();
void AddDrop(float x, float y, float DropRadius);
void AddDropByMouseClick(int x, int y);
};
...
opengl_21_tutorials_win32_framework.cpp
...
COpenGLRenderer::COpenGLRenderer()
{
WHMID = 0;
WireFrame = false;
Pause = false;
DropRadius = 4.0f / 128.0f;
Camera.SetViewMatrixPointer(&ViewMatrix, &ViewMatrixInverse);
}
COpenGLRenderer::~COpenGLRenderer()
{
}
bool COpenGLRenderer::Init()
{
// ------------------------------------------------------------------------------------------------------------------------
bool Error = false;
// ------------------------------------------------------------------------------------------------------------------------
if(!GLEW_ARB_texture_non_power_of_two)
{
ErrorLog.Append("GL_ARB_texture_non_power_of_two not supported!\r\n");
Error = true;
}
if(!GLEW_ARB_texture_float)
{
ErrorLog.Append("GL_ARB_texture_float not supported!\r\n");
Error = true;
}
if(!GLEW_EXT_framebuffer_object)
{
ErrorLog.Append("GL_EXT_framebuffer_object not supported!\r\n");
Error = true;
}
// ------------------------------------------------------------------------------------------------------------------------
char *PoolSkyCubeMapFileNames[] = {"pool\\right.jpg", "pool\\left.jpg", "pool\\bottom.jpg", "pool\\top.jpg", "pool\\front.jpg", "pool\\back.jpg"};
Error |= !PoolSkyCubeMap.LoadTextureCubeMap(PoolSkyCubeMapFileNames);
// ------------------------------------------------------------------------------------------------------------------------
Error |= !WaterAddDropProgram.Load("wateradddrop.vs", "wateradddrop.fs");
Error |= !WaterHeightMapProgram.Load("waterheightmap.vs", "waterheightmap.fs");
Error |= !WaterNormalMapProgram.Load("waternormalmap.vs", "waternormalmap.fs");
Error |= !PoolSkyProgram.Load("poolsky.vs", "poolsky.fs");
Error |= !WaterProgram.Load("water.vs", "water.fs");
// ------------------------------------------------------------------------------------------------------------------------
if(Error)
{
return false;
}
// ------------------------------------------------------------------------------------------------------------------------
vec3 LightPosition = vec3(0.0f, 5.5f, -9.5f);
vec3 CubeMapNormals[6] = {
vec3(-1.0f, 0.0f, 0.0f),
vec3(1.0f, 0.0f, 0.0f),
vec3(0.0f, -1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, 0.0f, -1.0f),
vec3(0.0f, 0.0f, 1.0f),
};
// ------------------------------------------------------------------------------------------------------------------------
glUseProgram(WaterHeightMapProgram);
glUniform1f(glGetUniformLocation(WaterHeightMapProgram, "ODWHMR"), 1.0f / (float)WHMR);
glUseProgram(0);
glUseProgram(WaterNormalMapProgram);
glUniform1f(glGetUniformLocation(WaterNormalMapProgram, "ODWNMR"), 1.0f / (float)WNMR);
glUniform1f(glGetUniformLocation(WaterNormalMapProgram, "WMSDWNMRM2"), 2.0f / (float)WNMR * 2.0f);
glUseProgram(0);
glUseProgram(WaterProgram);
glUniform1i(glGetUniformLocation(WaterProgram, "WaterHeightMap"), 0);
glUniform1i(glGetUniformLocation(WaterProgram, "WaterNormalMap"), 1);
glUniform1i(glGetUniformLocation(WaterProgram, "PoolSkyCubeMap"), 2);
glUniform1f(glGetUniformLocation(WaterProgram, "ODWMS"), 1.0f / 2.0f);
glUniform3fv(glGetUniformLocation(WaterProgram, "LightPosition"), 1, &LightPosition);
glUniform3fv(glGetUniformLocation(WaterProgram, "CubeMapNormals"), 6, (float*)CubeMapNormals);
glUseProgram(0);
// ------------------------------------------------------------------------------------------------------------------------
WaterAddDropProgram.UniformLocations = new GLuint[2];
WaterAddDropProgram.UniformLocations[0] = glGetUniformLocation(WaterAddDropProgram, "DropRadius");
WaterAddDropProgram.UniformLocations[1] = glGetUniformLocation(WaterAddDropProgram, "Position");
WaterProgram.UniformLocations = new GLuint[1];
WaterProgram.UniformLocations[0] = glGetUniformLocation(WaterProgram, "CameraPosition");
// ------------------------------------------------------------------------------------------------------------------------
glGenTextures(2, WaterHeightMaps);
vec4 *Heights = new vec4[WHMR * WHMR];
for(int i = 0; i < WHMR * WHMR; i++)
{
Heights[i] = vec4(0.0f, 0.0f, 0.0f, 0.0f);
}
for(int i = 0; i < 2; i++)
{
glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_texture_max_anisotropy_ext);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WHMR, WHMR, 0, GL_RGBA, GL_FLOAT, Heights);
glGenerateMipmapEXT(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
delete [] Heights;
// ------------------------------------------------------------------------------------------------------------------------
glGenTextures(1, &WaterNormalMap);
vec4 *Normals = new vec4[WNMR * WNMR];
for(int i = 0; i < WNMR * WNMR; i++)
{
Normals[i] = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
glBindTexture(GL_TEXTURE_2D, WaterNormalMap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_texture_max_anisotropy_ext);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WNMR, WNMR, 0, GL_RGBA, GL_FLOAT, Normals);
glGenerateMipmapEXT(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
delete [] Normals;
// ------------------------------------------------------------------------------------------------------------------------
glGenBuffers(1, &PoolSkyVBO);
float PoolSkyVertices[] =
{ // x, y, z, x, y, z, x, y, z, x, y, z
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, // +X
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, // -X
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // +Y
-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, // -Y
1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // +Z
-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f // -Z
};
glBindBuffer(GL_ARRAY_BUFFER, PoolSkyVBO);
glBufferData(GL_ARRAY_BUFFER, 288, PoolSkyVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// ------------------------------------------------------------------------------------------------------------------------
glGenBuffers(1, &WaterVBO);
int WMRP1 = WMR + 1;
vec3 *Vertices = new vec3[WMRP1 * WMRP1];
float WMSDWMR = 2.0f / (float)WMR;
for(int y = 0; y <= WMR; y++)
{
for(int x = 0; x <= WMR; x++)
{
Vertices[WMRP1 * y + x].x = x * WMSDWMR - 1.0f;
Vertices[WMRP1 * y + x].y = 0.0f;
Vertices[WMRP1 * y + x].z = 1.0f - y * WMSDWMR;
}
}
CBuffer Quads;
for(int y = 0; y < WMR; y++)
{
int yp1 = y + 1;
for(int x = 0; x < WMR; x++)
{
int xp1 = x + 1;
int a = WMRP1 * y + x;
int b = WMRP1 * y + xp1;
int c = WMRP1 * yp1 + xp1;
int d = WMRP1 * yp1 + x;
Quads.AddData(&Vertices[a], 12);
Quads.AddData(&Vertices[b], 12);
Quads.AddData(&Vertices[c], 12);
Quads.AddData(&Vertices[d], 12);
}
}
glBindBuffer(GL_ARRAY_BUFFER, WaterVBO);
glBufferData(GL_ARRAY_BUFFER, Quads.GetDataSize(), Quads.GetData(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
QuadsVerticesCount = Quads.GetDataSize() / 12;
Quads.Empty();
delete [] Vertices;
// ------------------------------------------------------------------------------------------------------------------------
glGenFramebuffersEXT(1, &FBO);
// ------------------------------------------------------------------------------------------------------------------------
Camera.Look(vec3(0.0f, 1.0f, 2.5f), vec3(0.0f, -0.5f, 0.0f), true);
// ------------------------------------------------------------------------------------------------------------------------
srand(GetTickCount());
// ------------------------------------------------------------------------------------------------------------------------
return true;
}
void COpenGLRenderer::Render(float FrameTime)
{
// add drops --------------------------------------------------------------------------------------------------------------
if(!Pause)
{
static DWORD LastTime = GetTickCount();
DWORD Time = GetTickCount();
if(Time - LastTime > 100)
{
LastTime = Time;
AddDrop(2.0f * (float)rand() / (float)RAND_MAX - 1.0f, 1.0f - 2.0f * (float)rand() / (float)RAND_MAX, 4.0f / 128.0f * (float)rand() / (float)RAND_MAX);
}
}
// update water surface ---------------------------------------------------------------------------------------------------
static DWORD LastTime = GetTickCount();
DWORD Time = GetTickCount();
if(Time - LastTime >= 16)
{
LastTime = Time;
// update water height map --------------------------------------------------------------------------------------------
glViewport(0, 0, WHMR, WHMR);
GLuint whmid = (WHMID + 1) % 2;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, WaterHeightMaps[whmid], 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[WHMID]);
glUseProgram(WaterHeightMapProgram);
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[whmid]);
glGenerateMipmapEXT(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
++WHMID %= 2;
// update water normal map --------------------------------------------------------------------------------------------
glViewport(0, 0, WNMR, WNMR);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, WaterNormalMap, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[WHMID]);
glUseProgram(WaterNormalMapProgram);
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_2D, WaterNormalMap);
glGenerateMipmapEXT(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
// render pool sky mesh ---------------------------------------------------------------------------------------------------
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&ProjectionMatrix);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&ViewMatrix);
if(WireFrame)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
glBindTexture(GL_TEXTURE_CUBE_MAP, PoolSkyCubeMap);
glUseProgram(PoolSkyProgram);
glBindBuffer(GL_ARRAY_BUFFER, PoolSkyVBO);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 12, (void*)0);
glDrawArrays(GL_QUADS, 0, 24);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glDisable(GL_CULL_FACE);
// render water surface ---------------------------------------------------------------------------------------------------
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[WHMID]);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, WaterNormalMap);
glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_CUBE_MAP, PoolSkyCubeMap);
glUseProgram(WaterProgram);
glUniform3fv(WaterProgram.UniformLocations[0], 1, &Camera.Position);
glBindBuffer(GL_ARRAY_BUFFER, WaterVBO);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 12, (void*)0);
glDrawArrays(GL_QUADS, 0, QuadsVerticesCount);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);
if(WireFrame)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
glDisable(GL_DEPTH_TEST);
}
void COpenGLRenderer::Resize(int Width, int Height)
{
this->Width = Width;
this->Height = Height;
ProjectionMatrix = perspective(45.0f, (float)Width / (float)Height, 0.125f, 512.0f);
ProjectionBiasMatrixInverse = inverse(ProjectionMatrix) * BiasMatrixInverse;
}
void COpenGLRenderer::Destroy()
{
PoolSkyCubeMap.Destroy();
WaterAddDropProgram.Destroy();
WaterHeightMapProgram.Destroy();
WaterNormalMapProgram.Destroy();
PoolSkyProgram.Destroy();
WaterProgram.Destroy();
glDeleteTextures(2, WaterHeightMaps);
glDeleteTextures(1, &WaterNormalMap);
glDeleteBuffers(1, &PoolSkyVBO);
glDeleteBuffers(1, &WaterVBO);
if(GLEW_EXT_framebuffer_object)
{
glDeleteFramebuffersEXT(1, &FBO);
}
}
void COpenGLRenderer::AddDrop(float x, float y, float DropRadius)
{
if(x >= -1.0f && x <= 1.0f && y >= -1.0f && y <= 1.0f)
{
glViewport(0, 0, WMR, WMR);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, WaterHeightMaps[(WHMID + 1) % 2], 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
glBindTexture(GL_TEXTURE_2D, WaterHeightMaps[WHMID]);
glUseProgram(WaterAddDropProgram);
glUniform1f(WaterAddDropProgram.UniformLocations[0], DropRadius);
glUniform2fv(WaterAddDropProgram.UniformLocations[1], 1, &vec2(x * 0.5f + 0.5f, 0.5f - y * 0.5f));
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();
glUseProgram(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
++WHMID %= 2;
}
}
void COpenGLRenderer::AddDropByMouseClick(int x, int y)
{
float s = (float)x / (float)(Width - 1);
float t = 1.0f - (float)y / (float)(Height - 1);
vec4 Position = ViewMatrixInverse * (ProjectionBiasMatrixInverse * vec4(s, t, 0.5f, 1.0f));
Position /= Position.w;
vec3 Ray = normalize(*(vec3*)&Position - Camera.Position);
vec3 Normal = vec3(0.0f, 1.0f, 0.0f);
float D = -dot(Normal, vec3(0.0f, 0.0f, 0.0f));
float NdotR = -dot(Normal, Ray);
if(NdotR != 0.0f)
{
float Distance = (dot(Normal, Camera.Position) + D) / NdotR;
if(Distance > 0.0f)
{
vec3 Position = Ray * Distance + Camera.Position;
AddDrop(Position.x, Position.z, DropRadius);
}
}
}
...
void COpenGLView::OnKeyDown(UINT Key)
{
switch(Key)
{
case VK_F1:
OpenGLRenderer.WireFrame = !OpenGLRenderer.WireFrame;
break;
case '1':
OpenGLRenderer.DropRadius = 4.0f / 256.0f;
break;
case '2':
OpenGLRenderer.DropRadius = 4.0f / 128.0f;
break;
case '3':
OpenGLRenderer.DropRadius = 4.0f / 64.0f;
break;
case '4':
OpenGLRenderer.DropRadius = 4.0f / 32.0f;
break;
case '5':
OpenGLRenderer.DropRadius = 4.0f / 16.0f;
break;
case VK_SPACE:
OpenGLRenderer.Pause = !OpenGLRenderer.Pause;
break;
}
}
void COpenGLView::OnLButtonDown(int X, int Y)
{
OpenGLRenderer.AddDropByMouseClick(X, Y);
}
...
wateradddrop.vs
#version 120
void main()
{
gl_TexCoord[0] = gl_Vertex;
gl_Position = gl_Vertex * 2.0 - 1.0;
}
wateradddrop.fs
#version 120
uniform sampler2D WaterHeightMap;
uniform float DropRadius;
uniform vec2 Position;
void main()
{
vec2 vh = texture2D(WaterHeightMap, gl_TexCoord[0].st).rg;
float d = distance(gl_TexCoord[0].st, Position);
gl_FragColor = vec4(vh.r, vh.g - 4.0f * max(DropRadius - d, 0.0), 0.0, 0.0);
}
waterheightmap.vs
#version 120
void main()
{
gl_TexCoord[0] = gl_Vertex;
gl_Position = gl_Vertex * 2.0 - 1.0;
}
waterheightmap.fs
#version 120
uniform sampler2D WaterHeightMap;
uniform float ODWHMR;
void main()
{
vec2 vh = texture2D(WaterHeightMap, gl_TexCoord[0].st).rg;
float force = 0.0;
force += 0.707107 * (texture2D(WaterHeightMap, gl_TexCoord[0].st - vec2(ODWHMR, ODWHMR)).g - vh.g);
force += texture2D(WaterHeightMap, gl_TexCoord[0].st - vec2(0.0, ODWHMR)).g - vh.g;
force += 0.707107 * (texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(ODWHMR, -ODWHMR)).g - vh.g);
force += texture2D(WaterHeightMap, gl_TexCoord[0].st - vec2(ODWHMR, 0.0)).g - vh.g;
force += texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(ODWHMR, 0.0)).g - vh.g;
force += 0.707107 * (texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(-ODWHMR, ODWHMR)).g - vh.g);
force += texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(0.0, ODWHMR)).g - vh.g;
force += 0.707107 * (texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(ODWHMR, ODWHMR)).g - vh.g);
force *= 0.125;
vh.r += force;
vh.g += vh.r;
vh.g *= 0.99;
gl_FragColor = vec4(vh, 0.0, 0.0);
}
waternormalmap.vs
#version 120
void main()
{
gl_TexCoord[0] = gl_Vertex;
gl_Position = gl_Vertex * 2.0 - 1.0;
}
waternormalmap.fs
#version 120
uniform sampler2D WaterHeightMap;
uniform float ODWNMR, WMSDWNMRM2;
void main()
{
float y[4];
y[0] = texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(ODWNMR, 0.0)).g;
y[1] = texture2D(WaterHeightMap, gl_TexCoord[0].st + vec2(0.0, ODWNMR)).g;
y[2] = texture2D(WaterHeightMap, gl_TexCoord[0].st - vec2(ODWNMR, 0.0)).g;
y[3] = texture2D(WaterHeightMap, gl_TexCoord[0].st - vec2(0.0, ODWNMR)).g;
vec3 Normal = normalize(vec3(y[2] - y[0], WMSDWNMRM2, y[1] - y[3]));
gl_FragColor = vec4(Normal, 1.0);
}
poolsky.vs
#version 120
void main()
{
gl_TexCoord[0].stp = vec3(gl_Vertex.x, -gl_Vertex.yz);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
poolsky.fs
#version 120
uniform samplerCube PoolSkyCubeMap;
void main()
{
gl_FragColor = textureCube(PoolSkyCubeMap, gl_TexCoord[0].stp);
}
water.vs
#version 120
uniform sampler2D WaterHeightMap;
varying vec3 Position;
void main()
{
gl_TexCoord[0].st = vec2(gl_Vertex.x * 0.5 + 0.5, 0.5 - gl_Vertex.z * 0.5);
Position = gl_Vertex.xyz;
Position.y += texture2D(WaterHeightMap, gl_TexCoord[0].st).g;
gl_Position = gl_ModelViewProjectionMatrix * vec4(Position, 1.0);
}
water.fs
#version 120
uniform sampler2D WaterNormalMap;
uniform samplerCube PoolSkyCubeMap;
uniform vec3 LightPosition, CubeMapNormals[6], CameraPosition;
varying vec3 Position;
vec3 IntersectCubeMap(vec3 Position, vec3 Direction)
{
vec3 Point;
for(int i = 0; i < 6; i++)
{
float NdotR = -dot(CubeMapNormals[i], Direction);
if(NdotR > 0.0)
{
float Distance = (dot(CubeMapNormals[i], Position) + 1.0) / NdotR;
if(Distance > -0.03)
{
Point = Direction * Distance + Position;
if(Point.x > -1.001 && Point.x < 1.001 && Point.y > -1.001 && Point.y < 1.001 && Point.z > -1.001 && Point.z < 1.001)
{
break;
}
}
}
}
return vec3(Point.x, -Point.yz);
}
void main()
{
vec3 Normal = normalize(texture2D(WaterNormalMap, gl_TexCoord[0].st).rgb);
vec3 Direction = normalize(Position - CameraPosition);
if(CameraPosition.y > 0)
{
vec3 ReflectedColor = textureCube(PoolSkyCubeMap, IntersectCubeMap(Position, reflect(Direction, Normal))).rgb;
vec3 RefractedColor = textureCube(PoolSkyCubeMap, IntersectCubeMap(Position, refract(Direction, Normal, 0.750395))).rgb;
vec3 LightDirectionReflected = reflect(normalize(Position - LightPosition), Normal);
float Specular = pow(max(-dot(Direction, LightDirectionReflected), 0.0), 128);
gl_FragColor.rgb = mix(ReflectedColor, RefractedColor, -dot(Normal, Direction)) + Specular;
}
else
{
Normal = -Normal;
vec3 ReflectedColor = textureCube(PoolSkyCubeMap, IntersectCubeMap(Position, reflect(Direction, Normal))).rgb;
vec3 DirectionRefracted = refract(Direction, Normal, 1.332631);
if(DirectionRefracted.x == 0.0 && DirectionRefracted.y == 0.0 && DirectionRefracted.z == 0.0)
{
gl_FragColor.rgb = ReflectedColor;
}
else
{
vec3 RefractedColor = textureCube(PoolSkyCubeMap, IntersectCubeMap(Position, DirectionRefracted)).rgb;
gl_FragColor.rgb = mix(ReflectedColor, RefractedColor, -dot(Normal, Direction));
}
}
}
Download
|