Advertisement

reflections

Started by November 22, 2002 10:08 AM
83 comments, last by Crispy 22 years, 2 months ago
Ok, this is starting to feel embarrassing for me already, my not being able to grasp the thing. You both described rendering to texture exactly the way I''m doing it - unfortunately, calculating those texture coordinates is the one thing I''ve never done and, quite frankly, I''ve very little clue as to what you''re talking about. I know it''s my fault, but no one ever taught me OpenGL - there''s only what I''ve managed to pick up on the Web so far. To bring this thread closer to being closed, I''ll simply post some code here:

This is the render to texture version:

    glPushMatrix();    glScalef(1.0f, -1.0f, 1.0f);    glCullFace(GL_FRONT);    glEnable(GL_CULL_FACE);    glEnable(GL_DEPTH_TEST);    //bind the terrain texture    tc->Bind(HMAP_TX);    //need to inverse cull direction for the reflection    glCullFace(GL_FRONT);    //draws the terrain, filled tri''s, DRAW_EVERYTHING     //indicates that both the under and above water sectsions     //should be draw - no clip planes used so far     QUADTerrain->Draw(Frustum, DRAW_TEXTURE_FILL, DRAW_EVERYTHING);    glCullFace(GL_BACK);  glPopMatrix();  //take a snapshot  glViewport(0, 0, 512, 512);    glBindTexture(GL_TEXTURE_2D, ReflectionTx);    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 512, 512, 0);    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  glViewport(0 , 0, 800, 600);  //draw the terrain   tc->Bind(HMAP_TX);  QUADTerrain->Draw(Frustum, DRAW_TEXTURE_FILL, DRAW_EVERYTHING);  glBindTexture(GL_TEXTURE_2D, ReflectionTx);  glEnable(GL_BLEND);  glColor4f(1.0f, 1.0f, 1.0f, 0.4f);  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  //bla-bla bla-bla bla - no clue what goes here except for these 4 lines  glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  glTexGenf(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  //these lines are probably very incorrect...//glTexGenfv(GL_S, GL_TEXTURE_GEN_MODE, GLCamera->GetPosition());//glTexGenfv(GL_T, GL_TEXTURE_GEN_MODE, GLCamera->GetPosition());  //enabling these messes up the texture//glEnable(GL_TEXTURE_GEN_S);//glEnable(GL_TEXTURE_GEN_T);  //draw the water  glBegin(GL_POLYGON);    glTexCoord2f(1, 0);    glVertex3f(0, 20, 1024);    glTexCoord2f(0, 0);    glVertex3f(1024, 20, 1024);    glTexCoord2f(0, 1);    glVertex3f(1024, 20, 0);    glTexCoord2f(1, 1);    glVertex3f(0, 20, 0);  glEnd();  


And here''s the stencil version, this one''s a bit longer:

    //taken from NeHe''s reflections tutorial. as far as i   //understand this should represent the plane equation   //for the reflecting surface (which should be (0, 60, 0)),  //but then I get no reflection  double eqr[] = {0.0f, -1.0f, 0.0f, 0.0f};     glCullFace(GL_BACK);  tc->Bind(HMAP_TX);  //draws only the underwater part - no clip planes used so far  QUADTerrain->Draw(Frustum, DRAW_TEXTURE_FILL, DRAW_BELOW);  //render water surface to stencil  glColorMask(0, 0, 0, 0);  glEnable(GL_STENCIL_TEST);  glStencilFunc(GL_ALWAYS, 1, 0xffffffff);  glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);  glDisable(GL_DEPTH_TEST);  glEnable(GL_TEXTURE_2D);  tc->Bind(TX_WATER);  glBegin(GL_POLYGON);    glTexCoord2f(0, 0);    glVertex3f(0, 60, 0);    glTexCoord2f(0, 1);    glVertex3f(0, 60, 1024);    glTexCoord2f(1, 1);    glVertex3f(1024, 60, 1024);    glTexCoord2f(1, 0);    glVertex3f(1024, 60, 0);  glEnd();  glEnable(GL_DEPTH_TEST);  glColorMask(1, 1, 1, 1);  glStencilFunc(GL_EQUAL, 1, 0xffffffff);  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);  glEnable(GL_CLIP_PLANE0);  glClipPlane(GL_CLIP_PLANE0, eqr);  glPushMatrix();    glScalef(1.0f, -1.0f, 1.0f);    glCullFace(GL_BACK);    glEnable(GL_CULL_FACE);    glEnable(GL_DEPTH_TEST);    glClear(GL_DEPTH_BUFFER_BIT);    //mmkay - the messy part - according to vincoof''s instructions one part is missing here    glDepthFunc(GL_EQUAL);    glEnable(GL_BLEND);    glCullFace(GL_FRONT);    tc->Bind(HMAP_TX);    //draw the whole lot, although jsut drawing anything    //that remains above water level should suffice    QUADTerrain->Draw(Frustum, DRAW_TEXTURE_FILL, DRAW_EVERYTHING);    glCullFace(GL_BACK);  glPopMatrix();  glDisable(GL_CLIP_PLANE0);  glDisable(GL_STENCIL_TEST);  glDepthFunc(GL_LEQUAL);  glEnable(GL_TEXTURE_2D);  tc->Bind(TX_WATER);  glEnable(GL_BLEND);  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  glColor4f(1, 1, 1, .4);    glBegin(GL_POLYGON);    glTexCoord2f(0, 0);    glVertex3f(0, 60, 0);    glTexCoord2f(0, 1);    glVertex3f(0, 60, 1024);    glTexCoord2f(1, 1);    glVertex3f(1024, 60, 1024);    glTexCoord2f(1, 0);    glVertex3f(1024, 60, 0);  glEnd();  glDisable(GL_BLEND);  //draw everything above the water  tc->Bind(HMAP_TX);  QUADTerrain->Draw(Frustum, DRAW_TEXTURE_FILL, DRAW_ABOVE);  


