MOgreDecal

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..


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
}

}

andyhebear1

11-12-2013 07:24:48


using System;
using System.Collections.Generic;
using System.Text;
using Mogre;


namespace MogreDecal
{

public class Triangle
{
//public:
// Triangle() { }
public Triangle() { }
//Triangle( const Ogre::Vector3& v1, const Ogre::Vector3& v2, const Ogre::Vector3& v3 )
//{
// v[0] = v1;
// v[1] = v2;
// v[2] = v3;

// normal = ( v[1] - v[0] ).crossProduct( v[2] - v[0] );
// normal.normalise();
//}
public Triangle(Mogre.Vector3 v1, Mogre.Vector3 v2, Mogre.Vector3 v3) {
v[0] = v1;
v[1] = v2;
v[2] = v3;

normal = (v[1] - v[0]).CrossProduct(v[2] - v[0]);
normal = normal.NormalisedCopy;
}
//Ogre::Vector3 v[3];
public Mogre.Vector3[] v = new Mogre.Vector3[3];
//Ogre::Vector3 normal;
public Mogre.Vector3 normal=new Vector3(0f,0f,0f);
}

public struct UniquePoint
{
public static UniquePoint Empty = new UniquePoint(new Vector3(0f,0f,0f),false);
//public:
//UniquePoint( const Ogre::Vector3& vertex, bool edge )
//{
// p = vertex;
// uvCoord.x = uvCoord.y = -1;

// isEdge = edge;
//}
public UniquePoint(Vector3 vertex, bool edge) {
p = vertex;
//uvCoord.x = uvCoord.y = -1;
uvCoord = new Vector2(-1f, -1f);
normal = new Vector3(0, 0, 0);
isEdge = edge;
}
//Ogre::Vector3 p;
public Mogre.Vector3 p;
//Ogre::Vector3 normal;
public Mogre.Vector3 normal;
// Ogre::Vector2 uvCoord;
public Mogre.Vector2 uvCoord;
//bool isEdge;
public bool isEdge;

internal void setNormal(Vector3 up_index_normal) {
//this.normal=new Vector3(up_index_normal.x,up_index_normal.y,up_index_normal.z);
this.normal.x = up_index_normal.x;
this.normal.y = up_index_normal.y;
this.normal.z = up_index_normal.z;
}
internal void setNormal(float nx, float ny, float nz) {
this.normal.x = nx;
this.normal.y = ny;
this.normal.z = nz;
}
internal void setuvCoord(Vector2 projectedPoint) {
uvCoord.x = projectedPoint.x;
uvCoord.y = projectedPoint.y;
}
internal void setuvCoord(float u, float v) {
uvCoord.x = u;
uvCoord.y = v;
}
}
public enum eBT_PLANE_INTERSECTION_TYPE
{
BT_CONST_BACK_PLANE = 0,
BT_CONST_COLLIDE_PLANE,
BT_CONST_FRONT_PLANE
}
public class DecalPolygon
{
public DecalPolygon(Mogre.Vector3 normal) {
norm = normal;
}
/// A list of indicies that index into the uniquePoints vector
//std::vector< int > points;
public List<int> points = new List<int>();
public Mogre.Vector3 norm = new Vector3(0, 0, 0);
}
public class DecalUtility
{
public const int MAX_CLIPPED_POINTS = 100;
public const float VEC_EPSILON = 0.001f; /// Used when comparing vectors for equality
/// 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 float BOX_PLANE_EPSILON = 0.000001f;

/*! Vector blending
Takes two vectors a, b, blends them together*/
static public void vec_blend(Mogre.Vector3 vr, Mogre.Vector3 va, Mogre.Vector3 vb, float blend_factor) {
vr = (1.0f - blend_factor) * va + blend_factor * vb;
}


///// Clips a polygon against an edge plane
//int plane_clip_polygon( const Ogre::Vector4 & plane, const Ogre::Vector3 * polygon_points, int polygon_point_count, Ogre::Vector3 * clipped);
//! This function calcs the distance from a 3D plane
static public void plane_clip_polygon_collect(
Mogre.Vector3 point0,
Mogre.Vector3 point1,
float dist0,
float dist1,
Mogre.Vector3[] clipped,
int clipped_count) {
bool _prevclassif = (dist0 > float.Epsilon);//DBL_EPSILON);
bool _classif = (dist1 > float.Epsilon);//DBL_EPSILON);
if (_classif != _prevclassif) {
float blendfactor = -dist0 / (dist1 - dist0);

assert(clipped_count < MAX_CLIPPED_POINTS);
vec_blend(clipped[clipped_count], point0, point1, blendfactor);
clipped_count++;
}
if (!_classif) {
assert(clipped_count < MAX_CLIPPED_POINTS);
clipped[clipped_count] = point1;
clipped_count++;
}
}

static internal void assert(bool p) {
throw new NotImplementedException();
}

static public float distance_point_plane(Vector4 plane, Vector3 point) {
return point.DotProduct(new Vector3(plane.x, plane.y, plane.z)) - plane[3];
}
static public int plane_clip_polygon(
Vector4 plane,
Vector3[] polygon_points,
int polygon_point_count,
Vector3[] clipped) {
int clipped_count = 0;


//clip first point
float firstdist = distance_point_plane(plane, polygon_points[0]);
if (!(firstdist > float.Epsilon))//DBL_EPSILON))
{
assert(clipped_count < MAX_CLIPPED_POINTS);

clipped[clipped_count] = polygon_points[0];
clipped_count++;
}

float olddist = firstdist;
for (int i = 1; i < polygon_point_count; i++) {
float dist = distance_point_plane(plane, polygon_points[i]);

plane_clip_polygon_collect(
polygon_points[i - 1], polygon_points[i],
olddist,
dist,
clipped,
clipped_count);


olddist = dist;
}

//RETURN TO FIRST point

plane_clip_polygon_collect(
polygon_points[polygon_point_count - 1], polygon_points[0],
olddist,
firstdist,
clipped,
clipped_count);

return clipped_count;
}
///Swap numbers
static public void BT_SWAP_NUMBERS(ref float a, ref float b) {
a = a + b;
b = a - b;
a = a - b;
}

static public bool TEST_CROSS_EDGE_BOX_MCR(Vector3 edge, Vector3 absolute_edge, Vector3 pointa, Vector3 pointb, Vector3 _extend,
int i_dir_0, int i_dir_1, int i_comp_0, int i_comp_1) {
float dir0 = -edge[i_dir_0];
float dir1 = edge[i_dir_1];
float pmin = pointa[i_comp_0] * dir0 + pointa[i_comp_1] * dir1;
float pmax = pointb[i_comp_0] * dir0 + pointb[i_comp_1] * dir1;

if (pmin > pmax) {
BT_SWAP_NUMBERS(ref pmin, ref pmax);
}

float abs_dir0 = absolute_edge[i_dir_0];
float abs_dir1 = absolute_edge[i_dir_1];
float rad = _extend[i_comp_0] * abs_dir0 + _extend[i_comp_1] * abs_dir1;

if (pmin > rad || -rad > pmax)
return false;

return true;
}
static public bool TEST_CROSS_EDGE_BOX_X_AXIS_MCR(Vector3 edge, Vector3 absolute_edge, Vector3 pointa,
Vector3 pointb, Vector3 _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 2, 1, 1, 2);
}

static public bool TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(Vector3 edge, Vector3 absolute_edge, Vector3 pointa,
Vector3 pointb, Vector3 _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 0, 2, 2, 0);
}

