outline a model

Started by
20 comments, last by songho 17 years, 12 months ago
Quote:Original post by daniel_i_l
Do you think that you (or someone else) could explain more? Maybe with a little code?
Thanks.


Let me try. First, you must request a stencil buffer when you create your window. Then do something like I do:
glClear(GL_STENCIL_BUFFER_BIT);                        // Clear the stencilglEnable(GL_STENCIL_TEST);                             //Enable stencil testglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);   //Disable color writes// Now set the stencil to create a 2d mask of the object// Increase the value in the stencil buffer if the depth test passes// ie, if it's visibleglStencilFunc(GL_ALWAYS, 1, 0xffff);      // the stencil test always passesglStencilOp(GL_KEEP, GL_INCR, GL_INCR);object.Draw();// At this point we have a mask of values > 0 where the object is// so we set the stencilfunc to allow fragments where stencil >= 1glStencilFunc(GL_GEQUAL, 1, 0xffff);glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);   // don't modify the valuesglLineWidth(5.0f);glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);object.DrawInWireframe();glDisable(GL_STENCIL_TEST);

That's it, i think. I hope you understand it, I'm not too good at explaining things.
Advertisement
Quote:Original post by Ademan555
On a similar note... are lines the "accepted" way to apply outlines to cell shading (to produce a cartoonish image)? Or is it a screen space normal direction test? (ie see which pixels are within a certain degree of perpendicular to the view direction)?

thanks
-Dan


Ademan, to adress your thought here. When I was making my toon shader, I ended up passing the model twice, the second time rendering the lines only on the inside of the model. That'll solve all problem without killing the stencil buffer. If you try to find out which edges are about perpendicular to you, you get a bad image. The reason is, because some people model diferently, and you can end up with huge black spots where they don't look cartoonish, just bad.

(Daniel, read those bolded words over again, remember, make it render green lines ON THE INSIDE, not outside.)

Couple images:

Bad:


Good:
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"
Gaenor: I used that code but for even one tank the framerate wnt incredibly slow. Could it be that the SB isn't good for more than simple geometry? Or is there another problem?
Since the tanks are pretty detailed and there're many of them I need a "quick and dirty" way of doing the outline.
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Have you considered using a lower-polygon mesh to render the outline instead?
Thats a good idea, I'll try it;
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Is it that slow? I'm currently using it in my map editor to draw the lights' area, as you can see here.

P.S: The second pass should use glStencilFunc(GL_EQUAL, 0, 0xffff); That is, draw outside the shape. The method I posted has the drawback of drawing the wireframe when the camera is inside the object (which is what i wanted at that moment).
Gaenor: I dont know what the problem is. I did this:
  glClear(GL_STENCIL_BUFFER_BIT);                          glEnable(GL_STENCIL_TEST);                               glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);     glStencilFunc(GL_ALWAYS, 1, 0xffff);        glStencilOp(GL_KEEP, GL_INCR, GL_INCR);    glEnable(GL_TEXTURE_2D);  Display(tank, 0, false);  //draws a 3D model of tank  glStencilFunc(GL_EQUAL, 0, 0xffff);  glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);     glLineWidth(1.0f);      //5 seemed huge, you could barely see the lines  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);    glDisable(GL_TEXTURE_2D);  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);  Display(tank, 0, false);  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);  glDisable(GL_STENCIL_TEST);


the tank looked like this: (normally its fully textured)
Image hosting by Photobucket
Is it supposed to do that?
When I did this to one tank it went very slow. Is there anything I missed? Maybe some initialation thing?
Thanks for you help!

"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
The code you posted should be working. Make sure you're requesting a stencil buffer when you create your window. This is how I do it:

	static PIXELFORMATDESCRIPTOR pfd =	{		sizeof(PIXELFORMATDESCRIPTOR),		1,					// Version number		PFD_DRAW_TO_WINDOW |			// Format must support window		PFD_SUPPORT_OPENGL |			// Format must support OpenGL		PFD_DOUBLEBUFFER,			// Must support double buffering		PFD_TYPE_RGBA,				// Request an RGBA format		bitsperpixel,				// Select our color depth		0, 0, 0, 0, 0, 0,			// Color bits ignored		8,					// 8bit Alpha buffer please		0,					// Alpha shift bits		0,					// No accumulation buffer		0, 0, 0, 0,				// Accumulation bits ignored		24,					// 24Bit Z-Buffer (Depth buffer)		1,					// We want a stencil buffer		0,					// No auxiliary buffer		PFD_MAIN_PLANE,			        // Main drawing layer		0,					// Reserved		0, 0, 0					// Layer masks ignored	};

You're right about the linesize. The screenshot you see in my previous post uses 3.0f

Also let me try to explain what we're doing. The stencil buffer is a screen sized buffer. It contains a x bits counter at each pixel. So what we are doing is draw the model filled incrementing the values in the stencil buffer. This creates a 2d mask containing x>0 values where your model is. In the second pass we are setting the stencil operation to let us draw where the stencil has values = 0, that is, anywhere but where the model is. So when we draw it again in wireframe, the stencil will block all fragments in the middle of the model, drawing only the outline.

Also, a cheap way of getting an outline is to scale the model a little (say, 1.01), draw it untextured in your preferred color, reset the scale and draw it normally. This method is affected by depth, though.
Also a quick googling gave these articles:

http://www.codeproject.com/opengl/Outline_Mode.asp
http://www.flipcode.com/articles/article_objectoutline.shtml
Quote:Original post by daniel_i_l
Gaenor: I dont know what the problem is. I did this:
*** Source Snippet Removed ***

the tank looked like this: (normally its fully textured)
Image hosting by Photobucket
Is it supposed to do that?
When I did this to one tank it went very slow. Is there anything I missed? Maybe some initialation thing?
Thanks for you help!


ALMOST ALMOST!!!

FIRST, when rendering a line, each line is actually 3 polygons, that's how video cards render them. That's why it's a bit slower.

SECOND, You need to render the NORMAL model.

THIRD, You need to make a SECOND PASS, rendering ONLY the BACK lines:

glPolygonMode( GL_BACK, GL_LINE);

During the second pass, you need to set the depth function to glDepthFunc(GL_LEQUAL); This will only render the outlines of the tank, which is what you're looking for.

[Edited by - dbzprogrammer on April 25, 2006 5:46:44 PM]
We should do this the Microsoft way: "WAHOOOO!!! IT COMPILES! SHIP IT!"

This topic is closed to new replies.

Advertisement