PDA

View Full Version : 3D object draw/hidden surfaces .....



Irena
02-07-2010, 02:46 PM
Hello,
I have a 3D object.
I draw it by drawing all its surfaces.The camera location
can be choosen randomly.(And the light sourse is place in rthe camera place)
How do I draw the surfaces correctly ?
Is the order of surfaces drawing important?
need draw them back to from probably according to the camera position or it is not important...?


thanks

Aleksandar
02-07-2010, 04:03 PM
The order is really relevant if your object is very complex and you are using fragment shaders that require significant amount of GPU shading unit time. Considering HyperZ or similar technologies, rendering should be done front to back (the opposite way you should expect).

But in your case, I guess that rendering order is totally irrelevant. Just enable depth test and everything will work fine.

In the scene preparation function just add

glEnable(GL_DEPTH_TEST);
and at the beginning of the drawing function clear depth buffer (along with frame buffer) with

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
After that you can freely draw in the order you want. ;)

P.S. Drawing may require polygon sorting if you want to implement some kind of transparency.

Irena
02-07-2010, 04:19 PM
Thank you for the answer!
The problem is that dispite the "light is placed in the camera"
The object drown ,looks like lighted from the side....

Aleksandar
02-08-2010, 03:27 AM
The problem can be in light position, but also in normals calculation.
If you want light source to be at the camera position, just set light source position at coordinates (0,0,0) after switching to modelview matrix and before the viewing transformation (for example, before gluLookAt).

Irena
02-08-2010, 05:34 AM
The problematic result,I get:
http://img17.imageshack.us/img17/1103/64347046.png

Aleksandar
02-08-2010, 08:32 AM
The light source is definitely not at the viewer position. Did you set light position at (0,0,0) in clip coordinates?

Irena
02-08-2010, 09:23 AM
yes.
I`ll be very thenkful if you could look at the code:


//Projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();


GLdouble diam = m_allModels.getDiam();
GLdouble left = m_allModels.getCenter()[0] - diam;
GLdouble right = m_allModels.getCenter()[0] + diam;
GLdouble bottom = m_allModels.getCenter()[1] - diam;
GLdouble top = m_allModels.getCenter()[1] + diam;


glFrustum(left,right,bottom,top,diam,diam*3.5);

//Model
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0.0, 0.0,2*m_allModels.getDiam(),
m_allModels.getCenter()[0],m_allModels.getCenter()[1],m_allModels.getCenter()[2],
0.0, 1.0, 0.0);

//Lighting
GLfloat light_position[] = {0.0, 0.0,0.0, 1.0 };
GLfloat white_light[] = { 0.7, 0.3, 0.2, 1.0 };
glEnable(GL_DEPTH_TEST);


glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT1, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, white_light);
glEnable(GL_LIGHT1);
glShadeModel(GL_FLAT);

//Draw
glEnable(GL_NORMALIZE);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//render here
for(unsigned int modelIdx = 0;modelIdx < m_allModels.zise();++modelIdx)
{
model curModel = m_allModels.getModel(modelIdx);
for(unsigned int modelSurfIdx = 0;modelSurfIdx <curModel.surfNum();
++modelSurfIdx)
{
surface curSurf = curModel.getSurface(modelSurfIdx);
glLineWidth(2);
glBegin( GL_POLYGON );


glNormal3f(curSurf.getN_x(),curSurf.getN_y(),curSu rf.getN_z());
for(unsigned int vertIdx = 0;vertIdx< curSurf.size();++vertIdx)
{
unsigned int curVertIdx = curSurf.getSurfVertices()[vertIdx];
vertex curVert = curModel.getVertex(curVertIdx);
glVertex3f((GLfloat)curVert.getX(),(GLfloat)curVer t.getY(),(GLfloat)curVert.getZ());
}
glEnd();

}
}

Aleksandar
02-08-2010, 09:56 AM
Than I don't have any idea. Post a code fragment where you set the light position.

Irena
02-08-2010, 10:02 AM
the code is added in the above post
thanks

Aleksandar
02-08-2010, 12:56 PM
You didn't obey my advice!
The light is not at the viewer's position.
Set light position to (0,0,0) before gluLookAt!

Irena
02-08-2010, 01:24 PM
It didn`t help....

Aleksandar
02-08-2010, 02:31 PM
You didn't get it again. :(
Hm...
You should write something like this:


glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//---------------------------
GLfloat light_position[] = {0.0, 0.0,0.0, 1.0 };
GLfloat white_light[] = { 0.7, 0.3, 0.2, 1.0 };
glLightfv(GL_LIGHT1, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, white_light);
//---------------------------
gluLookAt (...);

