prim cuts in ODE

Much thanks to Gerhard!
Merged with Darok's recent changes re: physical prims
afrisby
dan miller 2007-11-05 12:25:53 +00:00
parent 6bb1e91d41
commit fdb57b28b1
8 changed files with 507 additions and 516 deletions

View File

@ -221,6 +221,14 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
set { } set { }
} }
public override PrimitiveBaseShape Shape
{
set
{
return;
}
}
public override PhysicsVector Velocity public override PhysicsVector Velocity
{ {
get { return _velocity; } get { return _velocity; }

View File

@ -686,6 +686,15 @@ namespace OpenSim.Region.Physics.BulletXPlugin
get { return _size; } get { return _size; }
set { lock (BulletXScene.BulletXLock) { _size = value; } } set { lock (BulletXScene.BulletXLock) { _size = value; } }
} }
public override PrimitiveBaseShape Shape
{
set
{
return;
}
}
public override PhysicsVector Acceleration public override PhysicsVector Acceleration
{ {
get { return _acceleration; } get { return _acceleration; }

View File

@ -26,6 +26,7 @@
* *
*/ */
using Axiom.Math; using Axiom.Math;
using OpenSim.Framework;
namespace OpenSim.Region.Physics.Manager namespace OpenSim.Region.Physics.Manager
{ {
@ -50,6 +51,11 @@ namespace OpenSim.Region.Physics.Manager
public abstract PhysicsVector Size { get; set; } public abstract PhysicsVector Size { get; set; }
public abstract PrimitiveBaseShape Shape
{
set;
}
public abstract PhysicsVector Position { get; set; } public abstract PhysicsVector Position { get; set; }
public abstract PhysicsVector Velocity { get; set; } public abstract PhysicsVector Velocity { get; set; }
@ -85,6 +91,14 @@ namespace OpenSim.Region.Physics.Manager
set { return; } set { return; }
} }
public override PrimitiveBaseShape Shape
{
set
{
return;
}
}
public override PhysicsVector Velocity public override PhysicsVector Velocity
{ {
get { return PhysicsVector.Zero; } get { return PhysicsVector.Zero; }

View File

@ -25,6 +25,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*/ */
using System;
namespace OpenSim.Region.Physics.Manager namespace OpenSim.Region.Physics.Manager
{ {
public class PhysicsVector public class PhysicsVector
@ -50,5 +54,51 @@ namespace OpenSim.Region.Physics.Manager
{ {
return "<" + X + "," + Y + "," + Z + ">"; return "<" + X + "," + Y + "," + Z + ">";
} }
// Operations
public static PhysicsVector operator +(PhysicsVector a, PhysicsVector b)
{
return new PhysicsVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
public static PhysicsVector operator -(PhysicsVector a, PhysicsVector b)
{
return new PhysicsVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
}
public static PhysicsVector cross(PhysicsVector a, PhysicsVector b)
{
return new PhysicsVector(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
}
public float length()
{
return (float)Math.Sqrt(X*X + Y*Y + Z*Z);
}
public static PhysicsVector operator / (PhysicsVector v, float f)
{
return new PhysicsVector(v.X / f, v.Y / f, v.Z / f);
}
public static PhysicsVector operator *(PhysicsVector v, float f)
{
return new PhysicsVector(v.X * f, v.Y * f, v.Z * f);
}
public static PhysicsVector operator *(float f, PhysicsVector v)
{
return v * f;
}
public virtual bool IsIdentical(PhysicsVector v, float tolerance)
{
PhysicsVector diff = this - v;
float d = diff.length();
if (d < tolerance)
return true;
return false;
}
} }
} }

View File

@ -30,37 +30,63 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
public class Vertex : IComparable<Vertex> using OpenSim.Region.Physics.OdePlugin.Meshing;
{
public String name;
public PhysicsVector point;
public Vertex(String name, float x, float y, float z) public class Vertex : PhysicsVector, IComparable<Vertex>
{
public Vertex(float x, float y, float z)
: base(x, y, z)
{ {
this.name = name;
point = new PhysicsVector(x, y, z);
} }
public Vertex(PhysicsVector v)
: base(v.X, v.Y, v.Z)
{
}
public Vertex Clone()
{
return new Vertex(X, Y, Z);
}
public static Vertex FromAngle(double angle)
{
return new Vertex((float)Math.Cos(angle), (float)Math.Sin(angle), 0.0f);
}
public virtual bool Equals(Vertex v, float tolerance)
{
PhysicsVector diff = this - v;
float d = diff.length();
if (d < tolerance)
return true;
return false;
}
public int CompareTo(Vertex other) public int CompareTo(Vertex other)
{ {
if (point.X < other.point.X) if (X < other.X)
return -1; return -1;
if (point.X > other.point.X) if (X > other.X)
return 1; return 1;
if (point.Y < other.point.Y) if (Y < other.Y)
return -1; return -1;
if (point.Y > other.point.Y) if (Y > other.Y)
return 1; return 1;
if (point.Z < other.point.Z) if (Z < other.Z)
return -1; return -1;
if (point.Z > other.point.Z) if (Z > other.Z)
return 1; return 1;
return 0; return 0;
@ -75,52 +101,25 @@ public class Vertex : IComparable<Vertex>
{ {
return me.CompareTo(other) < 0; return me.CompareTo(other) < 0;
} }
public String ToRaw()
{
// Why this stuff with the number formatter?
// Well, the raw format uses the english/US notation of numbers
// where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1.
// The german notation uses these characters exactly vice versa!
// The Float.ToString() routine is a localized one, giving different results depending on the country
// settings your machine works with. Unusable for a machine readable file format :-(
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalSeparator = ".";
nfi.NumberDecimalDigits = 3;
String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi);
return s1;
}
} }
public class Simplex : IComparable<Simplex>
{
public Vertex v1;
public Vertex v2;
public Simplex(Vertex _v1, Vertex _v2)
{
// Presort indices to make sorting (comparing) easier
if (_v1 > _v2)
{
v1 = _v1;
v2 = _v2;
}
else
{
v1 = _v2;
v2 = _v1;
}
}
public int CompareTo(Simplex other)
{
if (v1 > other.v1)
{
return 1;
}
if (v1 < other.v1)
{
return -1;
}
if (v2 > other.v2)
{
return 1;
}
if (v2 < other.v2)
{
return -1;
}
return 0;
}
} ;
public class Triangle public class Triangle
{ {
public Vertex v1; public Vertex v1;
@ -155,6 +154,12 @@ public class Triangle
return false; return false;
} }
public bool isDegraded()
{
// This means, the vertices of this triangle are somewhat strange.
// They either line up or at least two of them are identical
return (radius_square == 0.0);
}
private void CalcCircle() private void CalcCircle()
{ {
@ -184,14 +189,14 @@ public class Triangle
double rx, ry; double rx, ry;
// Readout the three points, the triangle consists of // Readout the three points, the triangle consists of
p1x = v1.point.X; p1x = v1.X;
p1y = v1.point.Y; p1y = v1.Y;
p2x = v2.point.X; p2x = v2.X;
p2y = v2.point.Y; p2y = v2.Y;
p3x = v3.point.X; p3x = v3.X;
p3y = v3.point.Y; p3y = v3.Y;
/* calc helping values first */ /* calc helping values first */
c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2; c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2;
@ -253,12 +258,9 @@ public class Triangle
nfi.CurrencyDecimalDigits = 2; nfi.CurrencyDecimalDigits = 2;
nfi.CurrencyDecimalSeparator = "."; nfi.CurrencyDecimalSeparator = ".";
String s1 = "<" + v1.point.X.ToString(nfi) + "," + v1.point.Y.ToString(nfi) + "," + v1.point.Z.ToString(nfi) + String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">";
">"; String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">";
String s2 = "<" + v2.point.X.ToString(nfi) + "," + v2.point.Y.ToString(nfi) + "," + v2.point.Z.ToString(nfi) + String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">";
">";
String s3 = "<" + v3.point.X.ToString(nfi) + "," + v3.point.Y.ToString(nfi) + "," + v3.point.Z.ToString(nfi) +
">";
return s1 + ";" + s2 + ";" + s3; return s1 + ";" + s2 + ";" + s3;
} }
@ -271,23 +273,17 @@ public class Triangle
PhysicsVector e1; PhysicsVector e1;
PhysicsVector e2; PhysicsVector e2;
e1 = new PhysicsVector(v1.point.X - v2.point.X, v1.point.Y - v2.point.Y, v1.point.Z - v2.point.Z); e1 = new PhysicsVector(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
e2 = new PhysicsVector(v1.point.X - v3.point.X, v1.point.Y - v3.point.Y, v1.point.Z - v3.point.Z); e2 = new PhysicsVector(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z);
// Cross product for normal // Cross product for normal
PhysicsVector n = new PhysicsVector(); PhysicsVector n = PhysicsVector.cross(e1, e2);
float nx, ny, nz;
n.X = e1.Y*e2.Z - e1.Z*e2.Y;
n.Y = e1.Z*e2.X - e1.X*e2.Z;
n.Z = e1.X*e2.Y - e1.Y*e2.X;
// Length // Length
float l = (float) Math.Sqrt(n.X*n.X + n.Y*n.Y + n.Z*n.Z); float l = n.length();
// Normalized "normal" // Normalized "normal"
n.X /= l; n = n / l;
n.Y /= l;
n.Z /= l;
return n; return n;
} }
@ -299,4 +295,12 @@ public class Triangle
v1 = v2; v1 = v2;
v2 = vt; v2 = vt;
} }
}
// Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and
// debugging purposes
public String ToStringRaw()
{
String output = v1.ToRaw() + " " + v2.ToRaw() + " " +v3.ToRaw();
return output;
}
}

