Trouble implementing RenderMonkey's ocean shader

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.

I haven’t read through all your code, but here is how to set the sampler uniforms.

You have to bind the texture to some texture unit, and then you set the uniform to the number of the texture unit like it was an integer uniform:

/* load texture object in texture unit 0 */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, noiseTexture);

/* bind texture unit 0 to uniform "Noise" */
loc = glGetUniformLocationARB(p, "Noise");
glUniform1iARB(loc, 0);

/* same for the other texture in unit 1 */
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyBox);
loc = glGetUniformLocationARB(p, "skyBox");
glUniform1iARB(loc, 1);

Also, the ARB GLSL functions are deprecated. You should use the new core functions of OpenGL 2.0.

The main difference in the API is that there is no handle datatype, shaders and programs now use the same integer naming scheme like textures. Also, you can use GLSL 1.1.

Thanks for the info. I think I’m now implementing all the uniform variables correctly but nothing is being displayed. I’m obviously missing something. Please help, it’s driving me scatty, I’ve been trying to get this bugger to work for a week!

This is what I’ve got, now:

#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")
#pragma comment(lib, "DevIL.lib")
#endif

#include <iostream>
#include "glew.h"
#include "SDL.h"
#include <IL/il.h>

GLhandleARB p,f,v;
GLuint noiseTexture, skyBoxTexture;
ILuint noiseImage, skyBoxImage;

char *textFileRead(char *fn) {

	FILE *fp;
	char *content = NULL;

	int count=0;

	if (fn != NULL) {
		fp = fopen(fn,"rt");

		if (fp != NULL) {
      
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	return content;
}

int textFileWrite(char *fn, char *s) {

	FILE *fp;
	int status = 0;

	if (fn != NULL) {
		fp = fopen(fn,"w");

		if (fp != NULL) {
			
			if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s))
				status = 1;
			fclose(fp);
		}
	}
	return(status);
}

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, loc9, loc10;
	
	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 = 1.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);

	ilGenImages(1, &noiseImage);
	ilBindImage(noiseImage);
	ilLoadImage("NoiseVolume.dds");
	glGenTextures(1, &noiseTexture);
	glBindTexture(GL_TEXTURE_3D, noiseTexture);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexImage3D(GL_TEXTURE_3D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT), ilGetInteger(IL_IMAGE_DEPTH), 0, ilGetInteger(IL_IMAGE_FORMAT),
		GL_UNSIGNED_BYTE, ilGetData());

	ilGenImages(1, &skyBoxImage);
	ilBindImage(skyBoxImage);
	ilLoadImage("Snow.dds");
	glGenTextures(1, &skyBoxTexture);
	glBindTexture(GL_TEXTURE_CUBE_MAP, skyBoxTexture);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());

	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());

	glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());
	glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), 
		ilGetInteger(IL_IMAGE_HEIGHT),0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, ilGetData());

	glEnable(GL_TEXTURE_3D);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_3D, noiseTexture);
	loc9 = glGetUniformLocationARB(p, "Noise");
	glUniform1iARB(loc9, 0);

	glEnable(GL_TEXTURE_CUBE_MAP);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_CUBE_MAP, skyBoxTexture);
	loc10 = glGetUniformLocationARB(p, "skyBox");
	glUniform1iARB(loc10, 1);
}

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);

	glewInit();
	if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
		std::cout << "Ready for GLSL.
";
	else {
		std::cout << "Cannot use shaders.
";
		SDL_Quit();
	}

	ilInit();

	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);

		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();

		SDL_GL_SwapBuffers();
	}

	return 0;
}

No time to look at your code, but I may suggest you to use GLIntercept (http://glintercept.nutty.org) which may help you to locate occuring GL errors and to analyse the frame GL composition.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.