static public bool TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(Vector3 edge, Vector3 absolute_edge, Vector3 pointa,
Vector3 pointb, Vector3 _extend) {
return TEST_CROSS_EDGE_BOX_MCR(edge, absolute_edge, pointa, pointb, _extend, 1, 0, 0, 1);
}
static public void get_center_extend(Vector3 m_min, Vector3 m_max, out Vector3 center, out Vector3 extend) {
center = (m_max + m_min) * 0.5f;
extend = m_max - center;
}
static public void projection_interval(Vector3 m_min, Vector3 m_max, Vector3 direction, out float vmin, out float vmax) {
Vector3 center = (m_max + m_min) * 0.5f;
Vector3 extend = m_max - center;

float _fOrigin = direction.DotProduct(center);
float _fMaximumExtent = extend.DotProduct(new Vector3(fabs(direction.x), fabs(direction.y), fabs(direction.z)));
vmin = _fOrigin - _fMaximumExtent;
vmax = _fOrigin + _fMaximumExtent;
}

static internal float fabs(float p) {
return Mogre.Math.Abs(p);
//throw new NotImplementedException();
}
static public eBT_PLANE_INTERSECTION_TYPE plane_classify(Vector3 m_min, Vector3 m_max, Vector4 plane) {
float _fmin, _fmax;
projection_interval(m_min, m_max, new Vector3(plane.x, plane.y, plane.z), out _fmin, out _fmax);

if (plane[3] > _fmax + BOX_PLANE_EPSILON) {
return eBT_PLANE_INTERSECTION_TYPE.BT_CONST_BACK_PLANE; // 0
}

if (plane[3] + BOX_PLANE_EPSILON >= _fmin) {
return eBT_PLANE_INTERSECTION_TYPE.BT_CONST_COLLIDE_PLANE; //1
}
return eBT_PLANE_INTERSECTION_TYPE.BT_CONST_FRONT_PLANE;//2
}
//! Simple test for planes.
static public bool collide_plane(Vector3 m_min, Vector3 m_max, Vector4 plane) {
eBT_PLANE_INTERSECTION_TYPE classify = plane_classify(m_min, m_max, plane);
return (classify == eBT_PLANE_INTERSECTION_TYPE.BT_CONST_COLLIDE_PLANE);
}
///// Return true if the triangle intsersects the given AABB
//bool collide_triangle_exact( const Ogre::Vector3& m_min, const Ogre::Vector3& m_max, const Triangle& triangle);

