I’m trying to implement the ocean shader that comes with RenderMonkey (Reflections Refractions) in GLSL and have run into a couple of problems.
I’ve read through most of NVidia’s Cg Tutorial book but didn’t really like it so went on to read the OpenGL orange book (OpenGL Shading Language). It’s a great book but it doesn’t give anywhere near enough details on how to actually implement shaders. In the end, I learnt how to implement shaders from the tutorials on lighthouse3d.com.
Anyway, I think I’ve implemented everything correctly apart from two uniform variables. One is a sampler3D, to deal with the noise and one is a samplerCube, which is the texture being used for the sky box. Unfortunately, on lighthouse3d.com, there are no explanations detailing how to implement sampler3D or samplerCube so I was hoping someone could help me out.
Firstly, the vertex shader looks like this:
uniform vec4 view_position;
uniform vec4 scale;
varying vec3 vTexCoord;
varying vec3 vNormal;
varying vec3 vViewVec;
void main(void)
{
vec4 Position = gl_Vertex.xyzw;
// Get some size on the water
Position.xy *= 1000.0;
Position.z = -30.0;
vTexCoord = Position.xyz * scale.xyz;
vViewVec = Position.xyz - view_position.xyz;
vViewVec.z *=1.0;
vNormal = gl_Normal;
gl_Position = gl_ModelViewProjectionMatrix * Position;
}
And the fragment shader looks like this:
uniform sampler3D Noise;
uniform samplerCube skyBox;
uniform float time_0_X;
uniform vec4 waterColor;
uniform float fadeExp;
uniform float fadeBias;
uniform float noiseSpeed;
uniform vec4 scale;
uniform float waveSpeed;
varying vec3 vTexCoord;
varying vec3 vNormal;
varying vec3 vViewVec;
void main(void)
{
vec3 tcoord = vTexCoord;
tcoord.x += waveSpeed * time_0_X;
tcoord.z += noiseSpeed * time_0_X;
vec4 noisy = texture3D(Noise, tcoord);
// Signed noise
vec3 bump = 2.0 * noisy.xyz - 1.0;
bump.xy *= 0.15;
// Make sure the normal always points upwards
bump.z = 0.8 * abs(bump.z) + 0.2;
// Offset the surface normal with the bump
bump = normalize(vNormal + bump);
// Find the reflection vector
vec3 reflVec = reflect(vViewVec, bump);
vec4 refl = textureCube(skyBox, reflVec.yzx);
float lrp = 1.0 - dot(-normalize(vViewVec), bump);
// Interpolate between the water color and reflection
gl_FragColor = mix(waterColor, refl, clamp(fadeBias + pow(lrp, fadeExp),0.0, 1.0));
}
This is what I have so far:
#ifdef WIN32
#include <windows.h>
#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "GlU32.lib")
#pragma comment(lib, "SDL.lib")
#pragma comment(lib, "SDLmain.lib")
#pragma comment(lib, "glew32.lib")
#endif
#include <iostream>
#include "glew.h"
#include "SDL.h"
#include "textfile.h"
GLhandleARB p,f,v;
void PrintInfoLog(GLhandleARB obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
printf("%s
",infoLog);
free(infoLog);
}
}
void SetShaders() {
char *vs, *fs;
v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
vs = textFileRead("Ocean.vert");
fs = textFileRead("Ocean.frag");
const char *vv = vs;
const char *ff = fs;
glShaderSourceARB(v, 1, &vv, NULL);
glShaderSourceARB(f, 1, &ff, NULL);
free(vs);
free(fs);
glCompileShaderARB(v);
glCompileShaderARB(f);
PrintInfoLog(v);
PrintInfoLog(f);
p = glCreateProgramObjectARB();
glAttachObjectARB(p,v);
glAttachObjectARB(p,f);
glLinkProgramARB(p);
PrintInfoLog(p);
glUseProgramObjectARB(p);
GLint loc1, loc2, loc3, loc4, loc5, loc6, loc7, loc8;
float view_position[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float scale[4] = {0.01001f, 0.00554f, 0.01f, 1.0f};
float time_0_X = 0.0f;
float waterColor[4] = {0.195489f, 0.345865f, 0.684210f, 1.0f};
float fadeExp = 6.08f;
float fadeBias = 0.3f;
float noiseSpeed = 0.18f;
float waveSpeed = 0.34f;
loc1 = glGetUniformLocationARB(p, "view_position");
glUniform4fARB(loc1, view_position[0], view_position[1], view_position[2], view_position[3]);
loc2 = glGetUniformLocationARB(p, "scale");
glUniform4fARB(loc2, scale[0], scale[1], scale[2], scale[3]);
loc3 = glGetUniformLocationARB(p, "time_0_X");
glUniform1fARB(loc3, time_0_X);
loc4 = glGetUniformLocationARB(p, "waterColor");
glUniform4fARB(loc4, waterColor[0], waterColor[1], waterColor[2], waterColor[3]);
loc5 = glGetUniformLocationARB(p, "fadeExp");
glUniform1fARB(loc5, fadeExp);
loc6 = glGetUniformLocationARB(p, "fadeBias");
glUniform1fARB(loc6, fadeBias);
loc7 = glGetUniformLocationARB(p, "noiseSpeed");
glUniform1fARB(loc7, noiseSpeed);
loc8 = glGetUniformLocationARB(p, "waveSpeed");
glUniform1fARB(loc8, waveSpeed);
}
bool SetupEnvironment() {
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return false;
if (SDL_SetVideoMode(800, 600, 16, SDL_OPENGL | SDL_DOUBLEBUF | SDL_HWSURFACE) == 0)
return false;
SDL_WM_SetCaption("Shader Test", NULL);
glViewport(0, 0, 800, 600);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 800.0f / 600.0f, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glShadeModel(GL_SMOOTH);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glewInit();
if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
std::cout << "Ready for GLSL.
";
else {
std::cout << "Cannot use shaders.
";
SDL_Quit();
}
SetShaders();
return true;
}
int main(int argc, char **argv) {
if (!SetupEnvironment()) {
std::cout << "Unable to setup the environment: " << SDL_GetError() << "
";
SDL_Quit();
}
bool running = true;
SDL_Event event;
while (running) {
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE)
running = false;
break;
default:
break;
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, 0.0);
glPushMatrix();
glBegin(GL_QUADS);
glVertex3f(5.0f, -1.0f, 3.0f);
glVertex3f(5.0f, -1.0f, -7.0f);
glVertex3f(-5.0f, -1.0f, -7.0f);
glVertex3f(-5.0f, -1.0f, 3.0f);
glEnd();
glPopMatrix();
SDL_GL_SwapBuffers();
}
return 0;
}
Also, I’d appreciate it if anyone could point out any omissions that I have made.