Skip to main content
gamedev.net
🔒 Locked

Reflections

Started by kaiser83 2 replies 1.1k views
Original Post
kaiser83
kaiser83
Hi - first post here :) I'm trying to render a simple planar reflection to a texture in opengl, but I'm facing problems with the texture coordinate projection. I'm not sure if I'm doing it right - also when I increase the number of subdivisions in the plane (WATER_PTS), it looks better, but I want to be able to do a reflection with a single quad (ie WATER_PTS = 2). Any help?

#include <gl/glut.h>

#define TEXTURE_SIZE 512
#define WATER_SIZE   10.0
#define WATER_PTS	 10
#define ROT_STEP	 0.5f

float rotx = 0.0f, roty = 0.0f, rotz = 0.0f;
float srotx = 10.0f, sroty = 10.0f, srotz = 0.0f;

float P[3] = {0.0f, 0.0f, 0.0f };
float V[3] = {0.0f, 1.0f, 0.0f };
float M[16];

struct Point{
	double x, y, z;
	double u, v;
};

Point water[WATER_PTS][WATER_PTS];

int win_h = 900, win_w = 600;
static unsigned char texture[3 * TEXTURE_SIZE * TEXTURE_SIZE];
static unsigned int texture_id;

void UpdateUVCoords()
{
	GLint viewport[4];
	GLdouble modelview[16];
	GLdouble projection[16];
	double X, Y, Z;

	glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
	glGetDoublev( GL_PROJECTION_MATRIX, projection );
	glGetIntegerv( GL_VIEWPORT, viewport );

	for(int i = 0; i < WATER_PTS; i++)
	{
		for(int j = 0; j < WATER_PTS; j++)
		{
			gluProject(water[j].x, water[j].y, water[j].z, modelview, projection, viewport, &X, &Y, &Z );
			water[j].u = X / win_w; 
			water[j].v = Y / win_h;
		}
	}
}

void GetReflectionMatrix(float*m, float*p, float* v)
{
	float vp = p[0] * v[0] + p[1] * v[1] + p[2] * v[2];

	m[0]  = 1.0f - 2.0f * v[0] * v[0];
	m[1]  = -2.0f * v[0] * v[1];
	m[2]  = -2.0f * v[0] * v[2];
	m[3]  = 0.0f;

	m[4]  = m[1];
	m[5]  = 1.0f - 2.0f * v[1] * v[1];
	m[6]  = -2.0f * v[1] * v[2];
	m[7]  = 0.0f;

	m[8]  = m[2];
	m[9]  = m[6];
	m[10] = 1.0f - 2.0f * v[2] * v[2];
	m[11] = 0.0f;

	m[12] = 2.0f * vp * v[0];
	m[13] = 2.0f * vp * v[1];
	m[14] = 2.0f * vp * v[2];
	m[15] = 1.0f;
}

void DrawCube(float r, float g, float b)
{
	glDisable(GL_TEXTURE_2D);
	glPushMatrix();
		glTranslatef(0.0f,1.0f,0.0f);
		glRotatef(rotx,1,0,0);
		glRotatef(roty,0,1,0);
		glRotatef(rotz,0,0,1);
		glColor3f(r,g,b);
		glutSolidCube(1);
	glPopMatrix();
	glEnable(GL_TEXTURE_2D);
}

void DrawWater()
{
	glColor3f(1,1,1);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture_id);
	for(int i = 0; i < WATER_PTS - 1; i++)
	{
		glBegin(GL_QUAD_STRIP);
			for(int j = 0; j < WATER_PTS; j++)
			{
				glNormal3d(0.0, 1.0, 0.0);
				glTexCoord2f(water[j].u, water[j].v);
				glVertex3f(water[j].x, water[j].y, water[j].z);
				glTexCoord2f(water[i+1][j].u, water[i+1][j].v);
				glVertex3f(water[i+1][j].x, water[i+1][j].y, water[i+1][j].z);
			}
		glEnd();
	}
	glDisable(GL_TEXTURE_2D);
}