//! test for a triangle, with edges
static public bool collide_triangle_exact(Vector3 m_min, Vector3 m_max, Triangle triangle) {

//Ogre::Vector3 n = (triangle.v[1] - triangle.v[0]).crossProduct( triangle.v[2] - triangle.v[0] );
//n.normalise();

Vector3 n = triangle.normal;

//Ogre::Vector4 triangle_plane( n.x, n.y, n.z, triangle.v[0].dotProduct( n ) );
Vector4 triangle_plane = new Vector4(n.x, n.y, n.z, triangle.v[0].DotProduct(n));

if (!collide_plane(m_min, m_max, triangle_plane))
return false;

Vector3 center, extends;
get_center_extend(m_min, m_max, out center, out extends);


//const Ogre::Vector3 v1(triangle.v[0] - center);
Vector3 v1 = (triangle.v[0] - center);
//const Ogre::Vector3 v2(triangle.v[1] - center);
Vector3 v2 = (triangle.v[1] - center);
//const Ogre::Vector3 v3(triangle.v[2] - center);
Vector3 v3 = (triangle.v[2] - center);
//First axis
Vector3 diff = (v2 - v1);
Vector3 abs_diff = new Vector3(fabs(diff.x), fabs(diff.y), fabs(diff.z)); //diff.absolute();
//Test With X axis
if (!TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v1, v3, extends))
return false;
//Test With Y axis
if (!TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v1, v3, extends))
return false;

//Test With Z axis
if (!TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v1, v3, extends))
return false;


diff = v3 - v2;
abs_diff = new Vector3(fabs(diff.x), fabs(diff.y), fabs(diff.z)); //diff.absolute();
//Test With X axis
if (!TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v2, v1, extends))
return false;

//Test With Y axis
if (!TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v2, v1, extends))
return false;
//Test With Z axis
if (!TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v2, v1, extends))
return false;

diff = v1 - v3;
abs_diff = new Vector3(fabs(diff.x), fabs(diff.y), fabs(diff.z)); //diff.absolute();
//Test With X axis
if (!TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff, abs_diff, v3, v2, extends))
return false;
//Test With Y axis
if (!TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff, abs_diff, v3, v2, extends))
return false;
//Test With Z axis
if (!TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff, abs_diff, v3, v2, extends))
return false;

