public override CollisionShape Clone() { CollisionCapsule rv = new CollisionCapsule(bottomcenter, topcenter, capRadius); rv.handle = this.handle; rv.timeStamp = this.timeStamp; return(rv); }
private void FourCollisionsButton_Click(object sender, EventArgs e) { CollisionAPI API = new CollisionAPI(); // Create some obstacles, at 4 corners of a square List<CollisionShape> shapes = new List<CollisionShape>(); CollisionSphere sphere = new CollisionSphere(new Vector3(0f, 0f, 2f), 1f); shapes.Add(sphere); API.AddCollisionShape(sphere, 1); CollisionCapsule capsule = new CollisionCapsule(new Vector3(10f,0f,0f), new Vector3(10f,0f,4f), 1f); shapes.Add(capsule); API.AddCollisionShape(capsule, 2); // Now, an AABB CollisionAABB aabb = new CollisionAABB(new Vector3(9.5f,9.5f,0f), new Vector3(10.5f,10.5f,4f)); shapes.Add(aabb); API.AddCollisionShape(aabb, 3); CollisionOBB obb = new CollisionOBB(new Vector3(0f,10f,2), new Vector3[3] { new Vector3(1f,0f,0f), new Vector3(0f,1f,0f), new Vector3(0f,0f,1f)}, new Vector3(1f, 1f, 1f)); shapes.Add(obb); API.AddCollisionShape(obb, 4); FileStream f = new FileStream("C:\\Junk\\DumpSphereTree.txt", FileMode.Create, FileAccess.Write); StreamWriter writer = new StreamWriter(f); API.DumpSphereTree(writer); API.SphereTreeRoot.VerifySphereTree(); // Now a moving object capsule in the center of the square CollisionCapsule moCap = new CollisionCapsule(new Vector3(5f,5f,0f), new Vector3(5f,5f,4f), 1f); // Remember where the moving object started Vector3 start = moCap.center; // Move the moving object toward each of the obstacles foreach (CollisionShape s in shapes) { moCap.AddDisplacement(start - moCap.center); MoveToObject(writer, API, s, moCap); } writer.Close(); }
public static void CreateRenderedNodes(CollisionShape shape, int id, ref List <RenderedNode> renderedNodes) { // To keep all the rendering stuff internal to this file, we // reach inside of collision objects to create the rendered // shapes if (renderedNodes == null) { renderedNodes = new List <RenderedNode>(); } switch (shape.ShapeType()) { case ShapeEnum.ShapeSphere: renderedNodes.Add(NewRenderedSphere(id, 0, shape.center, shape.radius * MO.DivMeter)); break; case ShapeEnum.ShapeCapsule: CollisionCapsule c = (CollisionCapsule)shape; float r = c.capRadius * MO.DivMeter; renderedNodes.Add(NewRenderedSphere(id, 0, c.bottomcenter, r)); renderedNodes.Add(NewRenderedSphere(id, 1, c.topcenter, r)); Vector3 seg = (c.topcenter - c.bottomcenter); renderedNodes.Add(NewRenderedObject("unit_cylinder.mesh", id, 2, c.center, new Vector3(r, seg.Length * MO.DivMeter, r), new Vector3(0f, 1f, 0f).GetRotationTo(seg))); break; case ShapeEnum.ShapeAABB: renderedNodes.Add(NewRenderedBox(id, 0, ((CollisionAABB)shape).OBB())); break; case ShapeEnum.ShapeOBB: renderedNodes.Add(NewRenderedBox(id, 0, (CollisionOBB)shape)); break; } }
// This method is the callback by which the forests controlled // by the scene manager tell us about SpeedTrees. private void AddTreeObstacles(SpeedTreeWrapper tree) { // If this tree didn't use to be in range but now is V3 vp = tree.TreePosition; Vector3 p = new Vector3(vp.x, vp.y, vp.z); // Find the tile in question int tileX, tileZ; WorldToTileCoords(p, out tileX, out tileZ); bool oir = InRange(tileXCenter, tileZCenter, tileX, tileZ); bool nir = InRange(newTileXCenter, newTileZCenter, tileX, tileZ); // if (MO.DoLog) // MO.Log(String.Format("For tree at {0}, testing !InRange({1},{2},{3},{4}) = {5} && InRange({6},{7},{8},{9}) = {10}", // MO.MeterString(p),tileXCenter, tileZCenter, tileX, tileZ, MO.Bool(!oir), // newTileXCenter, newTileZCenter, tileX, tileZ, MO.Bool(nir))); if (!oir && nir) { int tX = TileToArrayIndex(tileX, newTileXCenter); int tZ = TileToArrayIndex(tileZ, newTileZCenter); uint count = tree.CollisionObjectCount; long handle = ComposeHandle(tileX, tileZ); CollisionShape shape = null; if (MO.DoLog) { MO.Log(string.Format("Adding tree at {0}, tiles[{1},{2}] = {3}, tile coords[{4},{5}], obj. new count {6}", MO.MeterString(p), tX, tZ, tiles[tX,tZ], tileX, tileZ, count)); MO.Log(string.Format("Handle {0}, oldcenter {1}, newcenter {2}", MO.HandleString(handle), MO.MeterString(tileWorldCenter), MO.MeterString(newTileWorldCenter))); } float size = 0f; float variance = 0f; tree.GetTreeSize(ref size, ref variance); float scaleFactor = size / tree.OriginalSize; for (uint i=0; i<count; i++) { TreeCollisionObject tco = tree.CollisionObject(i); Vector3 cp = new Vector3(tco.position.x, tco.position.y, tco.position.z) * scaleFactor + p; Vector3 cd = new Vector3(tco.dimensions.x, tco.dimensions.y, tco.dimensions.z) * scaleFactor; switch ((CollisionObjectType)tco.type) { case CollisionObjectType.ColSphere: shape = new CollisionSphere(cp, cd.x); break; case CollisionObjectType.ColCylinder: // We treat it as a capsule, but we raise the // capsule up by the capRadius, and shorten // the segment by the double the capRadius Vector3 top = cp; top.y += cd.y - cd.x * 2f; cp.y += cd.x; shape = new CollisionCapsule(cp, top, cd.x); break; case CollisionObjectType.ColBox: Vector3 tp = cp; tp.x -= cd.x * .5f; tp.y -= cd.y * .5f; shape = new CollisionAABB(tp, tp + cd); break; } collisionAPI.AddCollisionShape(shape, handle); tiles[tX, tZ]++; objectsAdded++; if (MO.DoLog) { MO.Log(string.Format(" tiles[{0},{1}] = {2}, tile at [{3},{4}] after adding shape {5}", tX, tZ, tiles[tX, tZ], tileX, tileZ, shape.ToString())); } } } }
public static bool TestCapsuleOBB(CollisionCapsule a, CollisionOBB b, CollisionParms parms) { SegOBBParams obbParms = new SegOBBParams(true); Segment s = Segment.SegmentFromStartAndEnd(a.bottomcenter, a.topcenter); if (SqrDistSegOBB(s, b, obbParms) < a.capRadius * a.capRadius) { // If parms.pfLParam == 0, closest is bottomcenter; if == 1, // closest is topcenter. Vector3 d = a.bottomcenter + obbParms.pfLParam * s.direction; // pfBVec is relative to the center of the box, but in box // coords. Vector3 f = b.center; for (int i=0; i<3; i++) f += obbParms.pfBVec[i] * b.axes[i]; Vector3 n = f - d; parms.SetNormPart(n); parms.SetNormObstacle(-n); if (MO.DoLog) { MO.Log(" TestCapsuleOBB: pfLParam {0}, pfBVec {1}", obbParms.pfLParam, obbParms.pfBVec); MO.Log(" TestCapsuleOBB: d {0}, f {1}", f, d); MO.Log(" -n {0}", -n); } return true; } else return false; }
public static bool TestCapsuleCapsule(CollisionCapsule c1, CollisionCapsule c2, CollisionParms parms) { // Compute (squared) distance between the inner structures of the capsules float s, t; Vector3 p1, p2; float d = ClosestPtSegmentSegment(c1.bottomcenter, c1.topcenter, c2.bottomcenter, c2.topcenter, out s, out t, out p1, out p2); float r = c1.capRadius + c2.capRadius; Vector3 n = p2 - p1; parms.SetNormPart(n); parms.SetNormObstacle(-n); return d < r * r; }
public static bool TestCapsuleAABB(CollisionCapsule a, CollisionAABB b, CollisionParms parms) { // Convert the AABB into an OBB, then run the OBBOBB test. // Not the most efficient algorithm but it gets the job // done. CollisionOBB newB = new CollisionOBB(b.center, UnitBasisVectors, (b.max - b.min) * .5f); return TestCapsuleOBB(a, newB, parms); }
private static void TestPhysics( string srcDir, string dstDir, string name ) { float OneMeter = 1000; PhysicsData pd = new PhysicsData(); Vector3 center = new Vector3( 10 * OneMeter, 1 * OneMeter, 1 * OneMeter ); Vector3[] obbAxes = new Vector3[ 3 ]; obbAxes[ 0 ] = new Vector3( 1, 0, -1 ); obbAxes[ 0 ].Normalize(); obbAxes[ 1 ] = Vector3.UnitY; obbAxes[ 2 ] = new Vector3( 1, 0, 1 ); obbAxes[ 2 ].Normalize(); Vector3 obbExtents = new Vector3( 2.5f * OneMeter, 1 * OneMeter, 1 * OneMeter ); CollisionOBB obb = new CollisionOBB( center, obbAxes, obbExtents ); pd.AddCollisionShape( "submesh01", obb ); CollisionAABB aabb = new CollisionAABB( center - obbExtents, center + obbExtents ); pd.AddCollisionShape( "submesh01", aabb ); CollisionSphere sphere = new CollisionSphere( center, 2 * OneMeter ); pd.AddCollisionShape( "submesh01", sphere ); Vector3 capExtents = new Vector3( -1 * OneMeter, 0, 0 ); CollisionCapsule capsule = new CollisionCapsule( center + capExtents, center - capExtents, .5f * OneMeter ); pd.AddCollisionShape( "submesh01", capsule ); PhysicsSerializer ps = new PhysicsSerializer(); ps.ExportPhysics( pd, name ); pd = new PhysicsData(); ps.ImportPhysics( pd, name ); foreach( string objectId in pd.GetCollisionObjects() ) { log.InfoFormat( "Collision shapes for: {0}", objectId ); List<CollisionShape> collisionShapes = pd.GetCollisionShapes( objectId ); foreach( CollisionShape shape in collisionShapes ) log.InfoFormat( "Shape: {0}", shape ); } }
// Keep the code below, commented out, because it is useful // for debugging near plane issues // private static int nearPlaneCollisionCount = 0; // private static int nearPlaneNodeId = 99999; // private static List<RenderedNode>[] nearPlaneRenderedNodes = new List<RenderedNode>[4] { // new List<RenderedNode>(), new List<RenderedNode>(), new List<RenderedNode>(), new List<RenderedNode>() }; // private static CollisionCapsule[] nearPlaneCapsules = new CollisionCapsule[4]; // // protected void CreateNearPlaneCapsules(Camera camera, // Vector3 cameraPosition, // Vector3 playerHeadPosition) // { // // Frame the clip plane with 4 narrow capsules // // Start by finding the center of the near plane // Vector3 toPlayer = (playerHeadPosition - cameraPosition).ToNormalized(); // Vector3 center = cameraPosition + (1.02f * camera.Near) * toPlayer; // float thetaY = MathUtil.DegreesToRadians(camera.FOVy * 0.5f); // float tanThetaY = MathUtil.Tan(thetaY); // float tanThetaX = tanThetaY * camera.AspectRatio; // Vector3 right = tanThetaX * camera.Near * (camera.Right.ToNormalized()); // Vector3 up = tanThetaY * camera.Near * (camera.Up.ToNormalized()); // Vector3 corner1 = center + right - up; // Vector3 corner2 = center + right + up; // Vector3 corner3 = center - right + up; // Vector3 corner4 = center - right - up; // nearPlaneCapsules[0] = new CollisionCapsule(corner1, corner2, Client.OneMeter * .001f); // nearPlaneCapsules[1] = new CollisionCapsule(corner2, corner3, Client.OneMeter * .001f); // nearPlaneCapsules[2] = new CollisionCapsule(corner3, corner4, Client.OneMeter * .001f); // nearPlaneCapsules[3] = new CollisionCapsule(corner4, corner1, Client.OneMeter * .001f); // // RenderedNode.Scene = sceneManager; // for (int i=0; i<4; i++) { // RenderedNode.RemoveNodeRendering(nearPlaneNodeId + i, ref nearPlaneRenderedNodes[i]); // RenderedNode.CreateRenderedNodes(nearPlaneCapsules[i], nearPlaneNodeId + i, ref nearPlaneRenderedNodes[i]); // } // } protected float FindAcceptableCameraPosition(Camera camera, Vector3 cameraPos, Vector3 cameraTarget) { //Logger.Log(0, "FindAcceptableCameraPosition cameraPos {0}, cameraTarget {1}", cameraPos, cameraTarget); // If there is no CollisionAPI object, punt CollisionAPI api = client.WorldManager.CollisionHelper; if (api == null) return (cameraPos - cameraTarget).Length; // Start by finding the point at which a narrow capsule // from the camera to the player intersects. If it // doesn't, then set the point to the cameraPos. // Make a very narrow capsule between the camera and the player's head CollisionCapsule cap = new CollisionCapsule(cameraPos, cameraTarget, Client.OneMeter * .001f); // 1 millimeter Vector3 newCameraPos = cameraPos; Vector3 unitTowardCamera = (newCameraPos - cameraTarget).ToNormalized(); // Test for a collision, setting intersection if there is one. Vector3 intersection = Vector3.Zero; if (api.FindClosestCollision(cap, cameraTarget, cameraPos, ref intersection) != null) { // There is A collision - - set the new camera pos to // be the point of intersection newCameraPos = intersection - unitTowardCamera * camera.Near; //Logger.Log(0, "FindAcceptableCameraPosition: Thin cap collides at {0}", newCameraPos); } // Move a near-plane OBB forward from the point of // intersection until we find a place where the near plane // doesn't intersect any collision volumes Vector3 center = newCameraPos - camera.Near * unitTowardCamera; float thetaY = MathUtil.DegreesToRadians(camera.FOVy * 0.5f); float tanThetaY = MathUtil.Tan(thetaY); float tanThetaX = tanThetaY * camera.AspectRatio; // Compute the OBB axes and extents Vector3[] axes = new Vector3[3]; Vector3 extents = Vector3.Zero; // The axis perpendicular to the near plane float obbDepth = 100f; // 100 mm thick axes[0] = -unitTowardCamera; axes[1] = -axes[0].Cross(Vector3.UnitY).ToNormalized(); axes[2] = -axes[1].Cross(axes[0]).ToNormalized(); extents[0] = obbDepth; extents[1] = camera.Near * tanThetaX; extents[2] = camera.Near * tanThetaY; float len = (newCameraPos - cameraTarget).Length; float startingLen = len; CollisionOBB obb = new CollisionOBB(center, axes, extents); CollisionParms parms = new CollisionParms(); while (len >= minThirdPersonDistance) { obb.center = cameraTarget + unitTowardCamera * len; bool collides = api.ShapeCollides(obb, parms); //Logger.Log(0, "FindAcceptableCameraPosition len {0}, obb center {1}, collides {2}", len, obb.center, collides); if (!collides) break; //client.Write(string.Format("OBB collides; len {0}", len)); len -= obbDepth; } // Len is less than the camera min distance, so just // return it //Logger.Log(0, "FindAcceptableCameraPosition: starting len {0} final len {1}", startingLen, len); return len; }
// This method is the callback by which the forests controlled // by the scene manager tell us about SpeedTrees. private void AddTreeObstacles(SpeedTreeWrapper tree) { // If this tree didn't use to be in range but now is V3 vp = tree.TreePosition; Vector3 p = new Vector3(vp.x, vp.y, vp.z); // Find the tile in question int tileX, tileZ; WorldToTileCoords(p, out tileX, out tileZ); bool oir = InRange(tileXCenter, tileZCenter, tileX, tileZ); bool nir = InRange(newTileXCenter, newTileZCenter, tileX, tileZ); // if (MO.DoLog) // MO.Log(String.Format("For tree at {0}, testing !InRange({1},{2},{3},{4}) = {5} && InRange({6},{7},{8},{9}) = {10}", // MO.MeterString(p),tileXCenter, tileZCenter, tileX, tileZ, MO.Bool(!oir), // newTileXCenter, newTileZCenter, tileX, tileZ, MO.Bool(nir))); if (!oir && nir) { int tX = TileToArrayIndex(tileX, newTileXCenter); int tZ = TileToArrayIndex(tileZ, newTileZCenter); uint count = tree.CollisionObjectCount; long handle = ComposeHandle(tileX, tileZ); CollisionShape shape = null; if (MO.DoLog) { MO.Log(string.Format("Adding tree at {0}, tiles[{1},{2}] = {3}, tile coords[{4},{5}], obj. new count {6}", MO.MeterString(p), tX, tZ, tiles[tX, tZ], tileX, tileZ, count)); MO.Log(string.Format("Handle {0}, oldcenter {1}, newcenter {2}", MO.HandleString(handle), MO.MeterString(tileWorldCenter), MO.MeterString(newTileWorldCenter))); } float size = 0f; float variance = 0f; tree.GetTreeSize(ref size, ref variance); float scaleFactor = size / tree.OriginalSize; for (uint i = 0; i < count; i++) { TreeCollisionObject tco = tree.CollisionObject(i); Vector3 cp = new Vector3(tco.position.x, tco.position.y, tco.position.z) * scaleFactor + p; Vector3 cd = new Vector3(tco.dimensions.x, tco.dimensions.y, tco.dimensions.z) * scaleFactor; switch ((CollisionObjectType)tco.type) { case CollisionObjectType.ColSphere: shape = new CollisionSphere(cp, cd.x); break; case CollisionObjectType.ColCylinder: // We treat it as a capsule, but we raise the // capsule up by the capRadius, and shorten // the segment by the double the capRadius Vector3 top = cp; top.y += cd.y - cd.x * 2f; cp.y += cd.x; shape = new CollisionCapsule(cp, top, cd.x); break; case CollisionObjectType.ColBox: Vector3 tp = cp; tp.x -= cd.x * .5f; tp.y -= cd.y * .5f; shape = new CollisionAABB(tp, tp + cd); break; } collisionAPI.AddCollisionShape(shape, handle); tiles[tX, tZ]++; objectsAdded++; if (MO.DoLog) { MO.Log(string.Format(" tiles[{0},{1}] = {2}, tile at [{3},{4}] after adding shape {5}", tX, tZ, tiles[tX, tZ], tileX, tileZ, shape.ToString())); } } } }
public override CollisionShape Clone() { CollisionCapsule rv = new CollisionCapsule(bottomcenter, topcenter, capRadius); rv.handle = this.handle; rv.timeStamp = this.timeStamp; return rv; }
public void ReadCapsule(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData) { Quaternion rot = MathHelpers.GetRotation(transform); Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform; Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale; if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon) log.Error("Scale is not currently supported for capsule shapes"); float height = 0; float[] radius = new float[2]; Vector3 halfExtents = Vector3.Zero; foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "height": height = float.Parse(childNode.InnerText); break; case "radius": { string[] values = childNode.InnerText.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); Debug.Assert(values.Length == 2); for (int i = 0; i < 2; ++i) radius[i] = float.Parse(values[i]); } break; default: DebugMessage(childNode); break; } } // We only support capsules where the two radii match if (radius[0] != radius[1]) log.Error("Different radii for capsules are not currently supported"); Vector3 center = unitConversion * transform.Translation; Vector3 halfExtent = unitConversion * (.5f * height * (rot * Vector3.UnitY)); radius[0] *= unitConversion; radius[1] *= unitConversion; CollisionShape collisionShape; collisionShape = new CollisionCapsule(center - halfExtent, center + halfExtent, radius[0]); physicsData.AddCollisionShape(objectId, collisionShape); }