RipTorn - maybe you wouldn''t mind sharing the part of your code where you calculate the tex coords (using glFrustum) - as I getmore idea of what''s really going on, I''ll try and optimize the thing. The whole concept isn''t at all that difficult - I understand how it works, but there''s those few things that just don''t make sense...

Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
You should set the viewport before you render into it, that is you should move the line glViewport(0, 0, 512, 512) to the beginning of this code sample.
Advertisement
The ready-to-use code sample for texture generation is the following :

  GLfloat s_plane[] = { .5f, 0, 0, -.5f };GLfloat t_plane[] = { 0, .5f, 0, -.5f };glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);glTexGenfv(GL_S, GL_EYE_PLANE, s_plane);glTexGenfv(GL_T, GL_EYE_PLANE, t_plane);glEnable(GL_TEXTURE_GEN_S);glEnable(GL_TEXTURE_GEN_T);  

Then don''t forget to disable GL_TEXTURE_GEN_S/T !
BTW, you don''t need to setup GL_R and GL_Q.
And you don''t need to call glTexCoord when you render your water surface if you enable GL_TEXTURE_GEN_S/T because the GL will ignore the coords you send in glTexCoord (except the Q coordinate maybe, if you use weird Q effects somewhere else in your graphics engine).
Here''s how I understand it:

GLfloat s_plane[] = { .5f, 0, 0, -.5f };

indicates that the texture should be mapped along the x axis, scaled by 2. I''ve no idea what the -0.5 does. Even though, unneccessary in this case, what do the q and r coordinates do?

Here''s what I cam up with, but it doesn''t work:

Empirical observation indicated that the texture was being scaled down by an enormous rate, hence I did my best to reverse the process:

GLfloat s_plane[] = { -1.0f/1024.0f, 0, 0, 0 };
GLfloat t_plane[] = { 0, 0, -1.0f/1024.0f, 0 };

where 1024 is the size of the quad the reflection is being mapped on.

So, I came to a conclusion that s and t are what are generally referred to as the u and v coordinates (yay!). In the meantime my browser was busy scouring the Web for a clear explanation on the use and full potential of glTexGen(). This is all that it came up with: one result.

Finally when I ran the program, the texture just moved away from there it should be (looking down moves it "away" and looking up moves it back towards the camera - this makes sense). However, why does it do that?

Crispy

"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
also, I seemed to notice you wern''t recalculating your frustum for each render, unless thats done in the render code.

v.good work though, your''ve done v.well so far, it''s just a matter of mapping the texture coords...



does this make it a bit easier to understand what you need to do to project the texture onto the water?