return true;
}
//// Extract verticies and indicies from an Ogre3D Mesh into arrays
//void extractTrianglesFromMesh( std::vector<Triangle>& triangleList, const Ogre::MeshPtr& mesh, const Ogre::Vector3 &position,
// const Ogre::Quaternion &orient, Ogre::Vector3 scale);

///// Returns the area of a polygon
//double area3D_Polygon( int n, const Ogre::Vector3* V, const Ogre::Vector3& N );
static public float area3D_Polygon(int n, Vector3[] V, Vector3 N) {
float area = 0;
float an, ax, ay, az; // abs value of normal and its coords
int coord; // coord to ignore: 1=x, 2=y, 3=z
int i, j, k; // loop indices

// select largest abs coordinate to ignore for projection
ax = (N.x > 0 ? N.x : -N.x); // abs x-coord
ay = (N.y > 0 ? N.y : -N.y); // abs y-coord
az = (N.z > 0 ? N.z : -N.z); // abs z-coord

coord = 3; // ignore z-coord
if (ax > ay) {
if (ax > az) coord = 1; // ignore x-coord
}
else if (ay > az) coord = 2; // ignore y-coord

// compute area of the 2D projection
for (i = 1, j = 2, k = 0; i <= n; i++, j++, k++)
switch (coord) {
case 1:
area += (V[i].y * (V[j].z - V[k].z));
continue;
case 2:
area += (V[i].x * (V[j].z - V[k].z));
continue;
case 3:
area += (V[i].x * (V[j].y - V[k].y));
continue;
}

// scale to get area before projection
an = sqrt(ax * ax + ay * ay + az * az); // length of normal vector
switch (coord) {
case 1:
area *= (an / (2 * ax));
break;
case 2:
area *= (an / (2 * ay));
break;
case 3:
area *= (an / (2 * az));
break;
default:
break;
}
return fabs(area);
}

static internal float sqrt(float p) {
return Mogre.Math.Sqrt(p);
//throw new NotImplementedException();
}
///// Check for duplicates
//bool isDuplicate( const std::vector<UniquePoint>& uniquePoints, const Ogre::Vector3& p, int& duplicateIndex );
//bool isDuplicate( const std::vector< Ogre::Vector3 >& points, const Ogre::Vector3& p );
/// create a list of unique points, and a list of triangles with indicies into that list

static public bool isDuplicate(List<UniquePoint> uniquePoints, Vector3 p, int duplicateIndex) {
//std::vector<UniquePoint>::const_iterator iter;
int index = 0;
//for (iter = uniquePoints.begin(); iter != uniquePoints.end(); ++iter)
foreach (var iter in uniquePoints) {
if (fabs(iter.p.x - p.x) < VEC_EPSILON && fabs(iter.p.y - p.y) < VEC_EPSILON && fabs(iter.p.z - p.z) < VEC_EPSILON) {
duplicateIndex = index;
return true;
}

++index;
}

return false;
}
static public bool isDuplicate(List<Vector3> points, Vector3 p) {
//std::vector< Ogre::Vector3 >::const_iterator iter;
//for (iter = points.begin(); iter != points.end(); ++iter)
foreach (var iter in points) {
if (fabs(iter.x - p.x) < VEC_EPSILON && fabs(iter.y - p.y) < VEC_EPSILON && fabs(iter.z - p.z) < VEC_EPSILON) {
return true;
}

}

return false;
}
//double max( double a, double b );
//double min( double a, double b );
//double average( double a, double b );
static public float max(float a, float b) {
if (a > b)
return a;

return b;
}

static public float min(float a, float b) {
if (a < b)
return a;

return b;
}

static public float average(float a, float b) {
return (a + b) * 0.5f;
}
///// Return true if the triangle's bounding box intersects the given AABB
//bool collide_triangle_bounding_box( const Ogre::Vector3& aabbMin, const Ogre::Vector3& aabbMax, const Triangle& triangle );
static public bool collide_triangle_bounding_box(Vector3 aabbMin, Vector3 aabbMax, Triangle triangle) {
float minX, maxX, minY, maxY, minZ, maxZ, x, y, z;

minX = maxX = triangle.v[0].x;
minY = maxY = triangle.v[0].y;
minZ = maxZ = triangle.v[0].z;

for (int i = 1; i < 3; ++i) {
x = triangle.v[i].x;
y = triangle.v[i].y;
z = triangle.v[i].z;

if (x < minX)
minX = x;

if (x > maxX)
maxX = x;

if (y < minY)
minY = y;

if (y > maxY)
maxY = y;

if (z < minZ)
minZ = z;

if (z > maxZ)
maxZ = z;
}

if (minX > aabbMax.x || maxX < aabbMin.x || minY > aabbMax.y ||
maxY < aabbMin.y || minZ > aabbMax.z || maxZ < aabbMin.z) {
return false;
}

return true;
}
// Extract verticies and indicies from an Ogre3D Mesh into arrays
/// This is a modified version taken from the Ogre wiki
static public unsafe void extractTrianglesFromMesh(List<Triangle> triangleList, MeshPtr mesh,
Vector3 position,
Quaternion orient,
Vector3 scale) {

bool added_shared = false;
//size_t current_offset = 0;
//size_t shared_offset = 0;
//size_t next_offset = 0;
//size_t index_offset = 0;

//size_t index_count = 0;
//size_t vertex_count = 0;
uint current_offset = 0;
uint shared_offset = 0;
uint next_offset = 0;
uint index_offset = 0;

uint index_count = 0;
uint vertex_count = 0;
// Calculate how many vertices and indices we're going to need
for (ushort i = 0; i < mesh.NumSubMeshes; ++i) {
SubMesh submesh = mesh.GetSubMesh(i);

// We only need to add the shared vertices once
if (submesh.useSharedVertices) {
if (!added_shared) {
vertex_count += mesh.sharedVertexData.vertexCount;
added_shared = true;
}
}
else {
vertex_count += submesh.vertexData.vertexCount;
}

// Add the indices
index_count += submesh.indexData.indexCount;
}


// Allocate space for the vertices and indices
Vector3[] vertices = new Vector3[vertex_count];
ulong[] indices = new ulong[index_count];

added_shared = false;

// Run through the submeshes again, adding the data into the arrays
for (ushort i = 0; i < mesh.NumSubMeshes; ++i) {
SubMesh submesh = mesh.GetSubMesh(i);

VertexData vertex_data = submesh.useSharedVertices ? mesh.sharedVertexData : submesh.vertexData;

if ((!submesh.useSharedVertices) || (submesh.useSharedVertices && !added_shared)) {
if (submesh.useSharedVertices) {
added_shared = true;
shared_offset = current_offset;
}

VertexElement posElem =
vertex_data.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.VES_POSITION);

HardwareVertexBufferSharedPtr vbuf =
vertex_data.vertexBufferBinding.GetBuffer(posElem.Source);

//unsigned char* vertex =
//static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
byte* vertex = (byte*)vbuf.Lock(HardwareBuffer.LockOptions.HBL_READ_ONLY);
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
// as second argument. So make it float, to avoid trouble when Ogre::Real will
// be comiled/typedefed as double:
// Ogre::Real* pReal;
float* pReal;

for (uint j = 0; j < vertex_data.vertexCount; ++j, vertex += vbuf.VertexSize) {
posElem.BaseVertexPointerToElement(vertex, &pReal);

Vector3 pt = new Vector3(pReal[0], pReal[1], pReal[2]);

vertices[current_offset + j] = (orient * (pt * scale)) + position;
}

vbuf.Unlock();
next_offset += vertex_data.vertexCount;
}


IndexData index_data = submesh.indexData;
uint numTris = index_data.indexCount / 3;
HardwareIndexBufferSharedPtr ibuf = index_data.indexBuffer;

bool use32bitindexes = (ibuf.Type == HardwareIndexBuffer.IndexType.IT_32BIT);

//unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
ulong* pLong = (ulong*)(ibuf.Lock(HardwareBuffer.LockOptions.HBL_READ_ONLY));
//unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
ushort* pShort = (ushort*)pLong;

uint offset = (submesh.useSharedVertices) ? shared_offset : current_offset;

if (use32bitindexes) {
for (uint k = 0; k < numTris * 3; ++k) {
//indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset);
indices[index_offset++] = pLong[k] + (ulong)(offset);
}
}
else {
for (uint k = 0; k < numTris * 3; ++k) {
//indices[index_offset++] = static_cast<unsigned long>(pShort[k]) +
//static_cast<unsigned long>(offset);
indices[index_offset++] = (ulong)(pShort[k]) + (ulong)offset;
}
}

ibuf.Unlock();
current_offset = next_offset;
}