You have probably changed the position of this statement

GLfloat white_light[] = { 0.7, 0.3, 0.2, 1.0 };
which changes nothing!
It is important where you put this statement

glLightfv(GL_LIGHT1, GL_POSITION, light_position);

And, please, remove glShadeModel(GL_FLAT); It makes lighting inadequate by disabling interpolation between vertices.

Irena
02-08-2010, 02:38 PM
No I changed/re-arranged the code placing light_position
as you said.

Any case it doesn`t change the result...

Aleksandar
02-08-2010, 02:41 PM
It should change. The position is quite different.
Post "the rearranged" code, please.

Irena
02-08-2010, 02:47 PM
glEnable(GL_DEPTH_TEST);

//projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

GLdouble diam = m_allModels.getDiam();
GLdouble left = m_allModels.getCenter()[0] - diam*1.5;
GLdouble right = m_allModels.getCenter()[0] + diam*1.5;
GLdouble bottom = m_allModels.getCenter()[1] - diam*1.5;
GLdouble top = m_allModels.getCenter()[1] + diam*1.5;


glFrustum(left,right,bottom,top,0.9,2*diam + 2);

//Lighting
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();


GLfloat light_position[] = {0.0,0.0,0.0, 1.0 };
GLfloat red_light[] = { 0.7, 0.3, 0.2, 1.0 };


glLightfv(GL_LIGHT1, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, red_light);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);


//model

gluLookAt (0.0,0.0,m_allModels.getCenter()[2]-diam - 1,
m_allModels.getCenter()[0],m_allModels.getCenter()[1],m_allModels.getCenter()[2],
0.0, 1.0, 0.0);



//Draw
glEnable(GL_NORMALIZE);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//render here

Aleksandar
02-08-2010, 03:37 PM
OK! We have eliminated the problem with the light position. Now it is at the right position. But there is still the problem with the normals, perhaps.
Take a look at the model. Some faces oriented "up" as well as some faces oriented "down" are equally lighted. Check the functions that calculate normals.

Irena
02-08-2010, 03:48 PM
I think the normals are computed correctly
(according to Hill`s book) the normal for the plane
(A,B,C)
A = sum((Y(i)-Y(i+1)*(Z(i)*Z(i+1))
etc...


//////////////////////////////////////////////////////////////////////////////
// Function name: setNormal //
// Input parametrs: //
// - vertexVector[vector<vertex>&amp;] :Vector of all vertices //
// Output parameters: //
// - none //
// Functionality: //
// Set Normal for the surface based on its vertexes //
//////////////////////////////////////////////////////////////////////////////
void surface::setNormal(vector<vertex>&amp; vertexVector)
{
unsigned int curVertIdx,nextVertIdx;
bool curVertFlag = false;

//Iterate all surface vertices
for(vector<unsigned int>::iterator vertSurfIt= m_surfVertices.begin();
vertSurfIt != m_surfVertices.end();++vertSurfIt)
{
//Set curVertIdx for the first vertex
if(!curVertFlag)
{
curVertIdx = *vertSurfIt;
curVertFlag = true;
}
//Set nextVertIdx for the not first vertex,update curVertIdx
//update the normal vector for the surface
else
{
nextVertIdx = *vertSurfIt;
normalUpdate(vertexVector,curVertIdx,nextVertIdx);
curVertIdx = nextVertIdx;
}
}
normalUpdate(vertexVector,curVertIdx,0);

}
//////////////////////////////////////////////////////////////////////////////
// Function name: normalUpdate //
// Input parametrs: //
// - vertexVector[vector<vertex>&amp;] : Vector of all vertices //
// - curVertIdx[unsigned int] : Current vertex index //
// - curVertIdx[unsigned int] : Next vertex index //
// Output parameters: //
// - none //
// Functionality: //
// Update the normal vector //
//////////////////////////////////////////////////////////////////////////////
void surface::normalUpdate(vector<vertex>&amp; vertexVector,unsigned int curVertIdx,
unsigned int nextVertIdx)
{
//Normal x part
n_x = n_x +
(vertexVector[curVertIdx].getY() - vertexVector[nextVertIdx].getY())*
(vertexVector[curVertIdx].getZ() + vertexVector[nextVertIdx].getZ());
//Normal y part
n_y = n_y +
(vertexVector[curVertIdx].getZ() - vertexVector[nextVertIdx].getZ())*
(vertexVector[curVertIdx].getX() + vertexVector[nextVertIdx].getX());
//Normal z part
n_z = n_z +
(vertexVector[curVertIdx].getX() - vertexVector[nextVertIdx].getX())*
(vertexVector[curVertIdx].getY() + vertexVector[nextVertIdx].getY());
}

MaxH
02-08-2010, 04:57 PM
I've been fooling around with your code by drawing a teapot instead of your object. I got the same results you did when I tried moving the glLightfv(.., light_position) command around. It didn't fix the lighting problem. What works for me is to put the light at the same location as the camera (first 3 values of LookAt). This only requires one line of code -

light_position[2] = m_allModels.getCenter()[2]-diam - 1;

Do this somewhere before the call to glLightfv(., light_position)

Irena
02-08-2010, 05:12 PM
I am afraid that may be the problem is in the
incorrect hidden surfaces removal and I have to use stencil test /or dot product of the vector from camera with the normal of surface plane /or the way I try to examine the depth is incorrect and I have to add some additional code....(whatever :confused:)

Any case,thank you very much for the answer,I`ll try as you said!!!!!!!!!!!!!

Irena
02-09-2010, 12:09 PM
I have found the reason for the error in the rendering image-the normals!!!!!!!!!
The way I was calculating them is by Martin Newell method.
But the problem is in the directions.So I tried to define correct directions by finding center of mass of the 3D object and the center of mass of each surface and findig the dot product between vector leading from center of mass of the surface with the normal to the surface.If it is negative the normal direction is corret else it has to be negated.
But this way is not optimal...Doesn`t work good for not convex
objects...
Will be very thankfull for some advices
(I don` want to use cross product ...)

rats_ogl
02-09-2010, 05:19 PM
And, please, remove glShadeModel(GL_FLAT); It makes lighting inadequate by disabling interpolation between vertices.
why do you said this? GL_FLAT does not disable interpolation between vertices, in fact it really permits to see if your normals are pointing correctly.it is a "sketching" manner to see your model.

Irena
02-10-2010, 01:09 AM
The GL_FLAT was not removed

Aleksandar
02-10-2010, 08:58 AM
why do you said this? GL_FLAT does not disable interpolation between vertices, in fact it really permits to see if your normals are pointing correctly.it is a "sketching" manner to see your model.

With flat shading, the color of one particular vertex of an independent primitive is duplicated across all the primitive&amp;#8217;s vertices to render that primitive.
With smooth shading, the color at each vertex is treated individually. For a polygon primitive, the colors for the interior of the polygon are interpolated between the vertex colors.

The provoking vertex of a primitive is the vertex that determines the constant primary and secondary colors when flat shading is enabled. In OpenGL, the provoking vertex for triangle, quad, line, and (trivially) point primitives is the last vertex used to assemble the primitive. The polygon primitive is an exception in OpenGL where the first vertex of a polygon primitive determines the color of the polygon, even if actually broken into triangles and/or quads. Since May 11th of the previous year, provoking vertex can be changed by using GL_EXT_provoking_vertex extension.

Even if all verices in the primitive share the same material properties and have the same normal (i.e. it is a flat surface), depending on the distance from the light and other parameters, flat shading will not give the same results as smooth, because the final color of the pixels are not interpolated across the primitive.

P.S. I'm glad that Irena is finally find the error, and that I'm right about the reason. ;)

Irena
02-11-2010, 02:09 PM
Aleksandar,
Thank you!!!!

May be you can advice me regarding the normal issue?
Thanks

Aleksandar
02-12-2010, 12:34 PM
I would like to help if I only know how. :)

Well your problem is how to determine front-facing side of the polygons. The best way is to keep order of specifying vertices consistent. Always draw vertices in the CCW direction (viewed from the outside). Try and check if it works.

Irena
02-12-2010, 01:25 PM
I get the mesh description from the file (PLG)
So the order (incinsistent) is already (pre)defined and I can`t know about the direction....

Aleksandar
02-12-2010, 02:11 PM
It is not very hard to determine the direction in which vertices are defined.
This is the code I'm using for determining orientation in 2D, where no is the number of vertices in the polygon

bool C3DB::CCW_Orientation()
{
double s = 0.0;
for(unsigned int i=0; i<no; i++)
{
s += ( (x[i%no] * y[(i+1)%no]) - (x[(i+1)%no] * y[i%no]) );
}
if( s >= 0 ) return true;
else return false;
}

It can be generalized for 3D also. Everything is much simpler for triangles only, and if you are using vector-product, but you said that this is prohibited.