bool init(void)
{
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	GetReflectionMatrix(M, P, V);

	glEnable (GL_TEXTURE_2D);
	glGenTextures (1, &texture_id);
	glBindTexture (GL_TEXTURE_2D, texture_id);
	glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	double step = WATER_SIZE / (WATER_PTS - 1);
	for(int i = 0; i < WATER_PTS; i++)
	{
		for(int j = 0; j < WATER_PTS; j++)
		{
			water[j].x = -WATER_SIZE + 2 * i * step;
			water[j].y = 0.0;
			water[j].z = -WATER_SIZE + 2 * j * step;
		}
	}
	return true;
}

void render(void)   
{
	glPushMatrix();
		
		glTranslatef(0.0f, 0.0f, -10.0f);
		glRotatef(srotx,1,0,0);
		glRotatef(sroty,0,1,0);
		glRotatef(srotz,0,0,1);

		glPushMatrix();
			glMultMatrixf(M);
			glViewport(0, 0, TEXTURE_SIZE, TEXTURE_SIZE);
			glClearColor (0, 0, 1, 1);
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			DrawCube(1,0,0);
			glEnable(GL_TEXTURE_2D);
			glBindTexture (GL_TEXTURE_2D, texture_id);
			glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEXTURE_SIZE, TEXTURE_SIZE);
			glDisable(GL_TEXTURE_2D);
		glPopMatrix();

		glViewport(0, 0, win_w, win_h);
		glMatrixMode(GL_MODELVIEW);
		glClearColor (0.8, 0.8, 0.8, 1);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		DrawCube(0,1,0);
		UpdateUVCoords();

		DrawWater();

	glPopMatrix();

    glutSwapBuffers();
}

void reshape(int w, int h)
{
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (h == 0) h = 1;
	gluPerspective(45, (float)w/(float)h, 1.0, 5000.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	win_w = w;
	win_h = h;
}

void key(unsigned char key, int x, int y)
{
	switch(key){
		case ',':
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			glLineWidth(4.0f);
			break;
		case '.':
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			glLineWidth(1.0f);
			break;
		case 'o':
			exit(0);
			break;
		case 'q':
			rotx+= ROT_STEP;
			break;
		case 'Q':
			rotx-= ROT_STEP;
			break;
		case 'a':
			roty+= ROT_STEP;
			break;
		case 'A':
			roty-= ROT_STEP;
			break;
		case 'z':
			rotz+= ROT_STEP;
			break;
		case 'Z':
			rotz-= ROT_STEP;
			break;
		case 'w':
			srotx+= ROT_STEP;
			break;
		case 'W':
			srotx-= ROT_STEP;
			break;
		case 's':
			sroty+= ROT_STEP;
			break;
		case 'S':
			sroty-= ROT_STEP;
			break;
		case 'x':
			srotz+= ROT_STEP;
			break;
		case 'X':
			srotz-= ROT_STEP;
			break;

	}
	glutPostRedisplay();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowSize(win_h, win_w);
	glutCreateWindow("Reflection Test"); 
	init();
	glutDisplayFunc(render);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(key);
	glutMainLoop();
	return 0;
}


kaiser83
kaiser83
sorry i forgot to add screenshots
here's the reflection with a 10x10 grid for the water



and here's it at 100x100



thanks for any replies
JvdWulp
JvdWulp
Hi,

Any luck yet?

I recall the fly3d engine calculating the amount of vertexes used for the mirror based on the camera distance. So the closer the camera the more vertexes.

However if you got close to the mirror you could still see some minor distortions in the reflection.

So maybe it helps to do it that way too.

- Jaap
ajm113
ajm113
Did you try videotutorialsrock.com?

They got free source code and video on this, that mite help you.

Tutorial

I am not trying to spam, but I got some resources on more OpenGL listed in my search engine.
OpenGL search
Check out my open source code projects/libraries! My Homepage You may learn something.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.