automatically render inside and outside outlines

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.