Outline of an object.

hi!
I’m trying to draw outlines of objects in opengl.
can anybody point to an example or explanation for this?
thnx :slight_smile:

and if it helps - here’s a part of my code.
I also try to draw my objects not from glut but it doesn’t work:

glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT); // Render the mesh into the stencil buffer.

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
thick wireframe version.
glutWireSphere(5,9,9);
glStencilFunc(GL_NOTEQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glLineWidth(2);
glPolygonMode(GL_FRONT, GL_LINE);
glutWireSphere(5,9,9);
glLineWidth(1);

Sorta depends on what you mean by outline. If you want a toon-outline (which is more of a contour than a silhouette) the usual version is to just draw the backfacing polygons of the object in black with each vertex extruded “a bit” along the vertex-normal (depthwrites enabled). Then afterwards, draw fronfaces as usual with depthtest enabled. Or you can do it the other way around and gain the benefit of early z-reject - or if you only want the outline you can do a depth-only pass. If you want the strict line with the background, just do the same thing, but with no depth tests.

If you know danish :wink: - this is a description of the method: http://b0rken.dk/hornet/shaders/toon.html

 
/* silhouette.c - by Tom McReynolds, SGI */

/* Doing Silhouette Edges with stencil */

#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>

enum {
  CONE = 1
};

/* Draw a cone */
void
cone(void)
{
  glPushMatrix();
  glTranslatef(0.f, 0.f, -30.f);
  glCallList(CONE);
  glPopMatrix();
}

/* Draw a torus */
void
torus(void)
{
  glutSolidTorus(10., 20., 20, 20);
}

enum {
  SIL, OBJ, SIL_AND_OBJ, TOGGLE
};

int rendermode = OBJ;

void (*curobj) (void) = cone;

void 
menu(int mode)
{
  switch (mode) {
  case SIL:
  case OBJ:
  case SIL_AND_OBJ:
    rendermode = mode;
    break;
  case TOGGLE:
    if (curobj == cone)
      curobj = torus;
    else
      curobj = cone;
    break;
  }
  glutPostRedisplay();
}

int winWidth = 512;
int winHeight = 512;

/* used to get current width and height of viewport */
void
reshape(int wid, int ht)
{
  glViewport(0, 0, wid, ht);
  winWidth = wid;
  winHeight = ht;
  glutPostRedisplay();
}

GLfloat viewangle;

void
drawsilhouette(void)
{
  int i;

  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  glEnable(GL_STENCIL_TEST);
  glStencilFunc(GL_ALWAYS, 1, 1);
  glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  glDisable(GL_DEPTH_TEST);  /* so the depth buffer doesn't change */
  for (i = -1; i < 2; i += 2) {  /* set stencil around object */
    glViewport(i, 0, winWidth + i, winHeight);
    curobj();
  }
  for (i = -1; i < 2; i += 2) {
    glViewport(0, i, winWidth, winHeight + i);
    curobj();
  }

  /* cut out stencil where object is */
  glViewport(0, 0, winWidth, winHeight);
  glStencilFunc(GL_ALWAYS, 0, 0);
  curobj();

  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

  glStencilFunc(GL_EQUAL, 1, 1);

  glDisable(GL_LIGHTING);
  glColor3f(1.f, 0.f, 0.f);  /* draw silhouette red */
  glRotatef(-viewangle, 0.f, 1.f, 0.f);
  glRecti(-50, -50, 50, 50);
  glRotatef(viewangle, 0.f, 1.f, 0.f);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glDisable(GL_STENCIL_TEST);
}

void
redraw(void)
{
  /* clear stencil each time */
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

  glPushMatrix();
  glRotatef(viewangle, 0.f, 1.f, 0.f);

  switch (rendermode) {
  case SIL:
    drawsilhouette();
    break;
  case SIL_AND_OBJ:
    drawsilhouette();
    curobj();
    break;
  case OBJ:
    curobj();
    break;
  }

  glPopMatrix();
  glutSwapBuffers();
}

/* animate scene by rotating */
enum {
  ANIM_LEFT, ANIM_RIGHT
};
int animDirection = ANIM_LEFT;

void 
anim(void)
{
  if (animDirection == ANIM_LEFT)
    viewangle -= 1.f;
  else
    viewangle += 1.f;
  glutPostRedisplay();
}

/* ARGSUSED1 */
/* special keys, like array and F keys */
void 
special(int key, int x, int y)
{
  switch (key) {
  case GLUT_KEY_LEFT:
    glutIdleFunc(anim);
    animDirection = ANIM_LEFT;
    break;
  case GLUT_KEY_RIGHT:
    glutIdleFunc(anim);
    animDirection = ANIM_RIGHT;
    break;
  case GLUT_KEY_UP:
  case GLUT_KEY_DOWN:
    glutIdleFunc(0);
    break;
  }
}

/* ARGSUSED1 */
void 
key(unsigned char key, int x, int y)
{
  switch (key) {
  case 'a':
    viewangle -= 10.f;
    glutPostRedisplay();
    break;
  case 's':
    viewangle += 10.f;
    glutPostRedisplay();
    break;
  case '\033':
    exit(0);
  }
}

int picked_object;
int xpos = 0, ypos = 0;
int newxpos, newypos;
int startx, starty;

int
main(int argc, char **argv)
{
  static GLfloat lightpos[] =
  {25.f, 50.f, -50.f, 1.f};
  static GLfloat cone_mat[] =
  {0.f, .5f, 1.f, 1.f};
  GLUquadricObj *cone, *base;

  glutInit(&argc, argv);
  glutInitWindowSize(512, 512);
  glutInitDisplayMode(GLUT_STENCIL | GLUT_DEPTH | GLUT_DOUBLE);
  (void) glutCreateWindow("silhouette edges");
  glutDisplayFunc(redraw);
  glutKeyboardFunc(key);
  glutSpecialFunc(special);
  glutReshapeFunc(reshape);

  glutCreateMenu(menu);
  glutAddMenuEntry("Object", OBJ);
  glutAddMenuEntry("Silhouette Only", SIL);
  glutAddMenuEntry("Object and Silhouette", SIL_AND_OBJ);
  glutAddMenuEntry("Toggle Object", TOGGLE);
  glutAttachMenu(GLUT_RIGHT_BUTTON);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

  /* make display list for cone; for efficiency */

  glNewList(CONE, GL_COMPILE);
  cone = gluNewQuadric();
  base = gluNewQuadric();
  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  gluQuadricOrientation(base, GLU_INSIDE);
  gluDisk(base, 0., 15., 32, 1);
  gluCylinder(cone, 15., 0., 60., 32, 32);
  gluDeleteQuadric(cone);
  gluDeleteQuadric(base);
  glEndList();

  glMatrixMode(GL_PROJECTION);
  glOrtho(-50., 50., -50., 50., -50., 50.);
  glMatrixMode(GL_MODELVIEW);
  glutMainLoop();
  return 0;             /* ANSI C requires main to return int. */
}
 

Thanks but this is not exactly what i need.
for example, suppose you have a model of a man.
I want to be able to see the lines of his hands, legs… and so on. but ony the side which faces me without the lines in the back.
is it possible to do this?
thanks :slight_smile:

I may be able to help but I need more info:

-Is this a “toon” artistic type effect? or a serious CAD program type of effect?

  • Can we use shaders or are you limited to fixed function?

Originally posted by white skies:
Thanks but this is not exactly what i need.
for example, suppose you have a model of a man.
I want to be able to see the lines of his hands, legs… and so on. but ony the side which faces me without the lines in the back.
is it possible to do this?
thanks :slight_smile:

i dont understand. could you please explain it with some graphics?

Originally posted by sqrt[-1]:
[b]I may be able to help but I need more info:

-Is this a “toon” artistic type effect? or a serious CAD program type of effect?

  • Can we use shaders or are you limited to fixed function?[/b]
    I just looked at some screenshots from this CAD
    and i guess that this is what i need.

And I didn’t quite understand your second question… but i’m going to create all kinds of
objects and not just one, if that’s what you mean :slight_smile:

Originally posted by Stroma:
[quote]Originally posted by white skies:
Thanks but this is not exactly what i need.
for example, suppose you have a model of a man.
I want to be able to see the lines of his hands, legs… and so on. but ony the side which faces me without the lines in the back.
is it possible to do this?
thanks :slight_smile:

i dont understand. could you please explain it with some graphics?
[/QUOTE]is there any way to upload pictures?

is there any way to upload pictures?
http://www.imageshack.us/

Originally posted by Stroma:
[quote] is there any way to upload pictures?
http://www.imageshack.us/
[/QUOTE]ok.
Here’s a picture of what i have now.
http://img301.imageshack.us/img301/5926/aircraft6tb.jpg

I loaded an .obj file and now it seems fine except for one problem.
It draws the faces in the wrong order…

here’s a part of my code:

glPolygonMode(GL_FRONT, GL_LINE);
glLineWidth(2);
SetWireColor(1,1,1);
WireDraw(GL_POLYGON);
glLineWidth(1);
glPolygonMode(GL_FRONT, GL_FILL);
SetWireColor(0,0,0);
WireDraw(GL_POLYGON);

If anybody has a better way to hide the back faces and those which shouldn’t be visible or
can solve my problem, i’ll be most grateful :slight_smile:

maybe i should just shoot myself. :mad:
I use this algorithm for the red book for hidden line removal and yet it does not work well.

glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
SetWireColor(1,1,1);
glLineWidth(1);
WireDraw(GL_POLYGON);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(2.0, 2.0);
SetWireColor(0,0,0);
WireDraw(GL_POLYGON);
glDisable(GL_POLYGON_OFFSET_FILL);

is there something i’m missing?
do i have to disable/enable some stuff whene i use this?
can someone please point me to an code of a working example?

i’m going insane :frowning:

I didn’t quite understand, but maybe it:

 void RenderScene ()
{
  glDepthMask (1);
  glColorMask (1,1,1,1);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix ();  
  // <- set modelview matrix

  glPolygonMode (GL_FRONT, GL_FILL);
  glDepthFunc (GL_LESS);
  glDepthMask (1);
  glColorMask (0,0,0,0);
  DrawMesh (&mesh);

  glPolygonMode (GL_FRONT, GL_LINE);
  glDepthFunc (GL_LEQUAL);
  glDepthMask (0);
  glColorMask (1,1,1,1);
  DrawMesh (&mesh);

  glPopMatrix ();
  
  glutSwapBuffers ();
}


void Init ()
{
  glEnable (GL_DEPTH_TEST);
  glEnable (GL_CULL_FACE);
  glLineWidth (2.0);
  ...
}
 

I didn’t understand well what you need, but here is a suggestion that can help:

  1. render backface triangles as wireframe, but use “fat” lines (using glLineWidth & glEnable(GL_LINE_SMOOTH))
  2. render frontface tringles

yooyo

If I understand correctly, you want to draw the models in hidden line mode… as in AutoCAD. One way to do it is draw the model normally (usually in black or whatever your background clear color is). Next draw the model again in wireframe mode with Polygon offset. That way you will get the effect of hidden line removed model rendering.

Originally posted by Fastian:
If I understand correctly, you want to draw the models in hidden line mode… as in AutoCAD. One way to do it is draw the model normally (usually in black or whatever your background clear color is). Next draw the model again in wireframe mode with Polygon offset. That way you will get the effect of hidden line removed model rendering.
But this is exactly what i do (i think)!

SetWireColor(0,0,0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
WireDraw(GL_POLYGON);
glDisable(GL_POLYGON_OFFSET_FILL);
SetWireColor(1,1,1);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
WireDraw(GL_POLYGON);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

And this is the WireDraw function:

oid Face::WireDraw(int beginStyle)
{

vector &lt;int&gt;::iterator vertIt; // Vertices iterator.
//Only Wire.
glBegin(beginStyle);
//Loop over all the vertices in this face.
vertIt = m_vIndices.begin();
int size = OverallObject-&gt;m_verts.size(); //The overallObject holds the coordinates 
										  // and the rest of the data.
glColor3f (m_wireColor[0], m_wireColor[1], m_wireColor[2]);
while (vertIt !=m_vIndices.end())
{
	Vector3 Vec = (OverallObject-&gt;m_verts[*vertIt]).m_vec;
	glVertex3f(Vec.m_x,
			   Vec.m_y,
			   Vec.m_z);
	vertIt++;
}
glEnd();

}

:frowning:

Originally posted by white skies:
[b]But this is exactly what i do (i think)!

SetWireColor(0,0,0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
WireDraw(GL_POLYGON);
glDisable(GL_POLYGON_OFFSET_FILL);
SetWireColor(1,1,1);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
WireDraw(GL_POLYGON);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

And this is the WireDraw function:

oid Face::WireDraw(int beginStyle)
{

vector <int>::iterator vertIt; // Vertices iterator.
//Only Wire.
glBegin(beginStyle);
//Loop over all the vertices in this face.
vertIt = m_vIndices.begin();
int size = OverallObject->m_verts.size(); //The overallObject holds the coordinates
// and the rest of the data.
glColor3f (m_wireColor[0], m_wireColor[1], m_wireColor[2]);
while (vertIt !=m_vIndices.end())
{
Vector3 Vec = (OverallObject->m_verts[*vertIt]).m_vec;
glVertex3f(Vec.m_x,
Vec.m_y,
Vec.m_z);
vertIt++;
}
glEnd();

}

:( [/b]

I don’t think this is what you are doing. Try moving the polygon offset code before drawing the line mode instead of fill mode.

Also, what happens when you render using your current code. Can you post the images?

I’ve been told in gamedev that perhaps my z-buffer is not initialized correctly.

http://www.gamedev.net/community/forums/topic.asp?topic_id=365869
The last set of pictures verifies it.
Can someone here help me with this initialization?
this is what i did:

glClearColor(0,0,0,0);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); 
glMatrixMode(GL_PROJECTION);	
glLoadIdentity();
float ratio = (float)(w/h);
glFrustum (-1.0, 1.0, -1.0, 1.0, 0, 150.0);
gluPerspective(60 ,ratio, 0, 150); // this makes a persepctive view with an angle of 60 degrees, the close plane is 1
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

:slight_smile: