andyhebear1
11-12-2013 07:24:20
look office :http://www.ogre3d.org/tikiwiki/tiki-index.php?page=OgreDecal
git: https://github.com/jlanis/OgreDecal/tree/master/src
this decal is using in mogre,i change c++code to c# can used..
![](http://www.ogre3d.org/tikiwiki/tiki-download_file.php?fileId=2148&display&x=322&y=207)
![](http://www.ogre3d.org/tikiwiki/tiki-download_file.php?fileId=2149&display&x=360&y=217)
my blog:http://hi.baidu.com/rainssoft
git: https://github.com/jlanis/OgreDecal/tree/master/src
this decal is using in mogre,i change c++code to c# can used..
my blog:http://hi.baidu.com/rainssoft
using System;
using System.Collections.Generic;
using System.Text;
using Mogre;
namespace MogreDecal
{
/// Base class
public abstract class TriangleMesh
{
//public:
// /// Pure virtual function to be left implemented by the user for maximum flexbility
// /// @param triangles An empty list of triangles to be filled with the ones that are inside the AABB
// virtual void findTrianglesInAABB( const Ogre::Vector3& aabbMin, const Ogre::Vector3& aabbMax, std::vector< Triangle >& triangles ) = 0;
public abstract void findTrianglesInAABB(Vector3 aabbMin, Vector3 aabbMax, List<Triangle> triangles);
}
/// Only need to create one per mesh
public class OgreMesh : TriangleMesh
{
//public:
// OgreMesh() { }
public OgreMesh() { }
//OgreMesh( const Ogre::MeshPtr& mesh, const Ogre::Vector3& scale );
public OgreMesh(Mogre.MeshPtr mesh, Mogre.Vector3 scale) {
initialize(mesh, scale);
}
//void initialize( const Ogre::MeshPtr& mesh, const Ogre::Vector3& scale );
public void initialize(Mogre.MeshPtr mesh, Mogre.Vector3 scale) {
meshTriangles.Clear();//清理
DecalUtility.extractTrianglesFromMesh(meshTriangles, mesh, Vector3.ZERO, Quaternion.IDENTITY, scale);
}
// void findTrianglesInAABB( const Ogre::Vector3& aabbMin, const Ogre::Vector3& aabbMax, std::vector< Triangle >& triangles );
public override void findTrianglesInAABB(Mogre.Vector3 aabbMin, Mogre.Vector3 aabbMax, List<Triangle> intersecting_triangles) {
//std::vector<Triangle>::iterator iter;
//for (iter = meshTriangles.begin(); iter != meshTriangles.end(); ++iter)
foreach (var iter in meshTriangles) {
/// Check aginst triangle bounding box first to increase efficiency
if (DecalUtility.collide_triangle_bounding_box(aabbMin, aabbMax, iter)) {
/// Perform the actual triangle-AABB test
if (DecalUtility.collide_triangle_exact(aabbMin, aabbMax, iter)) {
//intersecting_triangles.push_back( *iter );
intersecting_triangles.Add(iter);
}
}
}
}
//private:
// std::vector< Triangle > meshTriangles;
private List<Triangle> meshTriangles = new List<Triangle>();
}
public class Decal
{
//public:
// Decal();
public Decal() {
}
/// Always NULL-check this object before using it.
// Ogre::ManualObject* object;
public Mogre.ManualObject @Object;
}
public class DecalGenerator : IDisposable
{
//DecalGenerator DecalGenerator::mInstance;
/// Set "true" for smooth shading (more efficient) and "false" for flat shading (less efficient)
/// If "true", each face will share vertex indicies with averaged normals
/// If set to "false", each face will need to send duplicated vertex information
//public const bool SHARE_VERTEX_NORMALS = true;
/// Set "true" to save debug drawing information
/// Should be "false" by default, unless you intend to draw debugging info
/// You should not enable debug drawing for dynamic decals
//public const bool DEBUG_ENABLED = false;
//public const int MAX_CLIPPED_POINTS = 100;
//public const float VEC_EPSILON = 0.001f; /// Used when comparing vectors for equality
//public:
// void initialize(Ogre::SceneManager* sceneManager);
public void initialize(Mogre.SceneManager sceneManager) {
sceneMgr = sceneManager;
mDebugVisible = false;
if (DecalUtility.DEBUG_ENABLED) {
mDebugNode = sceneMgr.RootSceneNode.CreateChildSceneNode();
}
else {
mDebugNode = null;
}
}
//
public void turnDebugOn() {
if (mDebugNode != null && DecalUtility.DEBUG_ENABLED) {
mDebugVisible = true;
mDebugNode.SetVisible(true, true);
}
}
public void turnDebugOff() {
if (mDebugNode != null && DecalUtility.DEBUG_ENABLED) {
mDebugVisible = false;
mDebugNode.SetVisible(false, true);
}
}
public void flipDebug() {
if (mDebugNode != null && DecalUtility.DEBUG_ENABLED) {
mDebugVisible = !mDebugVisible;
mDebugNode.SetVisible(mDebugVisible, true);
}
}
public static DecalGenerator getSingleton() { return mInstance; }
//public static DecalGenerator* getSingletonPtr() { return &mInstance; }
DecalGenerator() {
}
//~DecalGenerator(){
//}
/// left unimplemented to enforce singleton pattern
//DecalGenerator(DecalGenerator const&);
//void operator=(DecalGenerator const&);
//public static bool operator ==(DecalGenerator dg1,DecalGenerator dg2){
// return false;
//}
static DecalGenerator mInstance = new DecalGenerator();
//private:
//Ogre::SceneManager* sceneMgr;
Mogre.SceneManager sceneMgr;
//Ogre::SceneNode* mDebugNode;
Mogre.SceneNode mDebugNode;
bool mDebugVisible = false;
//std::vector< UniquePoint > uniquePoints;
List<UniquePoint> uniquePoints = new List<UniquePoint>();
//std::vector< Triangle > triangles;
List<Triangle> triangles = new List<Triangle>();
//std::vector< Ogre::Vector3 > polygon_points;
List<Vector3> polygon_points = new List<Vector3>();
//std::vector< DecalPolygon > finalPolys;
List<DecalPolygon> finalPolys = new List<DecalPolygon>();
//Ogre::Vector3 clippedPoints[ MAX_CLIPPED_POINTS ];
Mogre.Vector3[] clippedPoints = new Vector3[DecalUtility.MAX_CLIPPED_POINTS];
//bool pointWasClipped[ MAX_CLIPPED_POINTS ];
bool[] pointWasClipped = new bool[DecalUtility.MAX_CLIPPED_POINTS];
//void AddTriangle(Ogre::ManualObject* mo, std::vector< int >& points, int p1, int p2, int p3, Ogre::ManualObject* lines );
void AddTriangle(Mogre.ManualObject decalObject, List<int> points, int p1, int p2, int p3, Mogre.ManualObject lines) {
int ai = points[0];
int bi = points[p2 - p1];
int ci = points[p3 - p1];
if (!DecalUtility.SHARE_VERTEX_NORMALS) {
decalObject.Triangle((ushort)p1, (ushort)p2, (ushort)p3);
}
else {
decalObject.Triangle((ushort)ai, (ushort)bi, (ushort)ci);
}
/// Debug stuff
if (DecalUtility.DEBUG_ENABLED) {
Vector3 v1 = uniquePoints[ai].p;
Vector3 v2 = uniquePoints[bi].p;
Vector3 v3 = uniquePoints[ci].p;
lines.Colour(ColourValue.Red);
lines.Position(v1);
lines.Position(v2);
lines.Position(v1);
lines.Position(v3);
lines.Position(v2);
lines.Position(v3);
}
}
/*
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 )
public Decal creatDecal(TriangleMesh mesh, Vector3 pos, float width, float height,
string materialName, bool flipTexture, ManualObject decalObject) {
/// Clear out any old left-over stuff from the fridge.
triangles.Clear();
uniquePoints.Clear();
finalPolys.Clear();
polygon_points.Clear();
float depth = DecalUtility.max(width, height);
/// Define our AABB
Vector3 aabbMin = pos + new Vector3(-depth, -depth, -depth);
Vector3 aabbMax = pos + new Vector3(depth, depth, depth);
/// We're gonna need triangles. Lot's of triangles.
mesh.findTrianglesInAABB(aabbMin, aabbMax, triangles);
//if (triangles.empty())
if (triangles.Count == 0) {
/// No triangles were found, return an empty Decal
/// Note that the caller is responsible for verifying the returned object
return new Decal();
}
//std::vector< Triangle >::iterator iter;
//Ogre::Vector3 averageN(0, 0, 0);
Vector3 averageN = new Vector3(0f, 0f, 0f);
/// Calculate the average normal of all the triangles gathered from our AABB
//for (iter = triangles.begin(); iter != triangles.end(); ++iter)
foreach (var iter in triangles) {
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 < DecalUtility.VEC_EPSILON) {
return new Decal();
}
//averageN.normalise();
averageN = averageN.NormalisedCopy;
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 == Vector3.UNIT_Y)//Ogre::Vector3(0, 1, 0))
{
right = new Vector3(1f, 0f, 0f);
}
else if (averageN == Vector3.NEGATIVE_UNIT_Y)//Ogre::Vector3(0, -1, 0))
{
right = new Vector3(-1f, 0f, 0f);
}
else {
right = (-averageN).CrossProduct(Vector3.UNIT_Y);//Ogre::Vector3(0, 1, 0) );
}
//right.normalise();
right = right.NormalisedCopy;
up = right.CrossProduct(-averageN);
//up.normalise();
up = up.NormalisedCopy;
/// 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.
int NUM_EDGE_PLANES = 6;
//Ogre::Vector4 edgePlanes[NUM_EDGE_PLANES];
Vector4[] edgePlanes = new Vector4[NUM_EDGE_PLANES];
//Ogre::Vector3 planeR[6];
//Ogre::Vector3 planeN[6];
Vector3[] planeR = new Vector3[6];
Vector3[] planeN = new Vector3[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"
float distanceLimit = DecalUtility.sqrt((depth * depth) + (depth * depth)) * 1.25f;
float edgeLimitX = DecalUtility.sqrt((width * width) + (width * width)) * 1.05f;
float edgeLimitY = DecalUtility.sqrt((height * height) + (height * height)) * 1.05f;
/// 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 = new Vector4(planeN.x, planeN.y, planeN.z, planeR.DotProduct(planeN));
}
//Ogre::Vector3 averageNormal(0, 0, 0);
Vector3 averageNormal = new Vector3(0f, 0f, 0f);
float totalPoints = 0f;
Vector3 averagePoint=new Vector3(0f,0f,0f);
/// Loop through each triangle to find the meaning of life
//for (iter = triangles.begin(); iter != triangles.end(); ++iter)
foreach (var iter in triangles) {
polygon_points.Clear();
//polygon_points.push_back( iter->v[0] );
//polygon_points.push_back( iter->v[1] );
//polygon_points.push_back( iter->v[2] );
polygon_points.Add(iter.v[0]);
polygon_points.Add(iter.v[1]);
polygon_points.Add(iter.v[2]);
Vector3 n = iter.normal;
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?
//int clipped_count = DecalUtility.plane_clip_polygon( edgePlanes[ edge ], &(polygon_points[0]), polygon_points.size(), clippedPoints );
int clipped_count = DecalUtility.plane_clip_polygon(edgePlanes[edge], polygon_points.ToArray(), polygon_points.Count, clippedPoints);
polygon_points.Clear();
int index = 0;
for (int i = 0; i < clipped_count; ++i) {
Vector3 p = clippedPoints;
/// Do not use any duplicate points returned by plane_clip_polygon()
if (!DecalUtility.isDuplicate(polygon_points, p)) {
//polygon_points.push_back( p );
polygon_points.Add(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 < DecalUtility.VEC_EPSILON || (p - iter.v[1]).Length < DecalUtility.VEC_EPSILON || (p - iter.v[2]).Length < DecalUtility.VEC_EPSILON) {
pointWasClipped[index] = false;
}
else {
pointWasClipped[index] = true;
}
}
++index;
}
}
}
/// If we ended up with less points than what we started out with, then we're in big horse doo-doo
if (polygon_points.Count < 3)
continue;
//finalPolys.push_back( DecalPolygon( polygonNormal ) );
finalPolys.Add(new DecalPolygon(polygonNormal));
int size = polygon_points.Count;
float area = 1f;
/// Find the area of our freshly clipped polygon; used for generating a "better" vertex normal
if (polygon_points.Count >= 3) {
polygon_points.Add(polygon_points[0]);
polygon_points.Add(polygon_points[1]);
area = DecalUtility.area3D_Polygon(size, polygon_points.ToArray(), n);
}
/// Loop through each point in our clipped polygon, and find the unique ones.
for (int i = 0; i < polygon_points.Count - 2; ++i) {
Vector3 p = polygon_points;
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.Count;
/// If a duplicate is found, uniqueIndex will be set to that point
if (!DecalUtility.isDuplicate(uniquePoints, p, uniqueIndex)) {
uniquePoints.Add(new UniquePoint(p, pointWasClipped));
}
/// Make sure we're still OK
DecalUtility.assert(uniqueIndex >= 0 && uniqueIndex < uniquePoints.Count);
// Update the normal for this point (we'll normalize it later). NormaLIZE.
//uniquePoints[ uniqueIndex ].normal += (polygonNormal * area);
Vector3 up_index_normal = uniquePoints[uniqueIndex].normal + (polygonNormal * area);
uniquePoints[uniqueIndex].setNormal(up_index_normal);
//finalPolys.back().points.push_back( uniqueIndex );
finalPolys[finalPolys.Count - 1].points.Add(uniqueIndex);
}
}
averageNormal += (n * area);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ///
/// 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();
averageNormal = averageNormal.NormalisedCopy;
averagePoint /= totalPoints;
Vector3 projectionPlaneNormal = -averageN;
Vector3 projectionPlaneRight = right;
//projectionPlaneRight.normalise();
projectionPlaneRight = projectionPlaneRight.NormalisedCopy;
Vector3 projectionPlaneUp = up;
//projectionPlaneUp.normalise();
projectionPlaneUp = projectionPlaneUp.NormalisedCopy;
Quaternion planeOrien = new Quaternion(projectionPlaneRight, projectionPlaneUp, -projectionPlaneNormal);
//Quaternion finalOrien=new Quaternion( new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1) );
Quaternion finalOrien = new Quaternion(Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.NEGATIVE_UNIT_Z);
planeOrien.Normalise();
finalOrien.Normalise();
//todo? 需要除? planeOrien=planeOrien*(1f/planeOrien.Norm);
/// 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.
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;
float leftMost=0f, rightMost=0f, topMost=0f, bottomMost=0f;
bool initCorners = false;
Vector3 center = finalQuat * pos;
Vector2 centerPoint = new Vector2(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)
foreach (var pointIter in uniquePoints) {
/// 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
Vector3 v = finalQuat * pointIter.p;
/// Project/flatten the point by eliminating the Z coordinate
Vector2 projectedPoint = new Vector2(v.x, v.y);
//pointIter.uvCoord = projectedPoint;
pointIter.setuvCoord(projectedPoint);
/// Find the left, right, top, and bottom edge
if (pointIter.isEdge) {
Vector2 diff = (projectedPoint - centerPoint);
/// More fudge-checking to make sure nothing is out of bounds
if (DecalUtility.fabs(diff.x) < edgeLimitX && DecalUtility.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;
UniquePoint topRight=UniquePoint.Empty, bottomRight=UniquePoint.Empty, topLeft=UniquePoint.Empty, bottomLeft=UniquePoint.Empty;
Vector2 cornerTopLeft = new Vector2(leftMost, topMost);
Vector2 cornerTopRight = new Vector2(rightMost, topMost);
Vector2 cornerBottomLeft = new Vector2(leftMost, bottomMost);
Vector2 cornerBottomRight = new Vector2(rightMost, bottomMost);
bool initValues = false;
float minDistanceTopLeft=0f, minDistanceTopRight=0f, minDistanceBottomLeft=0f, minDistanceBottomRight=0f;
//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)
foreach (var projectedPointIter in uniquePoints) {
Vector2 p = projectedPointIter.uvCoord;
float distanceTopLeft = (p - cornerTopLeft).Length;
float distanceTopRight = (p - cornerTopRight).Length;
float distanceBottomLeft = (p - cornerBottomLeft).Length;
float 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 = DecalUtility.average(DecalUtility.average(topRight.uvCoord.x, bottomRight.uvCoord.x), rightMost);
leftMost = DecalUtility.average(DecalUtility.average(topLeft.uvCoord.x, bottomLeft.uvCoord.x), leftMost);
topMost = DecalUtility.average(DecalUtility.average(topLeft.uvCoord.y, topRight.uvCoord.y), topMost);
bottomMost = DecalUtility.average(DecalUtility.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 = DecalUtility.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)
foreach (var projectedPointIter in uniquePoints) {
Vector2 p = projectedPointIter.uvCoord;
float uvMin = 0;
float uvMax = 1;
/// Ta da!
float u = (p.x - leftMost) / width;
float 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);
projectedPointIter.setuvCoord(new Vector2(u, 1f - 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);
projectedPointIter.setuvCoord(new Vector2((1f - u), (1f - v)));
}
break;
case 2: {
//projectedPointIter->uvCoord.x = (1 - u);
//projectedPointIter->uvCoord.y = v;
projectedPointIter.setuvCoord(new Vector2((1f - u), (v)));
}
break;
case 3: {
//projectedPointIter->uvCoord.x = u;
//projectedPointIter->uvCoord.y = v;
projectedPointIter.setuvCoord(new Vector2((u), (v)));
}
break;
case 4: {
//projectedPointIter->uvCoord.y = (1 - u);
//projectedPointIter->uvCoord.x = (1 - v);
projectedPointIter.setuvCoord(new Vector2((1f - u), (1f - v)));
}
break;
case 5: {
//projectedPointIter->uvCoord.y = (1 - u);
//projectedPointIter->uvCoord.x = v;
projectedPointIter.setuvCoord(new Vector2((1f - u), (v)));
}
break;
case 6: {
//projectedPointIter->uvCoord.y = u;
//projectedPointIter->uvCoord.x = v;
projectedPointIter.setuvCoord(new Vector2((u), (v)));
}
break;
case 7: {
//projectedPointIter->uvCoord.y = u;
//projectedPointIter->uvCoord.x = (1 - v);
projectedPointIter.setuvCoord(new Vector2((u), (1f - v)));
}
break;
default:
break;
}
}
}
/// 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 (DecalUtility.DEBUG_ENABLED) {
ManualObject moDebug = sceneMgr.CreateManualObject("decal_debug_" + Guid.NewGuid().ToString("N"));
moDebug.Begin("debug_draw", RenderOperation.OperationTypes.OT_TRIANGLE_LIST);
int indexOffset = 0;
//for (uniqueIter = uniquePoints.begin(); uniqueIter != uniquePoints.end(); ++uniqueIter)
foreach (var uniqueIter in uniquePoints) {
DecalUtility.createCubeMesh(sceneMgr, uniqueIter.p, 0.25f, ColourValue.Red, moDebug, indexOffset);
indexOffset += 8;
}
moDebug.End();
if (!mDebugVisible)
moDebug.Visible = (false);
mDebugNode.AttachObject(moDebug);
}
/// "lines" is used for debug drawing triangles
ManualObject lines = null;
if (DecalUtility.DEBUG_ENABLED) {
lines = sceneMgr.CreateManualObject("decal_line_" + Guid.NewGuid().ToString("N"));
lines.Begin("debug_draw", RenderOperation.OperationTypes.OT_LINE_LIST);
}
/// Create a new manual object if this one doesn't exist
if (decalObject == null) {
decalObject = sceneMgr.CreateManualObject("decal_obj_" + Guid.NewGuid().ToString("N"));
}
else {
/// Make sure the decal object can be dynmically updated
if (!decalObject.Dynamic)
decalObject.Dynamic = (true);
}
string material = materialName;
if (decalObject.Dynamic && decalObject.NumSections > 0) {
/// Update the existng decal instead of starting a new one
decalObject.BeginUpdate(0);
}
else {
/// Start a new decal
decalObject.Begin(material, RenderOperation.OperationTypes.OT_TRIANGLE_LIST);
}
/// If we're sharing vertices, then simply set up all of the vertex info ahead of time
if (DecalUtility.SHARE_VERTEX_NORMALS) {
//for (uniqueIter = uniquePoints.begin(); uniqueIter != uniquePoints.end(); ++uniqueIter)
foreach (var uniqueIter in uniquePoints) {
uniqueIter.normal.Normalise();//?
decalObject.Position(uniqueIter.p);
decalObject.TextureCoord(uniqueIter.uvCoord);
decalObject.Normal(uniqueIter.normal);
}
}
int p1, p2, p3;
p1 = p2 = p3 = 0;
//std::vector< DecalPolygon >::iterator pIter;
// Each of these finalPolys is a just list of indicies into the uniquePoints vector
//for (pIter = finalPolys.begin(); pIter != finalPolys.end(); ++pIter)
foreach (var pIter in finalPolys) {
//std::vector< int >::iterator iter;
//int iter;
Vector3 norm = pIter.norm;
if (pIter.points.Count >= 3) {
p2 = p1 + 1;
p3 = p2 + 1;
int t = 0;
//for (iter = pIter->points.begin(); iter != pIter->points.end(); ++iter)
foreach (var iter in pIter.points) {
if (!DecalUtility.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 (DecalUtility.DEBUG_ENABLED) {
lines.End();
if (!mDebugVisible)
lines.Visible = (false);
mDebugNode.AttachObject(lines);
}
/// And were done. Phew.
Decal decal = new Decal();
decal.Object = decalObject;
return decal;
}
#region IDisposable 成员
public void Dispose() {
throw new NotImplementedException();
}
#endregion
}
}