Vector3[] vertexPos = new Vector3[3];
Vector3 v;

for (uint i = 0; i < index_count; i += 3) {
for (int k = 0; k < 3; ++k) {
v = vertices[indices[i + k]];
vertexPos[k] = v;
}

//triangleList.push_back( Triangle( vertexPos[0], vertexPos[1], vertexPos[2] ) );
triangleList.Add(new Triangle(vertexPos[0], vertexPos[1], vertexPos[2]));
}

//delete [] vertices;
//delete [] indices;

}
///// Create a cube object, used for debug drawing
//Ogre::ManualObject* createCubeMesh(Ogre::SceneManager* sceneMgr, const Ogre::Vector3&pos, float size, Ogre::ColourValue color,
// Ogre::ManualObject* moDebug = 0, int offset = 0);
static public ManualObject createCubeMesh(SceneManager sceneMgr, Vector3 pos, float size, ColourValue color,
ManualObject moDebug, int offset) {
bool seperateSequence = false;

if (moDebug == null) {
seperateSequence = true;
moDebug = sceneMgr.CreateManualObject("decal_debug_" + Guid.NewGuid().ToString("N"));
}

if (seperateSequence)
moDebug.Begin("decal_debug_draw", RenderOperation.OperationTypes.OT_TRIANGLE_LIST);

float z1 = pos.z - size;
float z2 = pos.z + size;

float x1 = pos.x - size;
float x2 = pos.x + size;

float y1 = pos.y - size;
float y2 = pos.y + size;


moDebug.Position(x1, y1, z1); // 0
moDebug.Colour(color);
moDebug.Position(x2, y1, z1); // 1
moDebug.Colour(color);
moDebug.Position(x2, y2, z1); // 2
moDebug.Colour(color);
moDebug.Position(x1, y2, z1); // 3
moDebug.Colour(color);

moDebug.Position(x1, y1, z2); // 4
moDebug.Colour(color);
moDebug.Position(x2, y1, z2); // 5
moDebug.Colour(color);
moDebug.Position(x2, y2, z2); // 6
moDebug.Colour(color);
moDebug.Position(x1, y2, z2); // 7
moDebug.Colour(color);

moDebug.Triangle((ushort)(0 + offset), (ushort)(2 + offset), (ushort)(1 + offset));
moDebug.Triangle((ushort)(0 + offset), (ushort)(3 + offset), (ushort)(2 + offset));

moDebug.Triangle((ushort)(0 + offset), (ushort)(4 + offset), (ushort)(7 + offset));
moDebug.Triangle((ushort)(0 + offset), (ushort)(7 + offset), (ushort)(3 + offset));

moDebug.Triangle((ushort)(3 + offset), (ushort)(7 + offset), (ushort)(6 + offset));

moDebug.Triangle((ushort)(3 + offset), (ushort)(6 + offset), (ushort)(2 + offset));

moDebug.Triangle((ushort)(0 + offset), (ushort)(1 + offset), (ushort)(4 + offset));
moDebug.Triangle((ushort)(1 + offset), (ushort)(5 + offset), (ushort)(4 + offset));

moDebug.Triangle((ushort)(1 + offset), (ushort)(6 + offset), (ushort)(5 + offset));
moDebug.Triangle((ushort)(1 + offset), (ushort)(2 + offset), (ushort)(6 + offset));

moDebug.Triangle((ushort)(7 + offset), (ushort)(4 + offset), (ushort)(5 + offset));
moDebug.Triangle((ushort)(5 + offset), (ushort)(6 + offset), (ushort)(7 + offset));

if (seperateSequence)
moDebug.End();

return moDebug;

}

