// Given a scene node for a terrain, find the manual object on that scene node and
// update the manual object with the heightmap passed. If  there is no manual object on
// the scene node, remove all it's attachments and add the manual object.
// The heightmap is passed in a 1D array ordered by width rows (for(width) {for(length) {hm[w,l]}})
// This must be called between frames since it touches the scene graph
// BETWEEN FRAME OPERATION
void Region::UpdateTerrain(const int hmWidth, const int hmLength, const float* hm) {
	Ogre::SceneNode* node = this->TerrainSceneNode;
	LG::Log("Region::UpdateTerrain: updating terrain for region %s", this->Name.c_str());

	if (node == NULL) {
		LG::Log("Region::UpdateTerrain: terrain scene node doesn't exist. Not updating terrain.");
		return;
	}

	// Find the movable object attached to the scene node. If not found remove all.
	if (node->numAttachedObjects() > 0) {
		Ogre::MovableObject* attached = node->getAttachedObject(0);
		if (attached->getMovableType() != "ManualObject") {
            // don't know why this would ever happen but clean out the odd stuff
            LG::Log("Found extra stuff on terrain scene node");
			node->detachAllObjects();
		}
	}
	// if there is not a manual object on the node, create a new one
	if (node->numAttachedObjects() == 0) {
		LG::Log("Region::UpdateTerrain: creating terrain ManualObject for region %s", this->Name.c_str());
        // if no attached objects, we add our dynamic ManualObject
		Ogre::ManualObject* mob = LG::RendererOgre::Instance()->m_sceneMgr->createManualObject("ManualObject/" + node->getName());
		mob->addQueryFlags(Ogre::SceneManager::WORLD_GEOMETRY_TYPE_MASK);
		mob->setDynamic(true);
		mob->setCastShadows(true);
		mob->setVisible(true);
		node->attachObject(mob);
		// m_visCalc->RecalculateVisibility();
	}

	Ogre::ManualObject* mo = (Ogre::ManualObject*)node->getAttachedObject(0);

	// stuff our heightmap information into the dynamic manual object
	mo->estimateVertexCount(hmWidth * hmLength);
	mo->estimateIndexCount(hmWidth * hmLength * 6);

	if (mo->getNumSections() == 0) {
		// if first time
		mo->begin(LG::GetParameter("Renderer.Ogre.DefaultTerrainMaterial"));
	}
	else {
		mo->beginUpdate(0);					// we've been here before
	}

	int loc = 0;
	for (int xx = 0; xx < hmWidth; xx++) {
		for (int yy = 0; yy < hmLength; yy++) {
			mo->position((Ogre::Real)xx, (Ogre::Real)yy, hm[loc++]);
			mo->textureCoord((float)xx / (float)hmWidth, (float)yy / (float)hmLength);
			mo->normal(0.0, 1.0, 0.0);	// always up (for the moment)
		}
	}

	for (int px = 0; px < hmLength-1; px++) {
		for (int py = 0; py < hmWidth-1; py++) {
			mo->quad(px      + py       * hmWidth,
					 px      + (py + 1) * hmWidth,
					(px + 1) + (py + 1) * hmWidth,
					(px + 1) + py       * hmWidth
					 );
		}
	}

	mo->end();

	return;
}
Beispiel #2
0
/*
 
 Generates the decal and returns a Decal object. The caller is responsible for NULL-checking the manual object.
 This gigantic function should probably be chopped into smaller bite-sized pieces, but I'm just doo darn lazy.
 
 @param mesh    The mesh to project the decal onto.
 @param pos     The position of the decal
 @param width   The width of the decal
 @param height  The height of the decal
                Note: The aspect ratio defined by width/height should match the texture, otherwise it will appear stretched.
 
 @param materialName    The name of the material to use for the decal
 @param flipTexture     Will randomly flip the texture to introduce variety (useful for blood splatter, explosion decals, etc.)
 @param decalObject     If NULL, this function will automatically create a new manual object (default). Otherwise, it will re-use the one passed in.
                        For dynamic decals (generating one every frame), it is much more efficient to reuse the same manual object,
                        as long as the material doesn't change.
 

 */
