Hi:
I am writing to you to ask for advice about a specific need: to programmatically render inside and outside outlines of a 3D model, given a specific camera position and orientation. Ideally the output should be vector-based.
Do you have any pointers to ways to tackle this problem ?
Thanks in advance for your guidance.
Hughes Hoppe’s paper on silhouette clipping describes a method of calculating the outline of a model’s silhouette. Is that what you’re looking for?
http://img363.imageshack.us/my.php?image=outlinepp0.png
Pseudo-code:
typedef struct{
vec4 screenpos; // position in screen
}TransVertex; // a transformed-to-screenspace vertex
typedef struct{
vec4 vert0_screenpos;
vec4 vert1_screenpos;
}TransEdge;
TransVertex Vertices[10000];
TransEdge OutlineEdges[10000];
TransEdge InlineEdges[10000];
int NumOutlineEdges=0;
int NumInlineEdges=0;
int i=0;
foreach(vert in meshVertices){
// compute clipspace and screenpos of each vertex
vec4 clipspace = mvp * vert;
Vertices[i].screenpos = ClipspaceToScreenSpace(clipspace);
i++;
}
foreach(triangle in meshTriangles){
// mark backface triangles (that won't be drawn)
vec4 v0 = Vertices[triangle.vert0_ID];
vec4 v1 = Vertices[triangle.vert1_ID];
vec4 v2 = Vertices[triangle.vert2_ID];
triangle.isbackface = computeIsBackface(v0,v1,v2);
}
foreach(edge in meshEdges){
//-----[ is this edge part of the silhouette ]------------------[
bool isback1 = true;
bool isback2 = true;
if(edge.triangle1!=null)isback1 = edge.triangle1.isbackface;
if(edge.triangle2!=null)isback2 = edge.triangle2.isbackface;
if(isback1 == isback2)continue; // this edge is uninteresting
//--------------------------------------------------------------/
//------[ this edge contains 2 of the front-facing triangle's verts, get the 3rd vert ]------[
Triangle front=null;
if(!isback1)front=edge.triangle1;
if(!isback2)front=edge.triangle2;
int vert0_ID = edge.vert0_ID;
int vert1_ID = edge.vert1_ID;
int vert2_ID = front.vert0_ID;
if(vert2_ID==vert0_ID || vert2_ID==vert0_ID)vert2_ID=front.vert1_ID;
if(vert2_ID==vert0_ID || vert2_ID==vert0_ID)vert2_ID=front.vert2_ID;
//-------------------------------------------------------------------------------------------/
//----[ fetch the x:y screen values of the 3 vertices ]---------------------------[
vec2 vert0 = Vertices[vert0_ID].xy;
vec2 vert1 = Vertices[vert1_ID].xy;
vec2 vert2 = Vertices[vert2_ID].xy; // only this vertex doesn't belong to the edge
// we'll use vert2 to extrude the edge by 1 pixel. See attached image how
//--------------------------------------------------------------------------------/
//-------[ find the height of the altitude, starting from vert2 ]------[
#if USE_VERT4
vec2 vert4 = compute_vert4(vert0,vert1,vert2);
float distance1 = distance(vert2,vert4);
#else
float distance1 = compute_altitude_length(vert0,vert1,vert2);
#endif
if(distance1<0.001f)continue;
//---------------------------------------------------------------------/
//-----[ compute how much to scale ]-----------------[
float target_distance = distance1 + 1;
float scale_ratio = target_distance / distance1; // watch-out for infinities?
//--------------------------------------------------/
// now, scale the two vectors [vert2->vert0] and [vert2->vert1]
vec2 edge2 = (vert0-vert2)*scale_ratio;
vec2 edge3 = (vert1-vert2)*scale_ratio;
// now move vert0 and vert2 outward
OutlineEdges[NumOutlineEdges].vert0_screenpos = vec4(edge2 + vert2,Vertices[vert0_ID].zw);
OutlineEdges[NumOutlineEdges].vert1_screenpos = vec4(edge3 + vert2,Vertices[vert1_ID].zw);
NumOutlineEdges++;
if(distance1 > 1){
scale_ratio = (distance1-1)/distance1;
edge2 = (vert0-vert2)*scale_ratio;
edge3 = (vert1-vert2)*scale_ratio;
InlineEdges[NumInlineEdges].vert0_screenpos = vec4(edge2 + vert2,Vertices[vert0_ID].zw);
InlineEdges[NumInlineEdges].vert1_screenpos = vec4(edge3 + vert2,Vertices[vert1_ID].zw);
NumInlineEdges++;
}
}
From those edges (i.e OutlineEdges[]), produce another list of edges, that do not intersect each-other (but can end at shared vertices). From that edge-list, find line-loops (each is an arbitrary polygon). Discard line-loops, that are inside another line-loop. Done, you have outlines.