Ejemplo n.º 1
0
//=============================================================================
// We don't know what direction the initial triangle should face, but it will
// be important that all subsequently generated triangles face a consistent
// direction.  That is, for any two adjacent triangles, they must face the
// same direction.  We can then correct the direction all triangles face in
// the entire mesh later when we're done.
bool SurfaceMesh::PathConnectedComponent::GenerateInitialTriangle( const Surface& surface, const Vector& surfacePoint, const GenerationParameters& genParms )
{
	// Build a coordinate frame for the tangent space at the given surface point.
	CoordFrame coordFrame;
	surface.EvaluateGradientAt( surfacePoint, coordFrame.zAxis );
	Normalize( coordFrame.zAxis, coordFrame.zAxis );
	Scale( coordFrame.zAxis, coordFrame.zAxis, -1.0 );
	Orthogonal( coordFrame.yAxis, coordFrame.zAxis );
	Cross( coordFrame.xAxis, coordFrame.yAxis, coordFrame.zAxis );

	// Build an isosceles triangle in the tangent space.
	VectorMath::Triangle triangleVertices;
	Vector vec;
	Set( vec, cos( PI / 3.0 ), sin( PI / 3.0 ), 0.0 );
	Transform( vec, coordFrame, vec );
	Copy( triangleVertices.vertex[0], surfacePoint );
	AddScale( triangleVertices.vertex[1], surfacePoint, coordFrame.xAxis, genParms.walkDistance );
	AddScale( triangleVertices.vertex[2], surfacePoint, vec, genParms.walkDistance );

	// Now make sure that the triangle vertices are on the surface.
	if( !surface.ConvergePointToSurfaceInPlane( 0, triangleVertices.vertex[1], genParms.epsilon ) )
		return false;
	if( !surface.ConvergePointToSurfaceInPlane( 0, triangleVertices.vertex[2], genParms.epsilon ) )
		return false;

	// Make sure that we're starting in bounds.
	if( Aabb::IS_OUTSIDE_BOX == AabbSide( genParms.aabb, triangleVertices.vertex[0], genParms.epsilon ) )
		return false;
	if( Aabb::IS_OUTSIDE_BOX == AabbSide( genParms.aabb, triangleVertices.vertex[1], genParms.epsilon ) )
		return false;
	if( Aabb::IS_OUTSIDE_BOX == AabbSide( genParms.aabb, triangleVertices.vertex[2], genParms.epsilon ) )
		return false;

	// Add the triangle vertices.
	Vertex* vertex0 = new Vertex( triangleVertices.vertex[0] );
	Vertex* vertex1 = new Vertex( triangleVertices.vertex[1] );
	Vertex* vertex2 = new Vertex( triangleVertices.vertex[2] );
	vertexList.InsertRightOf( vertexList.RightMost(), vertex0 );
	vertexList.InsertRightOf( vertexList.RightMost(), vertex1 );
	vertexList.InsertRightOf( vertexList.RightMost(), vertex2 );

	// Add the triangle.
	Triangle* triangle = new Triangle( vertex0, vertex1, vertex2 );
	triangleList.InsertRightOf( triangleList.RightMost(), triangle );

	// Add the triangle edges.
	Edge* edge0 = new Edge( vertex0, vertex1, triangle );
	Edge* edge1 = new Edge( vertex1, vertex2, triangle );
	Edge* edge2 = new Edge( vertex2, vertex0, triangle );
	edgeQueue.InsertRightOf( edgeQueue.RightMost(), edge0 );
	edgeQueue.InsertRightOf( edgeQueue.RightMost(), edge1 );
	edgeQueue.InsertRightOf( edgeQueue.RightMost(), edge2 );

	// We're finished.
	return true;
}
Ejemplo n.º 2
0
//=============================================================================
bool SurfaceMesh::Generate( const Surface& surface, const GenerationParameters& genParms, ProgressInterface* progressInterface /*= 0*/ )
{
	// Begin with a blank slate.
	componentList.RemoveAll( true );

	// Given each given seed a try.
	for( int index = 0; index < genParms.seedListSize; index++ )
	{
		// Try to converge this seed point to the surface.  If it does
		// not converge, skip the point.
		Vector surfacePoint;
		Copy( surfacePoint, genParms.seedList[ index ] );
		if( !surface.ConvergePointToSurfaceInPlane( 0, surfacePoint, genParms.epsilon ) )
			continue;

		// If the surface point found is already on an existing component,
		// then skip the point, because we don't want to regenerate that component.
		if( IsPointOnSurface( surfacePoint, genParms.epsilon ) )
			continue;

		// Try to generate the component.  Did we succeed?
		PathConnectedComponent* component = new PathConnectedComponent();
		if( !component->Generate( surface, surfacePoint, genParms, progressInterface ) )
		{
			// No.  Delete the component and return failure.
			delete component;
			return false;
		}
		else
		{
			// Yes.  Accumulate the component.
			componentList.InsertRightOf( componentList.RightMost(), component );
		}
	}

	// Return success.
	return true;
}
Ejemplo n.º 3
0
//=============================================================================
// If at all possible, we always want to connect an edge to an existing
// vertex.  Otherwise, our algorithm could never terminate in the way
// that we would hope, having completely covered the surface.  The first
// such vertex we search for is one on an edge adjacent to the edge that
// we are processing.  The second such vertex we search from is one within
// the given walk distance of the edge we're processing.  This is so that
// the mesh can grow into and not over itself.
bool SurfaceMesh::PathConnectedComponent::GenerateNewTriangle( const Surface& surface, const GenerationParameters& genParms )
{
	// If there is no edge to process, then our job is done.
	Edge* processEdge = ( Edge* )edgeQueue.LeftMost();
	if( !processEdge )
		return true;

	// No matter what happens with the edge, we remove it from the queue
	// and add it to the processed list to indicate that we have considered
	// it and processed it.
	EdgeProcessed( processEdge );

	// If the entire edge is out of bounds, then we're done.
	if( Aabb::IS_OUTSIDE_BOX == AabbSide( genParms.aabb, processEdge->vertex[0]->point, genParms.epsilon ) )
		return true;
	if( Aabb::IS_OUTSIDE_BOX == AabbSide( genParms.aabb, processEdge->vertex[1]->point, genParms.epsilon ) )
		return true;

	// We hope this wouldn't happen, but if the edge we're about to process intesects
	// the mesh by penetrating a triangle in the mesh, then stop considering the edge
	// right now to prevent us from growing the mesh over itself.
	//...

	// Do our best to find an existing vertex to connect our edge with.
	Plane edgePlane;
	Vertex* ccwVertex = 0, *cwVertex = 0;
	Vertex* newVertex = FindVertexForEdge( processEdge, ccwVertex, cwVertex, edgePlane, genParms );

	// If these weren't found, then something is wrong.
	if( !( ccwVertex && cwVertex ) )
		return true;

	// Ultimately, if we couldn't find an existing vertex, we need to create a new one.
	if( !newVertex )
	{
		// Walk into the new frontier.  We fail here if we fail to converge to the surface.
		Vector edgeMidpoint, point;
		Lerp( edgeMidpoint, processEdge->vertex[0]->point, processEdge->vertex[1]->point, 0.5 );
		bool pointIsAcceptable = false;
		for( double scale = 1.0; scale > 0.1 && !pointIsAcceptable; scale *= 0.5 )
		{
			AddScale( point, edgeMidpoint, edgePlane.normal, genParms.walkDistance * scale );
			if( !surface.ConvergePointToSurfaceInPlane( 0, point, genParms.epsilon ) )
				return false;
			pointIsAcceptable = FrontierPointIsAcceptable( point, processEdge->triangle, genParms );
		}

		// If ultimately the point is not acceptable, fail to create an new triangle.
		// It's likely that an adjacent edge won't fail, and the final mesh won't have a hole in it.
		if( !pointIsAcceptable )
			return true;

		// Add the new point to our list.
		newVertex = new Vertex( point );
		vertexList.InsertRightOf( vertexList.RightMost(), newVertex );
	}

	// Create the new triangle.
	Triangle* triangle = new Triangle( processEdge->vertex[1], processEdge->vertex[0], newVertex );
	triangleList.InsertRightOf( triangleList.RightMost(), triangle );
	triangle->adjacentTriangle[0] = processEdge->triangle;

	// We either create a new CCW edge or delete an old one.
	Edge* adjacentEdge = FindEdge( processEdge->vertex[0], newVertex );
	if( !adjacentEdge )
		AddPendingEdge( processEdge->vertex[0], newVertex, triangle );
	else
	{
		triangle->adjacentTriangle[1] = adjacentEdge->triangle;
		EdgeProcessed( adjacentEdge );
	}
	
	// We either create a new CW edge or delete an old one.
	adjacentEdge = FindEdge( newVertex, processEdge->vertex[1] );
	if( !adjacentEdge )
		AddPendingEdge( newVertex, processEdge->vertex[1], triangle );
	else
	{
		triangle->adjacentTriangle[2] = adjacentEdge->triangle;
		EdgeProcessed( adjacentEdge );
	}

	// Lastly, knowing that the new triangle points to its adjacent triangles,
	// make sure that its adjacent triangles point back to it.
	triangle->PatchAdjacencies();

	// Return success.
	return true;
}