Contents
Sponsored Feature: Inking the Cube: Edge Detection with Direct3D 10
 
 
Printer-Friendly VersionPrinter-Friendly Version
 


Part of:



[More information...]
 

Latest News
spacer View All spacer
 
November 22, 2009
 
Video Game Watchdog National Institute On Media And The Family Shutting Down [11]
 
Modern Warfare 2 Infinity Ward's 'Most Successful PC Version' Yet [12]
 
New Tech, Design Details Of Project Natal To Emerge At Gamefest In February
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 22, 2009
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Network Programmer
 
Sucker Punch Productions
Texture Artist
 
Sony Online Entertainment
Brand Manager
 
Monolith Productions
Sr. Software Engineer, Engine - Monolith Productions - #113767
 
Crystal Dynamics
Sr. Level Designer
 
Gargantuan Studios
Lead World Designer
spacer
Latest Features
spacer View All spacer
 
November 22, 2009
 
arrow Upping The Craft: Susan O'Connor On Games Writing [6]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part II [6]
 
arrow iPhone Piracy: The Inside Story [48]
 
arrow And Yet It Grows: Analyzing the Size and Growth of the European Game Market [5]
 
arrow NPD: Behind the Numbers, October 2009 [13]
 
arrow Reflecting On Uncharted 2: How They Did It [5]
 
arrow Sponsored Feature: Rasterization on Larrabee -- Adaptive Rasterization Helps Boost Efficiency
 
arrow Postmortem: Wadjet Eye's The Blackwell Convergence [2]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 22, 2009
 
Time Fcuk
 
Accepting the Inherent Value of Games
 
Planckogenesis, Part II: Song Structure & Gravy Train [1]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  Sponsored Feature: Inking the Cube: Edge Detection with Direct3D 10
by Joshua Doss
0 comments
Share RSS
 
 
August 27, 2008 Article Start Previous Page 2 of 3 Next
 

Implementation in DirectX 10

Since DirectX 10 got its geometry shader, programmers are able to calculate face normals on the GPU, allowing for accurate detection methods for both silhouette and crease edges without the preprocessing step and the bus overhead resulting from frequent CPU to GPU communication. Nvidia devised this application and presented it at Siggraph 2006 (see Tariq in References) with respect to detecting and extruding silhouette edges. Here, we will output new geometry for the edges, applying strict control over their thicknesses.


The HLSL implementation of the detection and extrusion algorithm for silhouette edges is shown.

The first step is to create a mesh with adjacency information. This is done by creating a vertex buffer with three vertices per primitive, and then creating an index buffer containing the adjacent vertices in the proper winding order. The primitive-type triangle with adjacency must be declared in both the host code and the geometry shader constructor. As a result, the geometry shader gets access to vertex information from three triangles: the primary triangle, and the three adjacent triangles for a total of six vertices.

With this information we should test the primary triangle to see if it's front-facing by calculating the dot product of the face normal and the view direction. If the result is less than zero, we have a front-facing triangle and need to check whether it contains a silhouette edge (see Gooch et al. in References). This test is performed in world space coordinates. (See Listing 1.)

Listing 1

float3 faceNormal = normalize(cross(
inputVertex[2].position - inputVertex[0].position,
inputVertex[4].position - inputVertex[0].position)
);

float3 viewDirection = -inputVertex[0].position;

float dotView = dot(faceNormal, viewDirection);

if(dotView < 0)
//The triangle is front-facing, check to see if it contains a
//silhouette edge.

We test the three vertices containing an adjacent triangle with the shared edge by taking the dot product of the adjacent triangle's face normal and the view direction. If the result is greater than or equal to zero, we have a silhouette edge. To detect a crease edge, we simply calculate the dot product of the primary triangle's face normal with each adjacent triangle's face normal. If the result is less than an application defined threshold value, we have a crease edge.

Once we know we have an edge, we need to create the extruded geometry. We do this by creating fins in the direction of the normal of an application-specified constant thickness, then loop twice over each vertex, and simply replicate the vertex and transform it in the direction of the normal vector for each vertex that exists as a point along the silhouette edge. (See Listing 2.)

Listing 2

//The face normal of each adjacent triangle is calculated in //order to test whether it contains the adjacent edge. The //prefix vs designates view space coordinates, the prefix ws //indicates world space coordinates and the prefix ps //indicates perspective correct world view space //coordinates.

float3 wsAdjFaceNormal =
normalize(
cross(normalize(vertA.wsPos - vertC.wsPos),
normalize(vertB.wsPos-vertC.wsPos)));

float dotView =
dot(wsAdjFaceNormal, vertA.wsView);

if(dotView >= 0.0)
{
for(int v = 0; v < 2; v++)
{
float4 wsPos = vertB.wsPos +
v * float4(vertB.wsNorm,0) * g_fEdgeLength;
float4 vsPos = mul(wsPos, g_mView);
output.psPos = mul(vsPos, g_mProjection);
output.wsNorm = vertB.wsNorm;
output.EdgeFlag = SILHOUETTE_EDGE;
Stream.Append(output);
}
for(int v = 0; v < 2; v++)
{
float4 wsPos = vertC.wsPos +
v * float4(vertC.wsNorm,0) * g_fEdgeLength;
float4 vsPos = mul(wsPosition, g_mView);
output.psPos = mul(vsPosition, g_mProjection);
output.wsNorm = vertC.wsNormal;
output.EdgeFlag = SILHOUETTE_EDGE;
Stream.Append(output);
}
Stream.RestartStrip();
}

A crease edge can be either a ridge or valley edge. A ridge edge has an angle between the face normals that is either equal to or greater than 180 degrees, while a valley edge has an angle less than 180 degrees.

Since we extrude along the vertex normal, z-fighting may occur when we have valley edge with an angle near 90 degrees because the vertex normal in this case is coplanar with the face of the adjacent triangle. In order to solve this problem, we apply a z-bias to the affected edge by transforming the geometry a distance epsilon in the direction of the camera. (See Listing 3.)

Listing 3

for(int v = 0; v < 2; v++)
{
float4 wsPosition = Vertex.wsPosition +
v * float4(Vertex.wsNormal,0) * EdgeLength;

float4 vsPosition = mul(wsPosition, WorldToView);
vsPosition.z -= ZBiasEpsilon;
output.psPosition = mul(vsPosition,
ViewToProjection);
output.wsNormal = vertB.wsNormal;
output.EdgeFlag = CREASE_EDGE;
Stream.Append(output);
}

 
Article Start Previous Page 2 of 3 Next
 
Comments

none
 
Comment:
 


Submit Comment