| - Project-X - my mega project.. big things comming soon - | - adDeath - an ad blocker I made - | - email me - |
as I''ve said before, you really need to just keep screwing about with it, fudging things, etc, until things start to look right... the texture matrix isn''t exactly an easy thing to visualalize how it is working...
Advertisement
Oops I''ve been a bit hurried.
Because your scene is more than likely displayed in a perspective frustum, yes you have to use the Q coordinate in the "eye plane" equation.
But if you''re in an orthographic view, you don''t need it.
RipTorn - your reply is very graphic - I enjoy the challenge - it''s one of those pictures you won''t forget - thanks. I found a paper on the subject - gonna read it when I get the time later tonight or tomorrow.

vincoof - figured out I have to use the q coordinate all by myself (well, actually, it just seems right - for no too apparent reason) - just don''t understand why the r coordinate is not required, yet... as I said - gonna do some reading first. Unfortunately this requires sorting out some awkward terms for me - such as world space vs homogenous space etc...

Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
Alright, I figured a solution that works for every kind of views (I mean, perspective) but uses all four texture coordinates.
The solution is simple : map the (xyzw) quadruplet of the vertices to the (strq) quadruplet for the texture coordinate, and project this (strq) quadruplet using the texture matrix.



The first step (map xyzw to strq) is really straight forward :

  // Setup texture coordinate equationsGLfloat	plane_s[] = { 1.f, 0, 0, 0 };GLfloat	plane_t[] = { 0, 1.f, 0, 0 };GLfloat	plane_r[] = { 0, 0, 1.f, 0 };GLfloat	plane_q[] = { 0, 0, 0, 1.f };glMatrixMode(GL_MODELVIEW);glPushMatrix();glLoadIdentity();glTexGenfv(GL_S, GL_EYE_PLANE, plane_s);glTexGenfv(GL_T, GL_EYE_PLANE, plane_t);glTexGenfv(GL_R, GL_EYE_PLANE, plane_r);glTexGenfv(GL_Q, GL_EYE_PLANE, plane_q);glPopMatrix();  

And you have also to setup the texture generation (that you''ve done already) :

  	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);	glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);	glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);	glEnable(GL_TEXTURE_GEN_S);	glEnable(GL_TEXTURE_GEN_T);	glEnable(GL_TEXTURE_GEN_R);	glEnable(GL_TEXTURE_GEN_Q);  

You may be wondering why I''m loading identity matrix into the modelview matrix ? Well, that''s because when you call glTexGenfv(GL_x, GL_EYE_PLANE, plane_x) the modelview matrix is inverted to get the eye plane. If you don''t load the identity matrix, the GL will invert the current modelview matrix and you won''t have the desired result.


And the second step (project the (strq) quadruplet using the texture matrix) consists in configuring the GL_TEXTURE matrix :

  glMatrixMode(GL_TEXTURE);glPushMatrix();glLoadIdentity();glTranslatef(.5f, .5f, 0);glScalef(.5f, .5f, 1.f);gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);glMatrixMode(GL_MODELVIEW);  

First we push the texture matrix because we want to be able to restore it later.
Then we load the identity and translate by (0.5,0.5) and scale by 0.5 because it sets the center of the texture to the (0.5,0.5) texture coordinate. Lots of texture techniques use that scheme because it maps the texture coordinates to the [-1,+1]x[-1,+1] range. instead of the [0,1]x[0,1] range.
Then I call gluPerspective to project the texture matrix ! That''s where the trick is : normally you call gluPerspective (or glFrustum) with the GL_PROJECTION matrix, but this time we use the incredibly flexible OpenGL matrix management to apply the same operation to the GL_TEXTURE matrix. Note that I used gluPerspective, but you may use different values for gluPerspective (and you may even call another perspective function such as glFrustum) that reflect your projection parameters.
(Hint: If you''re not sure about what parameters to send to gluPerspective, you can get the GL_PROJECTION matrix and multiply it to the GL_TEXTURE matrix directly instead. It''s a bit heavy but it''s safe)

Once this is called, you can render your water surface and texture coordinates will be projected correctly.

Finally you have to restore the GL state. At least you should call :

  // Restore the texture matrixglMatrixMode(GL_TEXTURE);glPopMatrix();glMatrixMode(GL_MODELVIEW);// Disable texture coordinate generationglDisable(GL_TEXTURE_GEN_S);glDisable(GL_TEXTURE_GEN_T);glDisable(GL_TEXTURE_GEN_R);glDisable(GL_TEXTURE_GEN_Q);  


That''s all. Well ... hum ... I mean ... if you have any questions feel free to ask.
I can also send you a little demo with source code if you wish.
I wouldnt mind a demo (thereisnocowlevel@hotmail.com)

This topic is closed to new replies.

Advertisement