Decal DecalGenerator::createDecal( TriangleMesh* mesh, const Ogre::Vector3& pos, float width, float height, 
                                  const Ogre::String& materialName, bool flipTexture, Ogre::ManualObject* decalObject )
{
	//Variable de error para dar de salida en el object un NULL y que no pete
	bool bError = false;

    /// Clear out any old left-over stuff from the fridge.
    triangles.clear();
    uniquePoints.clear();
    finalPolys.clear();
    polygon_points.clear();
    
    float depth = max(width, height);

    /// Define our AABB 
    Ogre::Vector3 aabbMin = pos + Ogre::Vector3( -depth, -depth, -depth );
    Ogre::Vector3 aabbMax = pos + Ogre::Vector3( depth, depth, depth);
    
    /// We're gonna need triangles. Lot's of triangles.
    mesh->findTrianglesInAABB( aabbMin, aabbMax, triangles );
    
    if (triangles.empty())
    {
        /// No triangles were found, return an empty Decal
        /// Note that the caller is responsible for verifying the returned object
        return Decal();
    }
    
    std::vector< Triangle >::iterator iter;
    Ogre::Vector3 averageN(0, 0, 0);
    
    /// Calculate the average normal of all the triangles gathered from our AABB
    for (iter = triangles.begin(); iter != triangles.end(); ++iter)
    {
        averageN += iter->normal;
    }
    
    /// This average normal length is too close to zero, which is a bad omen. Get out while we still can!
    if (averageN.length() < VEC_EPSILON)
    {
        return Decal();
    }
    
    averageN.normalise();
    
    Ogre::Vector3 right, up;
    
    /// Calculate a coordinate space from the the average of all the triangle normals
    /// We're creating the projection box that will be used to clip the triangles
    
    if (averageN == Ogre::Vector3(0, 1, 0))
    {
        right = Ogre::Vector3(1, 0, 0);
    }
    else if (averageN == Ogre::Vector3(0, -1, 0))
    {
        right = Ogre::Vector3(-1, 0, 0);
    }
    else                
    {
        right = (-averageN).crossProduct( Ogre::Vector3(0, 1, 0) );
    }
    
    right.normalise();
    
    up = right.crossProduct( -averageN );
    up.normalise();
        
    
    /// Now that we have our coordinate space, let's define some planes. No silly, not the ones that fly in the sky!
    // These are the clipping planes! Be careful, because you might get cut.
    const int NUM_EDGE_PLANES = 6;
    
    Ogre::Vector4 edgePlanes[NUM_EDGE_PLANES];
    
    Ogre::Vector3 planeR[6];
    Ogre::Vector3 planeN[6];
    
    planeN[0] = averageN;  
    planeN[1] = -averageN; 
    planeN[2] = right;      
    planeN[3] = -right;     
    planeN[4] = up;       
    planeN[5] = -up;        
    
    
    /// These are to ensure that certain points are not "out of bounds"
    double distanceLimit = sqrt( (depth * depth) + (depth * depth) ) * 1.25;
    double edgeLimitX = sqrt( (width * width) + (width * width) ) * 1.05;
    double edgeLimitY = sqrt( (height * height) + (height * height) ) * 1.05;
    
    /// A point for each plane
    planeR[0] = pos + (planeN[0] * depth);
    planeR[1] = pos + (planeN[1] * depth);
    planeR[2] = pos + (planeN[2] * width);
    planeR[3] = pos + (planeN[3] * width);
    planeR[4] = pos + (planeN[4] * height);
    planeR[5] = pos + (planeN[5] * height);
    
    /// Set up each edge plane as a four dimensional vector defined in interstellar space. Carl Sagan would be all over this.
    for (int i = 0; i < NUM_EDGE_PLANES; ++i)
    {
        edgePlanes[i] = Ogre::Vector4(planeN[i].x, planeN[i].y, planeN[i].z, planeR[i].dotProduct( planeN[i] ) );
    }
    
    Ogre::Vector3 averageNormal(0, 0, 0);
    
    double totalPoints = 0;
    Ogre::Vector3 averagePoint;
    
    /// Loop through each triangle to find the meaning of life
    for (iter = triangles.begin(); iter != triangles.end(); ++iter)
    {
        polygon_points.clear();
        
        polygon_points.push_back( iter->v[0] );
        polygon_points.push_back( iter->v[1] );
        polygon_points.push_back( iter->v[2] );
     
        Ogre::Vector3 n = iter->normal;
        
        Ogre::Vector3 polygonNormal = n;
        
        /// Clip this triangle against each edge
        for (int edge = 0; edge < NUM_EDGE_PLANES; ++edge)
        {
            /// Clip the polygon against the edge plane.
            /// Why is this function returning duplicate points?

			//std::cout << "Cuando peta, peta aqui: " << polygon_points.size() << std::endl;
			if (polygon_points.size() > 0)
			{
				int clipped_count = plane_clip_polygon( edgePlanes[ edge ], &(polygon_points[0]), polygon_points.size(), clippedPoints );
            
				polygon_points.clear();
				int index = 0;
            
				for (int i = 0; i < clipped_count; ++i)
				{
					Ogre::Vector3 p = clippedPoints[ i ];
                
					/// Do not use any duplicate points returned by plane_clip_polygon()
					if (!isDuplicate( polygon_points, p ))
					{
						polygon_points.push_back( p );
                
						/// If this was the last edge plane we checked against, then we have all of our clipped points for this triangle
						if (edge == NUM_EDGE_PLANES - 1)
						{
							/// Check if this point was clipped by comparing it to each original vertex of the triangle.
							/// If this point is an original triangle vertex, then it wasn't clipped.
							if (( p - iter->v[0] ).length() < VEC_EPSILON || (p - iter->v[1]).length() < VEC_EPSILON || (p - iter->v[2]).length() < VEC_EPSILON)
							{
								pointWasClipped[ index ] = false;
							}
							else
							{
								pointWasClipped[ index ] = true;
							}
						}
                    
						++index;
					}
				}
			}//if points
			else
			{
				bError = true;
				std::cout << "Hay ERROR triangulando para el decal" << std::endl;
				break;
			}
		}// for edge
        

        /// If we ended up with less points than what we started out with, then we're in big horse doo-doo
        if (polygon_points.size() < 3)
            continue;
        
        finalPolys.push_back( DecalPolygon( polygonNormal ) );
        
        int size = polygon_points.size();
        
        double area = 1;
        
        /// Find the area of our freshly clipped polygon; used for generating a "better" vertex normal
        if (polygon_points.size() >= 3)
        {
            polygon_points.push_back( polygon_points[0] );
            polygon_points.push_back( polygon_points[1] );
            
            area = area3D_Polygon( size, &(polygon_points[0]), n );
        }
        
        /// Loop through each point in our clipped polygon, and find the unique ones.
        for (int i = 0; i < polygon_points.size() - 2; ++i)
        {
            Ogre::Vector3 p = polygon_points[i];
            
            averagePoint += p;
            ++totalPoints;
            
            /// Make sure this point is not "out of bounds"
            if ((p - pos).length() < distanceLimit)
            {
                /// Check to see if this point is a duplicate
                /// Assuming this point is not a duplicate, set uniqueIndex to be the point added next
                int uniqueIndex = uniquePoints.size();
                
                /// If a duplicate is found, uniqueIndex will be set to that point
                if ( !isDuplicate( uniquePoints, p, uniqueIndex ) )
                {
                    uniquePoints.push_back( UniquePoint( p, pointWasClipped[i] ) );
                }
                
                /// Make sure we're still OK
                assert( uniqueIndex >= 0 && uniqueIndex < uniquePoints.size() );
                
                // Update the normal for this point (we'll normalize it later). NormaLIZE.
                uniquePoints[ uniqueIndex ].normal += (polygonNormal * area);
                
                finalPolys.back().points.push_back( uniqueIndex );
            }
            
        }

        averageNormal += (n * area);
    }//for loop triangles
    
    
	if (!bError)
	{
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		///                                                                                                                                ///
		///                             We intterupt this program to give you a brief word from our sponsers...                            ///
		///                                                                                                                                ///
		/// Congratulations. You've made it this far. Half the battle is over. At this point, we have all of our final clipped points.     ///
		/// Now we need to project those points to 2D so we can calculate the UV coordinates. Don't worry, there's more fudge on the way.  ///
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
		averageNormal.normalise();
    
		averagePoint /= totalPoints;
    
		Ogre::Vector3 projectionPlaneNormal = -averageN;
    
		Ogre::Vector3 projectionPlaneRight = right;
		projectionPlaneRight.normalise();
    
		Ogre::Vector3 projectionPlaneUp = up;
		projectionPlaneUp.normalise();
    
		Ogre::Quaternion planeOrien( projectionPlaneRight, projectionPlaneUp, -projectionPlaneNormal );
    
		Ogre::Quaternion finalOrien( Ogre::Vector3(1, 0, 0), Ogre::Vector3(0, 1, 0), Ogre::Vector3(0, 0, -1) );
    
		planeOrien.normalise();
		finalOrien.normalise();
    
		/// This is the quaternion we'll use to tranform each point so we can project them onto the XY plane
		/// This quaternion takes the projection plane's coordinate system (which is indentical our clipping box)
		/// and rotates it so that it is parrallel with the XY plane, at which point we nuke the Z axis on every point to
		/// project them into 2D.
		Ogre::Quaternion finalQuat = planeOrien.UnitInverse() * finalOrien;
    
		/// My mom always said, you can never normalize too much. Except when you spell it wrong.
		finalQuat.normalise();
    
		std::vector< DecalPolygon >::iterator pIter;
    
		double leftMost, rightMost, topMost, bottomMost;
    
		bool initCorners = false;
    
		Ogre::Vector3 center = finalQuat * pos;
		Ogre::Vector2 centerPoint( center.x, center.y );
    
		std::vector< UniquePoint >::iterator pointIter;
    
		/// Loop through all of our points and project them into 2D.
		for (pointIter = uniquePoints.begin(); pointIter != uniquePoints.end(); ++pointIter)
		{
			/// Rotate each point so that we can project them onto the XY plane
			/// finalQuat transforms the projection plane so that it's parallel with the XY plane
			Ogre::Vector3 v = finalQuat * pointIter->p;
        
			/// Project/flatten the point by eliminating the Z coordinate
			Ogre::Vector2 projectedPoint(v.x, v.y);
        
			pointIter->uvCoord = projectedPoint;
        
			/// Find the left, right, top, and bottom edge
			if (pointIter->isEdge)
			{
				Ogre::Vector2 diff = (projectedPoint - centerPoint);
            
				/// More fudge-checking to make sure nothing is out of bounds
				if ( fabs( diff.x ) < edgeLimitX && fabs( diff.y ) < edgeLimitY )
				{
					if (!initCorners)
					{
						leftMost = rightMost = projectedPoint.x;
						topMost = bottomMost = projectedPoint.y;
                    
						initCorners = true;
					}
                
					if (projectedPoint.x < leftMost)
						leftMost = projectedPoint.x;
                
					if (projectedPoint.x > rightMost)
						rightMost = projectedPoint.x;
                
					if (projectedPoint.y > topMost)
						topMost = projectedPoint.y;
                
					if (projectedPoint.y < bottomMost)
						bottomMost = projectedPoint.y;
				}
			}
		}
    
    
		/// The hardest part is over. Now we get to fudge the UV coords, because you can never have too much fudge.
    
		std::vector< UniquePoint >::iterator topRight, bottomRight, topLeft, bottomLeft;
    
		Ogre::Vector2 cornerTopLeft( leftMost, topMost );
		Ogre::Vector2 cornerTopRight( rightMost, topMost );
		Ogre::Vector2 cornerBottomLeft( leftMost, bottomMost );
		Ogre::Vector2 cornerBottomRight( rightMost, bottomMost );
    
		bool initValues = false;
    
		double minDistanceTopLeft, minDistanceTopRight, minDistanceBottomLeft, minDistanceBottomRight;
    
		std::vector< UniquePoint >::iterator projectedPointIter;

		/// Loop throgh all of our (2D) points and figure out which points are nearest to each of the four corners.
		/// Why do we do this? Because I said so. Do not question my infinite wisdom.
		for (projectedPointIter = uniquePoints.begin(); projectedPointIter != uniquePoints.end(); ++projectedPointIter)
		{
			Ogre::Vector2 p = projectedPointIter->uvCoord;
        
			double distanceTopLeft = (p - cornerTopLeft).length();
			double distanceTopRight = (p - cornerTopRight).length();
			double distanceBottomLeft = (p - cornerBottomLeft).length();
			double distanceBottomRight = (p - cornerBottomRight).length();
        
			if (!initValues)
			{
				initValues = true;
            
				topRight = projectedPointIter;
				topLeft = projectedPointIter;
				bottomRight = projectedPointIter;
				bottomLeft = projectedPointIter;
            
				minDistanceTopLeft = distanceTopLeft;
				minDistanceTopRight = distanceTopRight;
				minDistanceBottomLeft = distanceBottomLeft;
				minDistanceBottomRight = distanceBottomRight;
			}
			else
			{
				if (distanceTopLeft < minDistanceTopLeft)
				{
					minDistanceTopLeft = distanceTopLeft;
					topLeft = projectedPointIter;
				}
            
				if (distanceTopRight < minDistanceTopRight)
				{
					minDistanceTopRight = distanceTopRight;
					topRight = projectedPointIter;
				}
            
				if (distanceBottomLeft < minDistanceBottomLeft)
				{
					minDistanceBottomLeft = distanceBottomLeft;
					bottomLeft = projectedPointIter;
				}
            
				if (distanceBottomRight < minDistanceBottomRight)
				{
					minDistanceBottomRight = distanceBottomRight;
					bottomRight = projectedPointIter;
				}
			}
		}
    
    
		/// Here we calculate (via fudge factor) the UV edges which are used to determine the UV coords.
		/// This is the fudge motherload.
		/// I could try to explain why we're doing this, but it would just sound like I have no idea what I'm talking about.
		/// Which is probably true.
		rightMost = average( average( topRight->uvCoord.x, bottomRight->uvCoord.x ), rightMost );
		leftMost = average( average( topLeft->uvCoord.x, bottomLeft->uvCoord.x ), leftMost );
    
		topMost = average( average( topLeft->uvCoord.y, topRight->uvCoord.y ), topMost );
		bottomMost = average( average(bottomRight->uvCoord.y, bottomLeft->uvCoord.y), bottomMost );
    
		/// Calcuate the width and height used to calculate UV coords.
		width = rightMost - leftMost;
		height = topMost - bottomMost;
    
		int randomFlipType = 0;
    
		if (flipTexture)
			randomFlipType = rand()%8;
    
		/// Ok, now we get to the final UV coords. For real this time, no kidding.
		for (projectedPointIter = uniquePoints.begin(); projectedPointIter != uniquePoints.end(); ++projectedPointIter)
		{
			Ogre::Vector2 p = projectedPointIter->uvCoord;
    
			double uvMin = 0;
			double uvMax = 1;
        
			/// Ta da!
			double u = (p.x - leftMost) / width;
			double v = (p.y - bottomMost) / height;
        
			/// Oops, we wouldn't want any rebel coordiantes wreaking havoc.
			if (u < uvMin)
				u = uvMin;
			else if (u > uvMax)
				u = uvMax;
        
			if ( v < uvMin )
				v = uvMin;
			else if (v > uvMax)
				v = uvMax;
        
			projectedPointIter->uvCoord.x = u;
			projectedPointIter->uvCoord.y = (1 - v);
        
			/// Randomly flip UV coords between 8 different ways
			/// This might be desirable for things like blood splatter, explosions, etc to simply introduce variety
			if (flipTexture && randomFlipType > 0)
			{
				switch (randomFlipType)
				{
					case 1:
					{
						projectedPointIter->uvCoord.x = (1 - u);
						projectedPointIter->uvCoord.y = (1 - v);
					}
					case 2:
					{
						projectedPointIter->uvCoord.x = (1 - u);
						projectedPointIter->uvCoord.y = v;
					}
					case 3:
					{
						projectedPointIter->uvCoord.x = u;
						projectedPointIter->uvCoord.y = v;
					}
					case 4:
					{
						projectedPointIter->uvCoord.y = (1 - u);
						projectedPointIter->uvCoord.x = (1 - v);
					}
					case 5:
					{
						projectedPointIter->uvCoord.y = (1 - u);
						projectedPointIter->uvCoord.x = v;
					}
					case 6:
					{
						projectedPointIter->uvCoord.y = u;
						projectedPointIter->uvCoord.x = v;
					}
					case 7:
					{
						projectedPointIter->uvCoord.y = u;
						projectedPointIter->uvCoord.x = (1 - v);
                    
					}
				}
            
			}
		}
    

		/// All of the final UV coords have been generated. Now it's rendering time. 
		/// What are you waiting for? Let's make that manual object that you've been dreaming about.
       
		std::vector<UniquePoint>::iterator uniqueIter;
    
		/// Debug drawing stuff
		if (DEBUG_ENABLED)
		{
			Ogre::ManualObject* moDebug = sceneMgr->createManualObject();
        
			moDebug->begin("debug_draw", Ogre::RenderOperation::OT_TRIANGLE_LIST);
        
			int indexOffset = 0;
        
			for (uniqueIter = uniquePoints.begin(); uniqueIter != uniquePoints.end(); ++uniqueIter)
			{
				createCubeMesh( sceneMgr, uniqueIter->p, 0.25, Ogre::ColourValue::Red, moDebug, indexOffset);
				indexOffset += 8;
			}
        
			moDebug->end();
        
			if (!mDebugVisible)
				moDebug->setVisible( false );
        
			mDebugNode->attachObject( moDebug );
		}
  

		/// "lines" is used for debug drawing triangles
		Ogre::ManualObject* lines = 0;

		if (DEBUG_ENABLED)
		{
			lines = sceneMgr->createManualObject();
			lines->begin("debug_draw", Ogre::RenderOperation::OT_LINE_LIST);
		}
    
		/// Create a new manual object if this one doesn't exist
		if (!decalObject)
		{
			decalObject = sceneMgr->createManualObject();
		}
		else
		{
			/// Make sure the decal object can be dynmically updated
			if (!decalObject->getDynamic())
				decalObject->setDynamic( true );
		}
    
		Ogre::String material = materialName;
    
		if (decalObject->getDynamic() && decalObject->getNumSections() > 0)
		{
			 /// Update the existng decal instead of starting a new one
			 decalObject->beginUpdate( 0 );
		}
		else
		{
			 /// Start a new decal
			decalObject->begin(material, Ogre::RenderOperation::OT_TRIANGLE_LIST);
		}
    
		/// If we're sharing vertices, then simply set up all of the vertex info ahead of time
		if ( SHARE_VERTEX_NORMALS )
		{
			for (uniqueIter = uniquePoints.begin(); uniqueIter != uniquePoints.end(); ++uniqueIter)
			{
				uniqueIter->normal.normalise();
            
				decalObject->position( uniqueIter->p );
				decalObject->textureCoord( uniqueIter->uvCoord );
				decalObject->normal( uniqueIter->normal );
			}
		}
    
		int p1, p2, p3;
		p1 = p2 = p3 = 0;
    
		// Each of these finalPolys is a just list of indicies into the uniquePoints vector
		for (pIter = finalPolys.begin(); pIter != finalPolys.end(); ++pIter)
		{
			std::vector< int >::iterator iter;
        
			Ogre::Vector3 norm = pIter->norm;
        
			if (pIter->points.size() >= 3)
			{
				p2 = p1 + 1;
				p3 = p2 + 1;
            
				int t = 0;
            
				for (iter = pIter->points.begin(); iter != pIter->points.end(); ++iter)
				{
					if (!SHARE_VERTEX_NORMALS)
					{
						decalObject->position( uniquePoints[ *iter ].p );
						decalObject->textureCoord( uniquePoints[ *iter ].uvCoord );
						decalObject->normal( norm );
					}
                
					if (t >= 3)
					{
						++p2;
						++p3;
                    
						AddTriangle( decalObject, pIter->points, p1, p2, p3, lines );
					}
                
					++t;
                
					if (t == 3)
					{
						AddTriangle( decalObject, pIter->points, p1, p2, p3, lines );
					}
                
				}
            
				p1 = p3 + 1;
			}
		}
    
		decalObject->end();
    
		/// Finish debug drawing stuff
		if (DEBUG_ENABLED)
		{
			lines->end();
        
			if (!mDebugVisible)
				lines->setVisible( false );
        
			mDebugNode->attachObject( lines );        
		}
	}

    /// And were done. Phew.
    Decal decal;
    decal.object = decalObject;

	if (bError)
		decal.object = NULL;
    
    return decal;
}