Jump to content
  • Advertisement
Sign in to follow this  
kaiser83

OpenGL Reflections

This topic is 3738 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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


Share this post


Link to post
Share on other sites
Advertisement
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!