View File

@ -27,109 +27,70 @@
*/ */
using System; using System;
using System.IO;
using System.Globalization;
using System.Diagnostics;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.OdePlugin namespace OpenSim.Region.Physics.OdePlugin.Meshing
{ {
public class Mesh
{
public List<Vertex> vertices;
public List<Triangle> triangles;
public float[] normals;
public Mesh()
{
vertices = new List<Vertex>();
triangles = new List<Triangle>();
}
public void Add(Triangle triangle)
{
int i;
i = vertices.IndexOf(triangle.v1);
if (i < 0)
throw new ArgumentException("Vertex v1 not known to mesh");
i = vertices.IndexOf(triangle.v2);
if (i < 0)
throw new ArgumentException("Vertex v2 not known to mesh");
i = vertices.IndexOf(triangle.v3);
if (i < 0)
throw new ArgumentException("Vertex v3 not known to mesh");
triangles.Add(triangle);
}
public void Add(Vertex v)
{
vertices.Add(v);
}
public float[] getVertexListAsFloat()
{
float[] result = new float[vertices.Count*3];
for (int i = 0; i < vertices.Count; i++)
{
Vertex v = vertices[i];
PhysicsVector point = v.point;
result[3*i + 0] = point.X;
result[3*i + 1] = point.Y;
result[3*i + 2] = point.Z;
}
GCHandle.Alloc(result, GCHandleType.Pinned);
return result;
}
public int[] getIndexListAsInt()
{
int[] result = new int[triangles.Count*3];
for (int i = 0; i < triangles.Count; i++)
{
Triangle t = triangles[i];
result[3*i + 0] = vertices.IndexOf(t.v1);
result[3*i + 1] = vertices.IndexOf(t.v2);
result[3*i + 2] = vertices.IndexOf(t.v3);
}
GCHandle.Alloc(result, GCHandleType.Pinned);
return result;
}
public void Append(Mesh newMesh)
{
foreach (Vertex v in newMesh.vertices)
vertices.Add(v);
foreach (Triangle t in newMesh.triangles)
Add(t);
}
}
public class Meshmerizer public class Meshmerizer
{ {
// Setting baseDir to a path will enable the dumping of raw files
// raw files can be imported by blender so a visual inspection of the results can be done
// const string baseDir = "rawFiles";
const string baseDir = null;
static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, ref float lambda, ref float mu)
{
// p1, p2, points on the straight
// r1, r2, directional vectors of the straight. Not necessarily of length 1!
// note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
// thus allowing to decide whether an intersection is between two points
float r1x = r1.X;
float r1y = r1.Y;
float r2x = r2.X;
float r2y = r2.Y;
float denom = r1y*r2x - r1x*r2y;
if (denom == 0.0)
{
lambda = Single.NaN;
mu = Single.NaN;
return;
}
float p1x = p1.X;
float p1y = p1.Y;
float p2x = p2.X;
float p2y = p2.Y;
lambda = (-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x) / denom;
mu = (-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x) / denom;
}
private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v) private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v)
{ {
List<Triangle> influenced = new List<Triangle>(); List<Triangle> influenced = new List<Triangle>();
foreach (Triangle t in triangles) foreach (Triangle t in triangles)
{ {
float dx, dy; if (t.isInCircle(v.X, v.Y))
if (t.isInCircle(v.point.X, v.point.Y))
{ {
influenced.Add(t); influenced.Add(t);
} }
} }
return influenced; return influenced;
} }
private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles, private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles)
List<int> innerBorders)
{ {
// This is a variant of the delaunay algorithm // This is a variant of the delaunay algorithm
// each time a new vertex is inserted, all triangles that are influenced by it are deleted // each time a new vertex is inserted, all triangles that are influenced by it are deleted
@ -148,8 +109,10 @@ namespace OpenSim.Region.Physics.OdePlugin
// do not fulfill this condition with respect to the new triangle // do not fulfill this condition with respect to the new triangle
// Find the triangles that are influenced by the new vertex // Find the triangles that are influenced by the new vertex
Vertex v = vertices[iCurrentVertex]; Vertex v=vertices[iCurrentVertex];
List<Triangle> influencedTriangles = FindInfluencedTriangles(triangles, v); if (v == null)
continue; // Null is polygon stop marker. Ignore it
List<Triangle> influencedTriangles=FindInfluencedTriangles(triangles, v);
List<Simplex> simplices = new List<Simplex>(); List<Simplex> simplices = new List<Simplex>();
@ -163,11 +126,12 @@ namespace OpenSim.Region.Physics.OdePlugin
simplices.AddRange(newSimplices); simplices.AddRange(newSimplices);
triangles.Remove(t); triangles.Remove(t);
} }
// Now sort the simplices. That will make identical ones side by side in the list // Now sort the simplices. That will make identical ones reside side by side in the list
simplices.Sort(); simplices.Sort();
// Look for duplicate simplices here. // Look for duplicate simplices here.
// Remember, they are directly side by side in the list right now // Remember, they are directly side by side in the list right now,
// So we only check directly neighbours
int iSimplex; int iSimplex;
List<Simplex> innerSimplices = new List<Simplex>(); List<Simplex> innerSimplices = new List<Simplex>();
for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards
@ -186,310 +150,145 @@ namespace OpenSim.Region.Physics.OdePlugin
// each simplex still in the list belongs to the hull of the region in question // each simplex still in the list belongs to the hull of the region in question
// The new vertex (yes, we still deal with verices here :-) ) forms a triangle // The new vertex (yes, we still deal with verices here :-) ) forms a triangle
// With each of these simplices. Build the new triangles and add them to the list // with each of these simplices. Build the new triangles and add them to the list
foreach (Simplex s in simplices) foreach (Simplex s in simplices)
{ {
Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]); Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]);
triangles.Add(t); if (!t.isDegraded())
{
triangles.Add(t);
}
} }
} }
// At this point all vertices should be inserted into the mesh
// But the areas, that should be kept free still are filled with triangles
// We have to remove them. For this we have a list of indices to vertices.
// Each triangle that solemnly constists of vertices from the inner border
// are deleted
List<Triangle> innerTriangles = new List<Triangle>();
foreach (Triangle t in triangles)
{
if (
innerBorders.Contains(vertices.IndexOf(t.v1))
&& innerBorders.Contains(vertices.IndexOf(t.v2))
&& innerBorders.Contains(vertices.IndexOf(t.v3))
)
innerTriangles.Add(t);
}
foreach (Triangle t in innerTriangles)
{
triangles.Remove(t);
}
} }
private static Mesh CreateBoxMeshX(PrimitiveBaseShape primShape, PhysicsVector size) static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
// Builds the x (+ and -) surfaces of a box shaped prim // Builds the z (+ and -) surfaces of a box shaped prim
{ {
UInt16 hollowFactor = primShape.ProfileHollow; UInt16 hollowFactor = primShape.ProfileHollow;
Mesh meshMX = new Mesh(); UInt16 profileBegin = primShape.ProfileBegin;
UInt16 profileEnd = primShape.ProfileEnd;
// Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
// of a block are basically the same
// They may be warped differently but the shape is identical
// So we only create one surface as a model and derive both plus and minus surface of the block from it
// This is done in a model space where the block spans from -.5 to +.5 in X and Y
// The mapping to Scene space is done later during the "extrusion" phase
// Surface 0, -X // Base
meshMX.Add(new Vertex("-X-Y-Z", -size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f)); Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f);
meshMX.Add(new Vertex("-X+Y-Z", -size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f)); Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f);
meshMX.Add(new Vertex("-X-Y+Z", -size.X/2.0f, -size.Y/2.0f, +size.Z/2.0f)); Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f);
meshMX.Add(new Vertex("-X+Y+Z", -size.X/2.0f, +size.Y/2.0f, +size.Z/2.0f)); Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f);
meshMX.Add(new Triangle(meshMX.vertices[0], meshMX.vertices[2], meshMX.vertices[1])); Meshing.SimpleHull outerHull = new SimpleHull();
meshMX.Add(new Triangle(meshMX.vertices[1], meshMX.vertices[2], meshMX.vertices[3])); outerHull.AddVertex(MM);
outerHull.AddVertex(PM);
outerHull.AddVertex(PP);
outerHull.AddVertex(MP);
// Deal with cuts now
if ((profileBegin != 0) || (profileEnd != 0))
{
double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; // In degree, for easier debugging and understanding
fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
fProfileEndAngle -= (90.0 + 45.0);
if (fProfileBeginAngle < fProfileEndAngle)
fProfileEndAngle -= 360.0;
Mesh meshPX = new Mesh(); // Note, that we don't want to cut out a triangle, even if this is a
// Surface 1, +X // good approximation for small cuts. Indeed we want to cut out an arc
meshPX.Add(new Vertex("+X-Y-Z", +size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f)); // and we approximate this arc by a polygon chain
meshPX.Add(new Vertex("+X+Y-Z", +size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f)); // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
meshPX.Add(new Vertex("+X-Y+Z", +size.X/2.0f, -size.Y/2.0f, +size.Z/2.0f)); // So it can easily be subtracted from the outer hull
meshPX.Add(new Vertex("+X+Y+Z", +size.X/2.0f, +size.Y/2.0f, +size.Z/2.0f)); int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); // how many steps do we need with approximately 45 degree
double dStepWidth=(fProfileBeginAngle-fProfileEndAngle)/iSteps;
Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
meshPX.Add(new Triangle(meshPX.vertices[0], meshPX.vertices[1], meshPX.vertices[2])); // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
meshPX.Add(new Triangle(meshPX.vertices[2], meshPX.vertices[1], meshPX.vertices[3])); SimpleHull cutHull = new SimpleHull();
cutHull.AddVertex(origin);
for (int i=0; i<iSteps; i++) {
double angle=fProfileBeginAngle-i*dStepWidth; // we count against the angle orientation!!!!
Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
cutHull.AddVertex(v);
}
Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); // Calculated separately to avoid errors
cutHull.AddVertex(legEnd);
MainLog.Instance.Debug("Starting cutting of the hollow shape from the prim {1}", 0, primName);
SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
outerHull = cuttedHull;
}
// Deal with the hole here
if (hollowFactor > 0) if (hollowFactor > 0)
{ {
float hollowFactorF = (float) hollowFactor/(float) 50000; float hollowFactorF = (float) hollowFactor/(float) 50000;
Vertex IMM = new Vertex(-0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
Vertex IPM = new Vertex(+0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
Vertex IMP = new Vertex(-0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
Vertex IPP = new Vertex(+0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
Vertex IPP; SimpleHull holeHull = new SimpleHull();
Vertex IPM;
Vertex IMP;
Vertex IMM;
IPP = new Vertex("Inner-X+Y+Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, +size.Z/2.0f); holeHull.AddVertex(IMM);
IPM = new Vertex("Inner-X+Y-Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, -size.Z/2.0f); holeHull.AddVertex(IMP);
IMP = new Vertex("Inner-X-Y+Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, +size.Z/2.0f); holeHull.AddVertex(IPP);
IMM = new Vertex("Inner-X-Y-Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, -size.Z/2.0f); holeHull.AddVertex(IPM);
meshMX.Add(IPP); SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
meshMX.Add(IPM);
meshMX.Add(IMP);
meshMX.Add(IMM);
meshMX.Add(new Triangle(IPP, IMP, IPM)); outerHull = hollowedHull;
meshMX.Add(new Triangle(IPM, IMP, IMM));
foreach (Triangle t in meshMX.triangles)
{
PhysicsVector n = t.getNormal();
}
IPP = new Vertex("Inner+X+Y+Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IPM = new Vertex("Inner+X+Y-Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
IMP = new Vertex("Inner+X-Y+Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IMM = new Vertex("Inner+X-Y-Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
meshPX.Add(IPP);
meshPX.Add(IPM);
meshPX.Add(IMP);
meshPX.Add(IMM);
meshPX.Add(new Triangle(IPP, IPM, IMP));
meshPX.Add(new Triangle(IMP, IPM, IMM));
foreach (Triangle t in meshPX.triangles)
{
PhysicsVector n = t.getNormal();
}
} }
Mesh result = new Mesh(); Mesh m = new Mesh();
result.Append(meshMX);
result.Append(meshPX);
return result; Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
} Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
m.Add(Seed1);
m.Add(Seed2);
m.Add(Seed3);
private static Mesh CreateBoxMeshY(PrimitiveBaseShape primShape, PhysicsVector size) m.Add(new Triangle(Seed1, Seed2, Seed3));
// Builds the y (+ and -) surfaces of a box shaped prim m.Add(outerHull.getVertices());
{
UInt16 hollowFactor = primShape.ProfileHollow;
// (M)inus Y InsertVertices(m.vertices, 3, m.triangles);
Mesh MeshMY = new Mesh(); m.DumpRaw(baseDir, primName, "Proto first Mesh");
MeshMY.Add(new Vertex("-X-Y-Z", -size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f));
MeshMY.Add(new Vertex("+X-Y-Z", +size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f));
MeshMY.Add(new Vertex("-X-Y+Z", -size.X/2.0f, -size.Y/2.0f, +size.Z/2.0f));
MeshMY.Add(new Vertex("+X-Y+Z", +size.X/2.0f, -size.Y/2.0f, +size.Z/2.0f));
MeshMY.Add(new Triangle(MeshMY.vertices[0], MeshMY.vertices[1], MeshMY.vertices[2])); m.Remove(Seed1);
MeshMY.Add(new Triangle(MeshMY.vertices[2], MeshMY.vertices[1], MeshMY.vertices[3])); m.Remove(Seed2);
m.Remove(Seed3);
m.DumpRaw(baseDir, primName, "Proto seeds removed");
m.RemoveTrianglesOutside(outerHull);
m.DumpRaw(baseDir, primName, "Proto outsides removed");
// (P)lus Y foreach (Triangle t in m.triangles)
Mesh MeshPY = new Mesh();
MeshPY.Add(new Vertex("-X+Y-Z", -size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f));
MeshPY.Add(new Vertex("+X+Y-Z", +size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f));
MeshPY.Add(new Vertex("-X+Y+Z", -size.X/2.0f, +size.Y/2.0f, +size.Z/2.0f));
MeshPY.Add(new Vertex("+X+Y+Z", +size.X/2.0f, +size.Y/2.0f, +size.Z/2.0f));
MeshPY.Add(new Triangle(MeshPY.vertices[1], MeshPY.vertices[0], MeshPY.vertices[2]));
MeshPY.Add(new Triangle(MeshPY.vertices[1], MeshPY.vertices[2], MeshPY.vertices[3]));
if (hollowFactor > 0)
{
float hollowFactorF = (float) hollowFactor/(float) 50000;
Vertex IPP;
Vertex IPM;
Vertex IMP;
Vertex IMM;
IPP = new Vertex("Inner+X-Y+Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IPM = new Vertex("Inner+X-Y-Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
IMP = new Vertex("Inner-X-Y+Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IMM = new Vertex("Inner-X-Y-Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
MeshMY.Add(IPP);
MeshMY.Add(IPM);
MeshMY.Add(IMP);
MeshMY.Add(IMM);
MeshMY.Add(new Triangle(IPP, IPM, IMP));
MeshMY.Add(new Triangle(IMP, IPM, IMM));
foreach (Triangle t in MeshMY.triangles)
{
PhysicsVector n = t.getNormal();
}
IPP = new Vertex("Inner+X+Y+Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IPM = new Vertex("Inner+X+Y-Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
IMP = new Vertex("Inner-X+Y+Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, +size.Z/2.0f);
IMM = new Vertex("Inner-X+Y-Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, -size.Z/2.0f);
MeshPY.Add(IPP);
MeshPY.Add(IPM);
MeshPY.Add(IMP);
MeshPY.Add(IMM);
MeshPY.Add(new Triangle(IPM, IPP, IMP));
MeshPY.Add(new Triangle(IMP, IMM, IPM));
foreach (Triangle t in MeshPY.triangles)
{
PhysicsVector n = t.getNormal();
}
}
Mesh result = new Mesh();
result.Append(MeshMY);
result.Append(MeshPY);
return result;
}
private static Mesh CreateBoxMeshZ(PrimitiveBaseShape primShape, PhysicsVector size)
// Builds the z (+ and -) surfaces of a box shaped prim
{
UInt16 hollowFactor = primShape.ProfileHollow;
// Base, i.e. outer shape
// (M)inus Z
Mesh MZ = new Mesh();
MZ.Add(new Vertex("-X-Y-Z", -size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f));
MZ.Add(new Vertex("+X-Y-Z", +size.X/2.0f, -size.Y/2.0f, -size.Z/2.0f));
MZ.Add(new Vertex("-X+Y-Z", -size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f));
MZ.Add(new Vertex("+X+Y-Z", +size.X/2.0f, +size.Y/2.0f, -size.Z/2.0f));
MZ.Add(new Triangle(MZ.vertices[1], MZ.vertices[0], MZ.vertices[2]));
MZ.Add(new Triangle(MZ.vertices[1], MZ.vertices[2], MZ.vertices[3]));
// (P)lus Z
Mesh PZ = new Mesh();
PZ.Add(new Vertex("-X-Y+Z", -size.X/2.0f, -size.Y/2.0f, 0.0f));
PZ.Add(new Vertex("+X-Y+Z", +size.X/2.0f, -size.Y/2.0f, 0.0f));
PZ.Add(new Vertex("-X+Y+Z", -size.X/2.0f, +size.Y/2.0f, 0.0f));
PZ.Add(new Vertex("+X+Y+Z", +size.X/2.0f, +size.Y/2.0f, 0.0f));
// Surface 5, +Z
PZ.Add(new Triangle(PZ.vertices[0], PZ.vertices[1], PZ.vertices[2]));
PZ.Add(new Triangle(PZ.vertices[2], PZ.vertices[1], PZ.vertices[3]));
if (hollowFactor > 0)
{
float hollowFactorF = (float) hollowFactor/(float) 50000;
MZ.Add(new Vertex("-X-Y-Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, 0.0f));
MZ.Add(new Vertex("-X+Y-Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, 0.0f));
MZ.Add(new Vertex("-X-Y+Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, 0.0f));
MZ.Add(new Vertex("-X+Y+Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, 0.0f));
List<int> innerBorders = new List<int>();
innerBorders.Add(4);
innerBorders.Add(5);
innerBorders.Add(6);
innerBorders.Add(7);
InsertVertices(MZ.vertices, 4, MZ.triangles, innerBorders);
PZ.Add(new Vertex("-X-Y-Z", -size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, 0.0f));
PZ.Add(new Vertex("-X+Y-Z", +size.X*hollowFactorF/2.0f, -size.Y*hollowFactorF/2.0f, 0.0f));
PZ.Add(new Vertex("-X-Y+Z", -size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, 0.0f));
PZ.Add(new Vertex("-X+Y+Z", +size.X*hollowFactorF/2.0f, +size.Y*hollowFactorF/2.0f, 0.0f));
innerBorders = new List<int>();
innerBorders.Add(4);
innerBorders.Add(5);
innerBorders.Add(6);
innerBorders.Add(7);
InsertVertices(PZ.vertices, 4, PZ.triangles, innerBorders);
}
foreach (Vertex v in PZ.vertices)
{
v.point.Z = size.Z/2.0f;
}
foreach (Vertex v in MZ.vertices)
{
v.point.Z = -size.Z/2.0f;
}
foreach (Triangle t in MZ.triangles)
{
PhysicsVector n = t.getNormal();
if (n.Z > 0.0)
t.invertNormal();
}
foreach (Triangle t in PZ.triangles)
{ {
PhysicsVector n = t.getNormal(); PhysicsVector n = t.getNormal();
if (n.Z < 0.0) if (n.Z < 0.0)
t.invertNormal(); t.invertNormal();
} }
Mesh result = new Mesh(); Extruder extr = new Extruder();
result.Append(MZ);
result.Append(PZ);
extr.size = size;
Mesh result = extr.Extrude(m);
result.DumpRaw(baseDir, primName, "Z extruded");
return result; return result;
} }
private static Mesh CreateBoxMesh(PrimitiveBaseShape primShape, PhysicsVector size)
{
Mesh result = new Mesh();
Mesh MeshX = CreateBoxMeshX(primShape, size);
Mesh MeshY = CreateBoxMeshY(primShape, size);
Mesh MeshZ = CreateBoxMeshZ(primShape, size);
result.Append(MeshX);
result.Append(MeshY);
result.Append(MeshZ);
return result;
}
public static void CalcNormals(Mesh mesh) public static void CalcNormals(Mesh mesh)
{ {
int iTriangles = mesh.triangles.Count; int iTriangles = mesh.triangles.Count;
@ -503,17 +302,18 @@ namespace OpenSim.Region.Physics.OdePlugin
float vx, vy, vz; float vx, vy, vz;
float wx, wy, wz; float wx, wy, wz;
ux = t.v1.point.X; ux = t.v1.X;
uy = t.v1.point.Y; uy = t.v1.Y;
uz = t.v1.point.Z; uz = t.v1.Z;
vx = t.v2.point.X; vx = t.v2.X;
vy = t.v2.point.Y; vy = t.v2.Y;
vz = t.v2.point.Z; vz = t.v2.Z;
wx = t.v3.X;
wy = t.v3.Y;
wz = t.v3.Z;
wx = t.v3.point.X;
wy = t.v3.point.Y;
wz = t.v3.point.Z;
// Vectors for edges // Vectors for edges
float e1x, e1y, e1z; float e1x, e1y, e1z;
@ -550,14 +350,14 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
} }
public static Mesh CreateMesh(PrimitiveBaseShape primShape, PhysicsVector size) public static Mesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
{ {
Mesh mesh = null; Mesh mesh = null;
switch (primShape.ProfileShape) switch (primShape.ProfileShape)
{ {
case ProfileShape.Square: case ProfileShape.Square:
mesh = CreateBoxMesh(primShape, size); mesh=CreateBoxMesh(primName, primShape, size);
CalcNormals(mesh); CalcNormals(mesh);
break; break;
default: default:
@ -568,4 +368,4 @@ namespace OpenSim.Region.Physics.OdePlugin
return mesh; return mesh;
} }
} }
} }

View File

@ -32,6 +32,8 @@ using Axiom.Math;
using Ode.NET; using Ode.NET;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
using OpenSim.Region.Physics.OdePlugin.Meshing;
namespace OpenSim.Region.Physics.OdePlugin namespace OpenSim.Region.Physics.OdePlugin
{ {
@ -274,6 +276,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
{ {
/*
String name1 = null; String name1 = null;
String name2 = null; String name2 = null;
@ -294,45 +297,52 @@ namespace OpenSim.Region.Physics.OdePlugin
d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
// MainLog.Instance.Debug("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z); // MainLog.Instance.Debug("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
*/
return 1; return 1;
} }
public bool needsMeshing(PrimitiveBaseShape pbs)
{
if (pbs.ProfileHollow != 0)
return true;
if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
return true;
return false;
}
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
PhysicsVector size, Quaternion rotation) //To be removed PhysicsVector size, Quaternion rotation) //To be removed
{ {
return this.AddPrimShape(primName, pbs, position, size, rotation, false); return this.AddPrimShape(primName, pbs, position, size, rotation, false);
} }
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
PhysicsVector size, Quaternion rotation, bool isPhysical) PhysicsVector size, Quaternion rotation, bool isPhysical)
{ {
PhysicsActor result; PhysicsActor result;
Mesh mesh = null;
switch (pbs.ProfileShape) switch (pbs.ProfileShape)
{ {
case ProfileShape.Square: case ProfileShape.Square:
/// support simple box & hollow box now; later, more shapes /// support simple box & hollow box now; later, more shapes
if (pbs.ProfileHollow == 0) if (needsMeshing(pbs))
{ {
result = AddPrim(primName, position, size, rotation, null, null); mesh = Meshmerizer.CreateMesh(primName, pbs, size);
} }
else
{
Mesh mesh = Meshmerizer.CreateMesh(pbs, size);
result = AddPrim(primName, position, size, rotation, mesh, pbs);
}
break;
default:
result = AddPrim(primName, position, size, rotation, null, null);
break; break;
} }
result = AddPrim(primName, position, size, rotation, mesh, pbs);
return result; return result;
} }
public override void Simulate(float timeStep) public override void Simulate(float timeStep)
{ {
step_time += timeStep; step_time += timeStep;
@ -551,6 +561,13 @@ namespace OpenSim.Region.Physics.OdePlugin
set { } set { }
} }
public override PrimitiveBaseShape Shape
{
set
{
return;
}
}
public override PhysicsVector Velocity public override PhysicsVector Velocity
{ {
@ -753,6 +770,12 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
} }
public override bool IsPhysical
{
get { return false; }
set { return; }
}
public void setMesh(OdeScene parent_scene, Mesh mesh) public void setMesh(OdeScene parent_scene, Mesh mesh)
{ {
float[] vertexList = mesh.getVertexListAsFloat(); // Note, that vertextList is pinned in memory float[] vertexList = mesh.getVertexListAsFloat(); // Note, that vertextList is pinned in memory
@ -769,12 +792,6 @@ namespace OpenSim.Region.Physics.OdePlugin
prim_geom = d.CreateTriMesh(parent_scene.space, _triMeshData, parent_scene.triCallback, null, null); prim_geom = d.CreateTriMesh(parent_scene.space, _triMeshData, parent_scene.triCallback, null, null);
} }
public override bool IsPhysical
{
get { return false; }
set { return; }
}
public override bool Flying public override bool Flying
{ {
get { return false; //no flying prims for you get { return false; //no flying prims for you
@ -810,18 +827,70 @@ namespace OpenSim.Region.Physics.OdePlugin
_size = value; _size = value;
lock (OdeScene.OdeLock) lock (OdeScene.OdeLock)
{ {
if (_mesh != null) // We deal with a mesh here string oldname = _parent_scene.geom_name_map[prim_geom];
// Cleanup of old prim geometry
d.GeomDestroy(prim_geom);
if (_mesh != null)
{ {
string oldname = _parent_scene.geom_name_map[prim_geom]; // Cleanup meshing here
d.GeomDestroy(prim_geom); }
Mesh mesh = Meshmerizer.CreateMesh(_pbs, _size);
// Construction of new prim
if (this._parent_scene.needsMeshing(_pbs))
{
Mesh mesh = Meshmerizer.CreateMesh(oldname, _pbs, _size);
setMesh(_parent_scene, mesh); setMesh(_parent_scene, mesh);
_parent_scene.geom_name_map[prim_geom] = oldname; } else {
prim_geom = d.CreateBox(_parent_scene.space, _size.X, _size.Y, _size.Z);
} }
else _parent_scene.geom_name_map[prim_geom] = oldname;
d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
d.Quaternion myrot = new d.Quaternion();
myrot.W = _orientation.w;
myrot.X = _orientation.x;
myrot.Y = _orientation.y;
myrot.Z = _orientation.z;
d.GeomSetQuaternion(prim_geom, ref myrot);
}
}
}
public override PrimitiveBaseShape Shape
{
set
{
_pbs = value;
lock (OdeScene.OdeLock)
{
string oldname = _parent_scene.geom_name_map[prim_geom];
// Cleanup of old prim geometry
d.GeomDestroy(prim_geom);
if (_mesh != null)
{ {
d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); // Cleanup meshing here
} }
// Construction of new prim
if (this._parent_scene.needsMeshing(_pbs))
{
Mesh mesh = Meshmerizer.CreateMesh(oldname, _pbs, _size);
setMesh(_parent_scene, mesh);
} else {
prim_geom = d.CreateBox(_parent_scene.space, _size.X, _size.Y, _size.Z);
}
_parent_scene.geom_name_map[prim_geom] = oldname;
d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
d.Quaternion myrot = new d.Quaternion();
myrot.W = _orientation.w;
myrot.X = _orientation.x;
myrot.Y = _orientation.y;
myrot.Z = _orientation.z;
d.GeomSetQuaternion(prim_geom, ref myrot);
} }
} }
} }

View File

@ -291,15 +291,23 @@ namespace OpenSim.Region.Physics.PhysXPlugin
gravityAccel = 0; gravityAccel = 0;
} }
} }
public override PrimitiveBaseShape Shape
public void UpdatePosition()
{ {
Vec3 vec = _character.Position; set
_position.X = vec.X; {
_position.Y = vec.Y; return;
_position.Z = vec.Z; }
} }
}
public void UpdatePosition()
{
Vec3 vec = this._character.Position;
this._position.X = vec.X;
this._position.Y = vec.Y;
this._position.Z = vec.Z;
}
}
public class PhysXPrim : PhysicsActor public class PhysXPrim : PhysicsActor
{ {
@ -358,55 +366,84 @@ namespace OpenSim.Region.Physics.PhysXPlugin
} }
} }
public override PrimitiveBaseShape Shape
{
set
{
return;
}
}
public override PhysicsVector Velocity
{
get
{
return _velocity;
}
set
{
_velocity = value;
}
}
public override bool Kinematic
{
get
{
return this._prim.Kinematic;
}
set
{
this._prim.Kinematic = value;
}
}
public override Quaternion Orientation
{
get
{
Quaternion res = new Quaternion();
PhysXWrapper.Quaternion quat = this._prim.GetOrientation();
res.w = quat.W;
res.x = quat.X;
res.y = quat.Y;
res.z = quat.Z;
return res;
}
set
{
}
}
public override PhysicsVector Acceleration
{
get
{
return _acceleration;
}
}
public void SetAcceleration (PhysicsVector accel)
{
this._acceleration = accel;
}
public override void AddForce(PhysicsVector force)
{
}
public override void SetMomentum(PhysicsVector momentum)
{
}
public override PhysicsVector Size public override PhysicsVector Size
{ {
get { return new PhysicsVector(0, 0, 0); } get { return new PhysicsVector(0, 0, 0); }
set { } set { }
} }
public override PhysicsVector Velocity
{
get { return _velocity; }
set { _velocity = value; }
}
public override bool Kinematic
{
get { return _prim.Kinematic; }
set { _prim.Kinematic = value; }
}
public override Quaternion Orientation
{
get
{
Quaternion res = new Quaternion();
PhysXWrapper.Quaternion quat = _prim.GetOrientation();
res.w = quat.W;
res.x = quat.X;
res.y = quat.Y;
res.z = quat.Z;
return res;
}
set { }
}
public override PhysicsVector Acceleration
{
get { return _acceleration; }
}
public void SetAcceleration(PhysicsVector accel)
{
_acceleration = accel;
}
public override void AddForce(PhysicsVector force)
{
}
public override void SetMomentum(PhysicsVector momentum)
{
}
} }
} }