void ConvexShapeObstacle::updateOrientation(Ogre::Quaternion orientation) { // Modify orientation if difference larger than epsilon if(! mOrientation.equals(orientation, Ogre::Degree(ORIENTATION_TOLERANCE_DEGREES))) { // Remove old obstacle from tilecache mDetourTileCache->removeConvexShapeObstacle(mConvexHull); // In case we didn't generate inputgeom yet (we previously generated hull directly from the bounding box), do it now if(!mInputGeom) mInputGeom = new InputGeom(mEnt); // Apply rotation to the inputGeometry and calculate a new 2D convex hull Ogre::Quaternion relativeOrientation = orientation * mOrientation.Inverse(); // Calculate relative rotation from current rotation to the specified one orientation.normalise(); // Make sure quaternion is normalized mInputGeom->applyOrientation(relativeOrientation, mPosition); // Rotate around obstacle position (center or origin point) if (mConvexHull) delete mConvexHull; mConvexHull = mInputGeom->getConvexHull(mOffset); mConvexHull->area = RC_NULL_AREA; // Be sure to set the proper area for the convex shape! // Add new hull as obstacle to tilecache mDetourTileCache->addConvexShapeObstacle(mConvexHull); mOrientation = orientation; // Now also set the rotation to the visual obstacle entity mNode->setOrientation(orientation); // Create new debug drawing of the convex hull mConvexHullDebug->detachFromParent(); mSceneMgr->destroyManualObject(mConvexHullDebug); mConvexHullDebug = InputGeom::drawConvexVolume(mConvexHull, mSceneMgr); } }
//----------------------------------------------------------------------------------------- void CCameraEditor::roll(const Ogre::Radian &value) { Ogre::Quaternion q; Ogre::Vector3 axis = mOrientation->get() * Ogre::Vector3::UNIT_Z; q.FromAngleAxis(value, axis); q.normalise(); mOrientation->set(q * mOrientation->get()); }
//----------------------------------------------------------------------------------------- void CCameraEditor::yaw(const Ogre::Radian &value) { Ogre::Quaternion q; q.FromAngleAxis(value, Ogre::Vector3::UNIT_Y); q.normalise(); mOrientation->set(q * mOrientation->get()); }
void processDirectionElement(VertexData* vertexData, const VertexElement* vertexElem ) { Ogre::Quaternion rotation = mTransform.extractQuaternion(); rotation.normalise(); int nMaxVert= vertexData->vertexCount ; //const Ogre::VertexElement* VertexEle_POS = vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_POSITION ); // get vertex buffer info via the input element Ogre::HardwareVertexBufferSharedPtr VertexBufPOS = vertexData->vertexBufferBinding->getBuffer( vertexElem->getSource() ); //LOCK BUFFER unsigned char* VertexPtrPOS = static_cast<unsigned char*>( VertexBufPOS->lock( Ogre::HardwareBuffer::HBL_NORMAL ) ); int VertSizePOS=VertexBufPOS->getVertexSize(); float * pElementPOS=NULL; //A vector of every vertices position std::vector<Ogre::Vector3> positions(nMaxVert); //Copy each position into position vector for(int nVert=0 ; nVert<nMaxVert ; nVert++) { vertexElem->baseVertexPointerToElement( VertexPtrPOS, &pElementPOS ); Ogre::Vector3 vertex(pElementPOS); vertex = rotation * vertex; if (mNormaliseNormals) { vertex.normalise(); } pElementPOS[0] = vertex.x; pElementPOS[1] = vertex.y; pElementPOS[2] = vertex.z; //mBoundingBox.merge(vertex); VertexPtrPOS+=VertSizePOS ; } //UNLOCK BUFFER if(VertexBufPOS->isLocked()){VertexBufPOS->unlock();} }
void MapCloudDisplay::update( float wall_dt, float ros_dt ) { rviz::PointCloud::RenderMode mode = (rviz::PointCloud::RenderMode) style_property_->getOptionInt(); if (needs_retransform_) { retransform(); needs_retransform_ = false; } { boost::mutex::scoped_lock lock(new_clouds_mutex_); if( !new_cloud_infos_.empty() ) { float size; if( mode == rviz::PointCloud::RM_POINTS ) { size = point_pixel_size_property_->getFloat(); } else { size = point_world_size_property_->getFloat(); } std::map<int, CloudInfoPtr>::iterator it = new_cloud_infos_.begin(); std::map<int, CloudInfoPtr>::iterator end = new_cloud_infos_.end(); for (; it != end; ++it) { CloudInfoPtr cloud_info = it->second; cloud_info->cloud_.reset( new rviz::PointCloud() ); cloud_info->cloud_->addPoints( &(cloud_info->transformed_points_.front()), cloud_info->transformed_points_.size() ); cloud_info->cloud_->setRenderMode( mode ); cloud_info->cloud_->setAlpha( alpha_property_->getFloat() ); cloud_info->cloud_->setDimensions( size, size, size ); cloud_info->cloud_->setAutoSize(false); cloud_info->manager_ = context_->getSceneManager(); cloud_info->scene_node_ = scene_node_->createChildSceneNode(); cloud_info->scene_node_->attachObject( cloud_info->cloud_.get() ); cloud_info->scene_node_->setVisible(false); cloud_infos_.insert(*it); } new_cloud_infos_.clear(); } } { boost::recursive_mutex::scoped_try_lock lock( transformers_mutex_ ); if( lock.owns_lock() ) { if( new_xyz_transformer_ || new_color_transformer_ ) { M_TransformerInfo::iterator it = transformers_.begin(); M_TransformerInfo::iterator end = transformers_.end(); for (; it != end; ++it) { const std::string& name = it->first; TransformerInfo& info = it->second; setPropertiesHidden( info.xyz_props, name != xyz_transformer_property_->getStdString() ); setPropertiesHidden( info.color_props, name != color_transformer_property_->getStdString() ); } } } new_xyz_transformer_ = false; new_color_transformer_ = false; } int totalPoints = 0; int totalNodesShown = 0; { // update poses boost::mutex::scoped_lock lock(current_map_mutex_); if(!current_map_.empty()) { for (std::map<int, rtabmap::Transform>::iterator it=current_map_.begin(); it != current_map_.end(); ++it) { std::map<int, CloudInfoPtr>::iterator cloudInfoIt = cloud_infos_.find(it->first); if(cloudInfoIt != cloud_infos_.end()) { totalPoints += cloudInfoIt->second->transformed_points_.size(); cloudInfoIt->second->pose_ = it->second; Ogre::Vector3 framePosition; Ogre::Quaternion frameOrientation; if (context_->getFrameManager()->getTransform(cloudInfoIt->second->message_->header, framePosition, frameOrientation)) { // Multiply frame with pose Ogre::Matrix4 frameTransform; frameTransform.makeTransform( framePosition, Ogre::Vector3(1,1,1), frameOrientation); const rtabmap::Transform & p = cloudInfoIt->second->pose_; Ogre::Matrix4 pose(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], 0, 0, 0, 1); frameTransform = frameTransform * pose; Ogre::Vector3 posePosition = frameTransform.getTrans(); Ogre::Quaternion poseOrientation = frameTransform.extractQuaternion(); poseOrientation.normalise(); cloudInfoIt->second->scene_node_->setPosition(posePosition); cloudInfoIt->second->scene_node_->setOrientation(poseOrientation); cloudInfoIt->second->scene_node_->setVisible(true); ++totalNodesShown; } else { ROS_ERROR("MapCloudDisplay: Could not update pose of node %d", it->first); } } } //hide not used clouds for(std::map<int, CloudInfoPtr>::iterator iter = cloud_infos_.begin(); iter!=cloud_infos_.end(); ++iter) { if(current_map_.find(iter->first) == current_map_.end()) { iter->second->scene_node_->setVisible(false); } } } } this->setStatusStd(rviz::StatusProperty::Ok, "Points", tr("%1").arg(totalPoints).toStdString()); this->setStatusStd(rviz::StatusProperty::Ok, "Nodes", tr("%1 shown of %2").arg(totalNodesShown).arg(cloud_infos_.size()).toStdString()); }
void Billboard::addTrajectoryPredictionMarkers() { visualization_msgs::InteractiveMarker predictionMarker; predictionMarker = object_; predictionMarker.controls.clear(); Ogre::Matrix3 *rotation = new Ogre::Matrix3(); Ogre::Quaternion orientation; orientation.x = direction_.x; orientation.y = direction_.y; orientation.z = direction_.z; orientation.w = direction_.w; orientation.normalise(); orientation.ToRotationMatrix(*rotation); Ogre::Vector3 position; position.x = velocity_; position.y = 0; position.z = 0; position = rotation->operator *(position); predictionMarker.pose.position.x = pose_.position.x; predictionMarker.pose.position.y = pose_.position.y; predictionMarker.pose.position.z = pose_.position.z; visualization_msgs::InteractiveMarkerControl predictionControl; predictionControl.name = "prediction_control"; predictionControl.always_visible = true; predictionControl.orientation_mode = InteractiveMarkerControl::VIEW_FACING; predictionControl.interaction_mode = InteractiveMarkerControl::NONE; for (int i = 1; i < PREDICTIONS_COUNT + 1; i++) { std::stringstream name; name << name_ << "_prediction_" << i; predictionMarker.name = name.str(); std::stringstream desc; desc << i << "s"; predictionMarker.description = desc.str(); predictionMarker.pose.position.x += position.x; predictionMarker.pose.position.y += position.y; predictionMarker.pose.position.z += position.z; predictionControl.markers.clear(); predictionMarker.controls.clear(); visualization_msgs::Marker sphere; sphere.type = visualization_msgs::Marker::SPHERE; sphere.color.g = 1; sphere.color.b = 1; sphere.color.a = 1; sphere.scale.x = PREDICTION_SPHERE_SIZE; sphere.scale.y = PREDICTION_SPHERE_SIZE; sphere.scale.z = PREDICTION_SPHERE_SIZE; predictionControl.markers.push_back(sphere); predictionMarker.controls.push_back(predictionControl); server_->insert(predictionMarker); } server_->applyChanges(); }
/* 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; }