internal static int rand() {
return (int)Mogre.Math.RangeRandom(0f, 10000f);
//throw new NotImplementedException();
}
}
}



material debug_draw
{
technique
{
pass
{
lighting off
scene_blend alpha_blend
depth_check on
depth_write off
ambient vertexcolour
diffuse vertexcolour
specular vertexcolour
}
}
}

how to use?

/// This is the mesh object that we will pass to the decal generator.
/// Do not create any more than one OgreMesh per mesh, even if you have multiple instances of the same mesh in your scene.
OgreDecal::OgreMesh worldMesh;

/// This method will extract all of the triangles from the mesh to be used later. Only should be called once.
/// If you scale your mesh at all, pass it in here.
worldMesh.initialize( entity->getMesh(), 1.0 );

/// Get the DecalGenerator singleton and initialize it
OgreDecal::DecalGenerator& generator = OgreDecal::DecalGenerator::getSingleton();
generator.initialize( sceneMgr );

/// Set Decal parameters:
Ogre::Vector3 pos = getRaycastPoint(); /// Send a ray into the mesh
float width = 10;
float height = 10;
std::string textureName = "MyTexture"; /// Make sure your texture has a depth_bias greater than 1 to avoid z-fighting

/// We have everything ready to go. Now it's time to actually generate the decal:
OgreDecal::Decal decal = generator.createDecal( &worldMesh, pos, width, height, textureName );

/// Render the decal object. Always verify the returned object - it will be NULL if no decal could be created.
if (decal.object)
{
sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject( decal.object );
}

andyhebear1

11-12-2013 07:32:23

Example class using the Bullet physics engine

class BulletMesh : public OgreDecal::TriangleMesh, public btTriangleCallback
{
public:

BulletMesh()
{
mMesh = 0;
mTriangles = 0;
}

BulletMesh( btConcaveShape* mesh )
{
setMesh( mesh );
mTriangles = 0;
}

void setMesh( btConcaveShape* mesh )
{
mMesh = mesh;
}

void processTriangle( btVector3* triangle, int partId, int triangleIndex)
{
/// Convert Bullet vectors to Ogre vectors
Ogre::Vector3 v1( triangle[0].getX(), triangle[0].getY(), triangle[0].getZ() );
Ogre::Vector3 v2( triangle[1].getX(), triangle[1].getY(), triangle[1].getZ() );
Ogre::Vector3 v3( triangle[2].getX(), triangle[2].getY(), triangle[2].getZ() );

OgreDecal::Triangle t( v1, v2, v3 );

/// Check for false-positive
if (OgreDecal::collide_triangle_exact( mAABBMin, mAABBMax, t ))
mTriangles->push_back( t );
}

void findTrianglesInAABB( const Ogre::Vector3& aabbMin, const Ogre::Vector3& aabbMax, std::vector< OgreDecal::Triangle >& triangles )
{
mTriangles = &triangles;
mTriangles->clear();

mAABBMin = aabbMin;
mAABBMax = aabbMax;

if (mMesh)
mMesh->processAllTriangles( this, OgreToBullet(aabbMin), OgreToBullet(aabbMax) );

/// We no longer need to point to the triangle list
mTriangles = 0;
}

private:

Ogre::Vector3 mAABBMin, mAABBMax;
std::vector< OgreDecal::Triangle >* mTriangles;
btConcaveShape* mMesh;

};

andyhebear1

11-12-2013 07:33:16

Debug Drawing

/// At the top of OgreDecal.cpp, this is required:
const bool DEBUG_ENABLED = true;

OgreDecal::DecalGenerator::getSingleton().turnDebugOn();

/// Alternatively, you can flip the debug state on/off:
OgreDecal::DecalGenerator::getSingleton().flipDebug();