Abnormals normals

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Oddmonger
Posts: 24
Joined: Tue Oct 04, 2005 7:01 pm
Location: Near Paris

Abnormals normals

Post by Oddmonger »

Well, hello everyone.

I tried to compute normals on a small object (a pyramid).
The results are strange, when i turn on "normals display" in debug mode.

I got this:
Image



Hmmm strange normals.. i wrote some code to display normals my own way. Here it is:
Image
the small lines attached to the edges of the pyramid are my normals.

Let's face it. I'm dazed and confused (i should have set my color background as deep purple).

Here is the code :

Code: Select all

/* pyramid with computed normals */

#include <irrlicht.h>

irr::IrrlichtDevice *device=0;
irr::video::IVideoDriver *driver=0;
irr::scene::ISceneManager *scenemgr=0;
irr::scene::ICameraSceneNode *cam=0;

irr::scene::SMesh *mesh_pyramid=0;
irr::scene::ISceneNode *mesh_scenenode=0; 


irr::scene::SMesh * create_mesh(float scale_x,float scale_y,float scale_z)
{
  irr::scene::SMesh *mesh; //le mesh
  irr::scene::SMeshBuffer *mesh_buffer; //son buffer

  mesh = new irr::scene::SMesh();
  mesh_buffer = new irr::scene::SMeshBuffer();

  irr::f32 cubeSize = 5.f;
  irr::video::SColor colour(255,255,0,0);

#define NB_INDICES 18
   irr::u16 indices[NB_INDICES] = { 0,1,3, 1,2,3, 3,4,0, 2,4,3, 1,4,2, 0,4,1 };

   mesh_buffer->Indices.set_used(NB_INDICES);
   for (irr::s32 i=0; i<NB_INDICES; ++i)
     mesh_buffer->Indices[i] = indices[i];

   //S3DVertex: pos(x,y,z) normal(x,y,z) color(c) texture_coords(u,v)
   //only vertices position are defined, normals will be computed later...
   mesh_buffer->Vertices.set_used(5);
   mesh_buffer->Vertices[0]  = irr::video::S3DVertex(-.5,0,-.5,  0,0,0, colour, 0, 1);
   mesh_buffer->Vertices[1]  = irr::video::S3DVertex( .5,0,-.5,  0,0,0, colour, 1, 1);
   mesh_buffer->Vertices[2]  = irr::video::S3DVertex( .5,0, .5,  0,0,0, colour, 1, 0);
   mesh_buffer->Vertices[3]  = irr::video::S3DVertex(-.5,0, .5,  0,0,0, colour, 0, 0);
   mesh_buffer->Vertices[4]  = irr::video::S3DVertex(  0,1,  0,  0,0,0, colour, 0, 0); //normal OK

   //now that we've defined vertices, we get their buffer, and recompute their normals.
   // vertice[4] is the top of the pyramid, vertices 1,2,3,4 are the base of the prism.
   irr::video::S3DVertex *vertice = (irr::video::S3DVertex *)mesh_buffer->getVertices();
   irr::core::vector3df normal;
   
   normal =  (vertice[4].Pos - vertice[1].Pos).crossProduct ((vertice[0].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[0].Normal = normal;
   
   normal =  (vertice[4].Pos - vertice[2].Pos).crossProduct ((vertice[1].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[1].Normal = normal;
   
   normal =  (vertice[4].Pos - vertice[3].Pos).crossProduct ((vertice[2].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[2].Normal = normal;

   normal =  (vertice[4].Pos - vertice[0].Pos).crossProduct ((vertice[3].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[3].Normal = normal;
   //normals computing done.
  
   //the mesh buffer is now ready (bounding box is computed just after assignation)
   mesh->addMeshBuffer(mesh_buffer);

   //recalculate bounding box
   for (int j=0; j<mesh->MeshBuffers.size(); ++j) 
      ((irr::scene::SMeshBuffer*)mesh->MeshBuffers[j])->recalculateBoundingBox(); 
   mesh->recalculateBoundingBox();

   return mesh;
}


//the draw of the normals in Irrlicht seems weird to me.
//i want to display normals my own way.
static void draw_my_normals()
{
  irr::scene::SMeshBuffer *mesh_buffer; //pyramid mesh buffer

  //when you do getMeshBuffer, you have to pass the *index* of mesh buffer.
  //usually, it's "0"
  mesh_buffer = (irr::scene::SMeshBuffer *) mesh_pyramid->getMeshBuffer(0);
  irr::video::S3DVertex *vertice = (irr::video::S3DVertex *)mesh_buffer->getVertices();

  for (int i=0; i<5; i++) {
    driver->draw3DLine(vertice[i].Pos, vertice[i].Pos + vertice[i].Normal); 
  }

}


static void start_irr()
{
  device = irr::createDevice(irr::video::EDT_OPENGL, irr::core::dimension2d<irr::s32>(800,600), 32 );
  if (!device) { printf("impossible de créer le device!\n"); exit(0); }
  device->setWindowCaption(L"Pyramid");

  driver = device->getVideoDriver();
  if (!driver) printf("Erreur driver\n");

  scenemgr = device->getSceneManager();

  mesh_pyramid = create_mesh(1.0f,1.0f,2.0f);
  mesh_scenenode = scenemgr->addMeshSceneNode(mesh_pyramid);
  mesh_scenenode->setPosition(irr::core::vector3df(0,0,1) );
  mesh_scenenode->setDebugDataVisible(irr::scene::EDS_FULL);

}

static void stop_irr()
{
  device->drop();
}

static void main_loop()
{
  irr::scene::ILightSceneNode *light=0;

  cam = scenemgr->addCameraSceneNodeFPS (0, 10.0f, .01f, 0, 0, 0, false);
  device->getCursorControl ()-> setVisible (false);

  scenemgr->addLightSceneNode(0,irr::core::vector3df(0,0,-10));

  
  while(device->run() && driver)
  {
    driver->beginScene(true, true, irr::video::SColor(255,0,0,255));
    scenemgr->drawAll();
    draw_my_normals(); //for debug purposes: draw the normals of the pyramid
    driver->endScene();
    device->sleep(20); 
  }
}


int main(void)
{
  start_irr();
  main_loop();
  stop_irr();
  return 0;
}


Thank you, and good night.
Oddmonger
Posts: 24
Joined: Tue Oct 04, 2005 7:01 pm
Location: Near Paris

a few details about my question.

Post by Oddmonger »

- Hey, it seems nobody replied to me.
- Yeah . Perhaps the question was not so obvious ?
- You're right dear me. Let's sum this up.
- Oh me, you're so smart.


Well, the question was:
is my normal computing done right ?

And, another one:
why the display of the normal with irrlicht's debug mode is not the same that my own normal display ?

For the first question, here is a little drawing for helping the representation of my pyramid.

Image



And here is the part of my code which do the normals computing (taken from the listing above):

mesh_buffer hold the datas of my mesh, and is defined just before. The normals in the mesh buffer are not defined during initialisation (they are at (0,0,0) value).

Code: Select all

irr::video::S3DVertex *vertice = (irr::video::S3DVertex *)mesh_buffer->getVertices();
   irr::core::vector3df normal;
   
   normal =  (vertice[4].Pos - vertice[1].Pos).crossProduct ((vertice[0].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[0].Normal = normal;
   
   normal =  (vertice[4].Pos - vertice[2].Pos).crossProduct ((vertice[1].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[1].Normal = normal;
   
   normal =  (vertice[4].Pos - vertice[3].Pos).crossProduct ((vertice[2].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[2].Normal = normal;

   normal =  (vertice[4].Pos - vertice[0].Pos).crossProduct ((vertice[3].Pos-vertice[4].Pos)) ;
   normal.normalize();
   vertice[3].Normal = normal;
   //normals computing done. 

Please help me.
I'm lost in the C ! :(
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Both normal groups are wrong. Moreover, you need separate normals for each face, because you want sharp edges. So it's a total of 12 normals. All of them should be perpendicular to the face they belong to, facing away from the visible side.
Oddmonger
Posts: 24
Joined: Tue Oct 04, 2005 7:01 pm
Location: Near Paris

Post by Oddmonger »

Hello,

Let's call "Irrlicht's normals representation in debug mode" BYA (i.e. big yellow arrow)

1) Why BYA aren't connected to the vertices of the pyramid ? They wander in the space, they should be connected to the matching vertex (even if the normal's computing is wrong.)

2) What do you call "normal groups" ?

Thank you.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

With groups I meant those from Irrlicht and those you have rendered. I don't know why the normals are rendered this way, it could be the rotation code used in the debug render setup.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

I think your normals are not drawn right because you don't set the tranformation matrix... :lol:

Code: Select all

static void draw_my_normals()
{
  irr::scene::SMeshBuffer *mesh_buffer; //pyramid mesh buffer

  //when you do getMeshBuffer, you have to pass the *index* of mesh buffer.
  //usually, it's "0"
  mesh_buffer = (irr::scene::SMeshBuffer *) mesh_pyramid->getMeshBuffer(0);
  irr::video::S3DVertex *vertice = (irr::video::S3DVertex *)mesh_buffer->getVertices();

// it's important to set the transformation !!!
driver->setTransform(video::ETS_WORLD, core::matrix4());

  for (int i=0; i<5; i++) {
    driver->draw3DLine(vertice[i].Pos, vertice[i].Pos + vertice[i].Normal);
  }

} 
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
Oddmonger
Posts: 24
Joined: Tue Oct 04, 2005 7:01 pm
Location: Near Paris

Post by Oddmonger »

Thanks for the answers.

I haven't thought i'd have to manipulate transformation matrix.
That's an interesting discovery :D
Matrix in Irrlicht seem to work the same way as OpenGL do (modelview, projection ..).

Doing the change in my code with adding

Code: Select all

driver->setTransform(video::ETS_WORLD, core::matrix4());
(before drawing my normals) brings some changes, not as expected, but that's another story :?

Now i'm going to try and calculate normals by face (each face will get its own vertices, as Hybrid said).
I still don't understand the Irrlicht's debug output for normals.
Post Reply