PDA

View Full Version : Surfaces

Corrail
04-06-2002, 09:07 AM
Hi all!

I've a problem. You all know the Tutorial with Heightfield Terrain while using a Bitmap-File.
I want to make this code better while taking no triangles. I want to bulit the terrain by using Surfaces. I always take 3x3 points which describe my Surface.
So, now my problem: When I'm using GL_AUTO_NORMAL the lightning isn't correct because of all some points use other tangents.

How can I make the lightning here correct? I tried it by using my own normals but it didn't work!

Thanks for every help!!
greets, Corrail

Here my code I'm using:
(If you want the whole Source-Code pls Mail me! corrail@gmx.at)

///////////////////////
// Terrain Variables //
///////////////////////

#define MAPX 31
#define MAPZ 31
#define BitMAPX 32
#define BitMAPZ 32
#define MAPScale 20.0f

float terPkt[MAPX][MAPZ][3];

float terAktPkt[3][3][3];

///////////////////////
// InitializeTerrain //
///////////////////////
// ImageData is the black-white Image

void InitializeTerrain()
{

for (int i = 0; i < MAPZ; i++)
{
for (int j = 0; j < MAPX; j++)
{

terPkt[j][0] = float(i)*MAPScale;
terPkt[j][i][1] = (float)imageData[(j*BitMAPZ+i)*3];
terPkt[j][i][2] = -float(j)*MAPScale;

terNorm[j][i][0] = 0.0f;
terNorm[j][i][1] = 0.0f;
terNorm[j][i][2] = 0.0f;

}
}
}

///////////////////////
// Rendering Terrain //
///////////////////////

glFrontFace(GL_CW);

for (int a = 0; a < (int)((MAPX-1)/2); a++)
{
for (int b = 0; b < (int)((MAPZ-1)/2); b++)
{
for (int c = 0; c < 3; c++)
{
for (int d = 0; d < 3; d++)
{
terAktPkt[c][d][0] = terPkt[2*a+c][2*b+d][0];
terAktPkt[c][d][1] = terPkt[2*a+c][2*b+d][1];
terAktPkt[c][d][2] = terPkt[2*a+c][2*b+d][2];
}
}

glColor3f(1.0,1.0,1.0);
glMap2f(GL_MAP2_VERTEX_3, 0.0, count, 3, 3, 0.0, count, 9, 3, &terAktPkt[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);

glMapGrid2f((int)count, 0.0f, count, (int)count, 0.0f, count);
glEvalMesh2(GL_FILL, 0, (int)count, 0, (int)count);

}
}

glFrontFace(GL_CCW);

Rob The Bloke
04-07-2002, 01:32 AM
Using 3x3 patches will not give you surface continuity. Using patches for that matter will not give you continuity either for that matter. This is the fundamental problem with bezier patches and openGL's implimentation of them.

The only way you can do it is to tessellate the surface yourself and use a b-spline basis for the surfaces; or tessellate them yourself using the bezier basis and fix the normals yourself so that they work.

I suppose you could use 4x4 patches and fix the positions of the central 4 points so that they maintain continuity between neihgbouring patches, but that wont be pleasant.

Corrail
04-07-2002, 02:00 AM
Thanks, I thought that... http://www.opengl.org/discussion_boards/ubb/biggrin.gif

But how can I calculate the normals myself and, what is more important, how can I use them with bezier surfaces? Do I have to calculate the normals of each quad in my 3x3 surface or only for the four corner point?

Rob The Bloke
04-07-2002, 02:56 AM
Run a search on this and the advanced forum, I've actually gone into loads of detail in the past that should answer most questions you may have.

Calculating a bezier curve can be done with :

Q(t) = (1-t)^3*P1 + 3*(1-t)^2*t*P2 + 3*(1-t)*t^2*P3 + t^3*P4

where P1 - P4 are the four control points and Q(t) is the final point; and t varies between 0 and 1.

tessellating a bezier patch involves calculating the points on the four curves going in one direction, and then using those points to form control points for curves in the other direction. This should give you your vertices of the patch.

To get the normals, differentiate the bezier equation to get an equation that represents the rate of change of the curve. By calculating the rate of change of U & V directions, you'll get two tangents. Do a cross product of those to get the normal at that point on the surface.

Having calculated the normals for each patch, you'll then have to average them to get them to maintain surface continuity.

The other way of doing it is to presume that du/dt and dv/dt can be approximated by subtracting neighbouring vertices and use those values (with a couple of hacks) to do the cross product to calculate the normals. Faster, but not as elegant.

Thirdly, use NURBS surfaces which have the benefit of surface continuity inherant in their structure, and the calculation required for any single point is always identical, no matter how many control points you add, but you'll need some slightly more hectic maths.

Check out quite a few of the papers on www.gamasutra.com (http://www.gamasutra.com) on the subject of bezier patches for more info.

gumby
04-07-2002, 07:05 AM
Rather than taking the derivative, and doing a cross product for every point, you can generate a degree 5x5 path that represents the normals. The derivative (wrt u) of the bicubic patch is degree 2x3 patch where the control points have been differenced in one direction. Crossing the 2X3 with the 3x2 patch gives a 5x5 patch which can be evaluated to give you the normals of the 3x3 patch at the same u,v coord.

[This message has been edited by gumby (edited 04-07-2002).]