diff --git a/Programs/Simian/Extensions/PhysicsSimple.cs b/Programs/Simian/Extensions/PhysicsSimple.cs index af525c7f..20895885 100644 --- a/Programs/Simian/Extensions/PhysicsSimple.cs +++ b/Programs/Simian/Extensions/PhysicsSimple.cs @@ -16,6 +16,10 @@ namespace Simian.Extensions public void Start(Simian server) { this.server = server; + + server.Scene.OnObjectAdd += Scene_OnObjectAdd; + server.Scene.OnObjectModify += Scene_OnObjectModify; + server.Scene.OnObjectTransform += Scene_OnObjectTransform; } public void Stop() @@ -24,8 +28,6 @@ namespace Simian.Extensions public Vector3 ObjectCollisionTest(Vector3 rayStart, Vector3 rayEnd, SimulationObject obj) { - const float OO_THREE = 1f / 3f; - Vector3 closestPoint = rayEnd; if (rayStart == rayEnd) @@ -37,18 +39,7 @@ namespace Simian.Extensions Vector3 direction = Vector3.Normalize(rayEnd - rayStart); // Get the mesh that has been transformed into world-space - SimpleMesh mesh = null; - if (obj.Prim.ParentID != 0) - { - SimulationObject parent; - if (server.Scene.TryGetObject(obj.Prim.ParentID, out parent)) - mesh = obj.GetWorldMesh(DetailLevel.Low, parent); - } - else - { - mesh = obj.GetWorldMesh(DetailLevel.Low, null); - } - + SimpleMesh mesh = obj.GetWorldMesh(DetailLevel.Low, false); if (mesh != null) { // Iterate through all of the triangles in the mesh, doing a ray-triangle intersection @@ -60,16 +51,11 @@ namespace Simian.Extensions Vector3 point1 = mesh.Vertices[mesh.Indices[i + 1]].Position; Vector3 point2 = mesh.Vertices[mesh.Indices[i + 2]].Position; - if (RayTriangleIntersection(rayStart, direction, point0, point1, point2)) + Vector3 collisionPoint; + if (RayTriangleIntersection(rayStart, direction, point0, point1, point2, out collisionPoint)) { - // HACK: Find the barycenter of this triangle. Would be better to have - // RayTriangleIntersection return the exact collision point - Vector3 center = (point0 + point1 + point2) * OO_THREE; - - Logger.DebugLog("Collision hit with triangle at " + center); - - if ((center - rayStart).Length() < closestDistance) - closestPoint = center; + if ((collisionPoint - rayStart).Length() < closestDistance) + closestPoint = collisionPoint; } } } @@ -100,8 +86,9 @@ namespace Simian.Extensions /// Position of the first triangle corner /// Position of the second triangle corner /// Position of the third triangle corner + /// The collision point in the triangle /// True if the ray passes through the triangle, otherwise false - bool RayTriangleIntersection(Vector3 origin, Vector3 direction, Vector3 vert0, Vector3 vert1, Vector3 vert2) + static bool RayTriangleIntersection(Vector3 origin, Vector3 direction, Vector3 vert0, Vector3 vert1, Vector3 vert2, out Vector3 collisionPoint) { const float EPSILON = 0.00001f; @@ -119,7 +106,10 @@ namespace Simian.Extensions determinant = Vector3.Dot(edge1, pvec); if (determinant > -EPSILON && determinant < EPSILON) + { + collisionPoint = Vector3.Zero; return false; + } invDeterminant = 1f / determinant; @@ -129,7 +119,10 @@ namespace Simian.Extensions // Calculate U parameter and test bounds float u = Vector3.Dot(tvec, pvec) * invDeterminant; if (u < 0.0f || u > 1.0f) + { + collisionPoint = Vector3.Zero; return false; + } // Prepare to test V parameter Vector3 qvec = Vector3.Cross(tvec, edge1); @@ -137,10 +130,18 @@ namespace Simian.Extensions // Calculate V parameter and test bounds float v = Vector3.Dot(direction, qvec) * invDeterminant; if (v < 0.0f || u + v > 1.0f) + { + collisionPoint = Vector3.Zero; return false; + } //t = Vector3.Dot(edge2, qvec) * invDeterminant; + collisionPoint = new Vector3( + vert0.X + u * (vert1.X - vert0.X) + v * (vert2.X - vert0.X), + vert0.Y + u * (vert1.Y - vert0.Y) + v * (vert2.Y - vert0.Y), + vert0.Z + u * (vert1.Z - vert0.Z) + v * (vert2.Z - vert0.Z)); + return true; } @@ -403,5 +404,30 @@ namespace Simian.Extensions return returnMass; } + + #region Callbacks + + void Scene_OnObjectAdd(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags) + { + // TODO: This doesn't update children prims when their parents move. "World meshes" are a bad approach in general, + // the transforms should probably be applied to the mesh in the collision test + obj.GetWorldMesh(DetailLevel.Low, true); + } + + void Scene_OnObjectModify(object sender, SimulationObject obj, Primitive.ConstructionData data) + { + obj.GetWorldMesh(DetailLevel.Low, true); + } + + void Scene_OnObjectTransform(object sender, SimulationObject obj, Vector3 position, Quaternion rotation, Vector3 velocity, + Vector3 acceleration, Vector3 angularVelocity) + { + // TODO: This doesn't update children prims when their parents move. "World meshes" are a bad approach in general, + // the transforms should probably be applied to the mesh in the collision test + if (position != obj.Prim.Position || rotation != obj.Prim.Rotation) + obj.GetWorldMesh(DetailLevel.Low, true); + } + + #endregion Callbacks } } diff --git a/Programs/Simian/SimulationObject.cs b/Programs/Simian/SimulationObject.cs index 849a44e0..14accd0b 100644 --- a/Programs/Simian/SimulationObject.cs +++ b/Programs/Simian/SimulationObject.cs @@ -189,13 +189,14 @@ namespace Simian } } - public SimpleMesh GetWorldMesh(DetailLevel lod, SimulationObject parent) + public SimpleMesh GetWorldMesh(DetailLevel lod, bool forceRebuild) { int i = (int)lod; - if (WorldTransformedMeshes == null) WorldTransformedMeshes = new SimpleMesh[4]; + if (WorldTransformedMeshes == null) + WorldTransformedMeshes = new SimpleMesh[4]; - if (WorldTransformedMeshes[i] != null) + if (!forceRebuild && WorldTransformedMeshes[i] != null) { return WorldTransformedMeshes[i]; } @@ -207,7 +208,8 @@ namespace Simian // Construct a matrix to transform to world space Matrix4 transform = Matrix4.Identity; - if (parent != null) + SimulationObject parent = GetLinksetParent(); + if (parent != this) { // Apply parent rotation and translation first transform *= Matrix4.CreateFromQuaternion(parent.Prim.Rotation);