public CameraManager(int width, int height) { //tmp position Position = Vector3.Zero; newPosition = Vector3.Zero; Acceleration = 0.5f; //tmp lookAtPoint LookAtPoint = Vector3.Zero; //set aspect ratio aspectRatio = (float)width / (float)height; //setup projection ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(40.0f),//40 this.aspectRatio, 1.0f, 10000.0f); SetViewMatrix(); rotationLeftRight = 0.0f; rotationUpDown = 0.0f; box = new CollisionBox(new Vector3(-15, -100, -15), new Vector3(15, 30, 15)); }
public virtual bool BoxIntersect(CollisionBox ray_box, Vector3 ray_origin, Vector3 ray_direction, Vector3[] vert_pos, out float intersect_distance, out Vector3 intersect_position, out Vector3 intersect_normal) { intersect_distance = 0; intersect_position = Vector3.Zero; intersect_normal = Vector3.Zero; return false; }
public CollisionFace(int offset, short[] vert_indx, int vert_offset, Vector3[] vert_pos) { vertices = new int[3]; box = new CollisionBox(float.MaxValue, -float.MaxValue); for (int i = 0; i < 3; i++) { vertices[i] = (int)vert_indx[i + offset] + vert_offset; box.AddPoint(vert_pos[vertices[i]]); } }
public CollisionCameraObserver( Vector3 position, Vector3 lookPosition, float angle, float aspect, float radius) : base(position, lookPosition, angle, aspect) { box = new CollisionBox(-radius, radius); }
public bool BoxIntersect( CollisionBox box, Vector3 rayStart, Vector3 rayEnd, Vector3[] vertices, out float intersectDistance, out Vector3 intersectPosition, out Vector3 intersectNormal) { intersectDistance = 0.0f; intersectPosition = rayStart; intersectNormal = Vector3.Zero; Vector3 rayDirection = rayEnd - rayStart; float rayLength = rayDirection.Length(); if (rayLength == 0) return false; CollisionBox rayBox = new CollisionBox(box.min + rayStart, box.max + rayStart); rayBox.AddPoint(rayBox.min + rayDirection); rayBox.AddPoint(rayBox.max + rayDirection); Vector3 inflate = new Vector3(0.001f, 0.001f, 0.001f); rayBox.min -= inflate; rayBox.max += inflate; List<CollisionTreeElem> elems = new List<CollisionTreeElem>(); root.GetElements(rayBox, elems, ++recurseId); rayDirection *= 1.0f / rayLength; intersectDistance = rayLength; bool intersected = false; foreach (CollisionTreeElem e in elems) { float distance; Vector3 position; Vector3 normal; if (true == e.BoxIntersect(box, rayStart, rayDirection, vertices, out distance, out position, out normal)) { if (distance < intersectDistance) { intersectDistance = distance; intersectPosition = position; intersectNormal = normal; intersected = true; } } } return intersected; }
public CollisionTreeNode(CollisionBox b,uint subdiv_level) { box = b; if (subdiv_level>0) { subdiv_level--; childs = new CollisionTreeNode[8]; CollisionBox[] childs_box = box.GetChilds(); for( uint i=0;i<8;i++ ) childs[i] = new CollisionTreeNode(childs_box[i], subdiv_level); } }
/// <summary> /// Virtual function to intersect a box with the element /// </summary> public virtual bool BoxIntersect( CollisionBox rayBox, Vector3 rayOrigin, Vector3 rayDirection, Vector3[] vertices, out float intersectDistance, out Vector3 intersectPosition, out Vector3 intersectNormal) { intersectDistance = 0; intersectPosition = Vector3.Zero; intersectNormal = Vector3.Zero; return false; }
public CollisionFace( int offset, short[] indexBuffer, int vertexOffset, Vector3[] vertexBuffer) { indices = new int[3]; box = new CollisionBox(float.MaxValue, -float.MaxValue); for (int i = 0; i < 3; i++) { indices[i] = (int)indexBuffer[i + offset] + vertexOffset; box.AddPoint(vertexBuffer[indices[i]]); } }
/// <summary> /// Recursive function to get all elements intersecting a given bounding box /// </summary> public void GetElements( CollisionBox b, List <CollisionTreeElem> e, uint recurseId) { // if selection box does not intersect node box, return if (b.BoxIntersect(box) == false) { return; } // if any elements in this node add them to selection list if (elems != null) { foreach (CollisionTreeElem elem in elems) { // elements can be repeated in many nodes // only add element to selection list if not already // added by another node in this same recursion if (elem.lastRecurseId < recurseId) { // if selection box intersect the element box if (elem.box.BoxIntersect(b)) { // add element to selection list e.Add(elem); } // set this recuse id to prevent duplicate results elem.lastRecurseId = recurseId; } } } // if not a leaf node, recurso to all children if (children != null) { foreach (CollisionTreeNode n in children) { n.GetElements(b, e, recurseId); } } }
// split in middle point creating 8 children public CollisionBox[] GetChildren() { Vector3 center = 0.5f * (min + max); CollisionBox[] children = new CollisionBox[8]; children[0] = new CollisionBox(min, center); children[1] = new CollisionBox(new Vector3(center.X, min.Y, min.Z), new Vector3(max.X, center.Y, center.Z)); children[2] = new CollisionBox(new Vector3(min.X, center.Y, min.Z), new Vector3(center.X, max.Y, center.Z)); children[3] = new CollisionBox(new Vector3(center.X, center.Y, min.Z), new Vector3(max.X, max.Y, center.Z)); children[4] = new CollisionBox(new Vector3(min.X, min.Y, center.Z), new Vector3(center.X, center.Y, max.Z)); children[5] = new CollisionBox(new Vector3(center.X, min.Y, center.Z), new Vector3(max.X, center.Y, max.Z)); children[6] = new CollisionBox(new Vector3(min.X, center.Y, center.Z), new Vector3(center.X, max.Y, max.Z)); children[7] = new CollisionBox(center, max); return(children); }
/// <summary> /// Create a new tree node /// </summary> public CollisionTreeNode(CollisionBox collisionBox, uint subdivLevel) { if (collisionBox == null) { throw new ArgumentNullException("collisionBox"); } // save node box box = collisionBox; // if subdivision needed if (subdivLevel > 0) { // decrease subdivision level subdivLevel--; // create the 8 children children = new CollisionTreeNode[8]; CollisionBox[] childrenBox = box.GetChildren(); for (uint i = 0; i < 8; i++) children[i] = new CollisionTreeNode(childrenBox[i], subdivLevel); } }
public Vector3 velocity; // current velocity vector used only by gravity #endregion Fields #region Constructors public CollisionCameraPerson(Vector3 position, Vector3 look_position, float angle, float aspect, float width, float height, float step_height, float head_height, float up_down_rot, float gravity, float jump_height) : base(position, look_position, angle, aspect) { width *= 0.5f; height *= 0.5f; this.step_height = step_height; this.head_height = head_height - height; this.up_down_rot = up_down_rot; this.gravity = gravity; this.jump_height = jump_height; transform = world; on_ground = false; velocity = Vector3.Zero; box = new CollisionBox( new Vector3(-width, -height + step_height, -width), new Vector3(width, height, width)); }
public void GetElements(CollisionBox b, List<CollisionTreeElem> e, uint recurse_id) { if (b.BoxIntersect(box) == false) return; if (elems != null) { foreach (CollisionTreeElem elem in elems) { if (elem.last_recurse_id < recurse_id) { if (elem.box.BoxIntersect(b)) e.Add(elem); elem.last_recurse_id = recurse_id; } } } if (childs != null) { foreach (CollisionTreeNode n in childs) n.GetElements(b, e, recurse_id); } }
public bool BoxMove( CollisionBox box, Vector3 pointStart, Vector3 pointEnd, Vector3[] vertices, float frictionFactor, float bumpFactor, uint recurseLevel, out Vector3 pointResult) { pointResult = pointStart; Vector3 delta = pointEnd - pointStart; float deltaLength = delta.Length(); if (deltaLength < 0.00001f) return false; float totalDistance = deltaLength; delta *= 1.0f / deltaLength; float bias = 0.01f; pointEnd += delta * bias; bool collisionHit = false; while (recurseLevel > 0) { float dist; Vector3 pos, norm; if (false == BoxIntersect(box, pointStart, pointEnd, vertices, out dist, out pos, out norm)) { pointStart = pointEnd - delta * bias; break; } collisionHit = true; dist -= bias / Math.Abs(Vector3.Dot(delta, norm)); if (dist > 0) { pointStart += delta * dist; totalDistance -= dist; } Vector3 reflectDirection = Vector3.Normalize(Vector3.Reflect(delta, norm)); Vector3 n = norm * Vector3.Dot(reflectDirection, norm); Vector3 t = reflectDirection - n; reflectDirection = frictionFactor * t + bumpFactor * n; pointEnd = pointStart + reflectDirection * totalDistance; delta = pointEnd - pointStart; deltaLength = delta.Length(); if (deltaLength < 0.00001f) break; delta *= 1.0f / deltaLength; pointEnd += delta * bias; recurseLevel--; } pointResult = pointStart; return collisionHit; }
/// <summary> /// Check collisions for dynamic objects /// </summary> public virtual void CheckCollisions(GameTime gameTime) { GameEntityList deadObjects = new GameEntityList(); CollisionBox cameraBox = new CollisionBox(this.camera.box); cameraBox.min += this.camera.world.Translation; cameraBox.max += this.camera.world.Translation; cameraBox.min.Y -= this.camera.head_height + this.camera.step_height; cameraBox.max.Y += this.camera.head_height + this.camera.step_height; ///Dynamic objects with player foreach (GameEntity ge in this.sceneObjects.Values) { if (cameraBox.BoxIntersect(ge.Box)) { if (ge is ICatchable) { ((ICatchable)ge).Attach(this.player); deadObjects.Add(ge.ModelMesh.Name, ge); ge.ModelMesh.Tag = null; } else if (ge is IAttachable) { if (ge is GameObjectEntity) this.player.Add((GameObjectEntity)ge); } } ge.Update(gameTime, this.collisionMesh); } foreach (GameEntity ge in deadObjects.Values) { this.sceneObjects.Remove(ge.ModelMesh.Name); } deadObjects.Clear(); ///Enemies with player foreach (Enemy e in this.enemies.Values) { if (e.ActualAnimationState != GameEntityAnimationState.Die) { if (cameraBox.BoxIntersect(e.Box)) { this.SendMessage(player, e, GameEntityMessageType.Hit, gameTime); } } e.Update(gameTime, this.collisionMesh); } ///Bullets with enemies, static objects... foreach (Bullet b in this.bullets) { Vector3 position = b.Position; Vector3 speed = b.Speed; Vector3 new_pos = position + speed * (float)gameTime.ElapsedGameTime.TotalSeconds; this.collisionMesh.PointMove(position, new_pos, 1.0f, 1.0f, 3, out position); //these are discartable, just to pass to the PointIntersect method as out parameters float intersect_distance; Vector3 intersect_position = new Vector3(); Vector3 intersection_normal = new Vector3(); //collision of bullets with static scenario (walls, etc.) if (this.collisionMesh.PointIntersect(position, new_pos, out intersect_distance, out intersect_position, out intersection_normal)) { b.Dead = true; } //collision of bullets with enemies foreach (Enemy e in this.enemies.Values) { if (e.Box.PointInside(b.Position)) { b.Dead = true; SendMessage(b, e, GameEntityMessageType.Damage, gameTime); if (e.Health >= 10) SendMessage(b, e, GameEntityMessageType.Hit, gameTime); } } b.Position = position; b.Speed = speed; } }
public void GetElements(CollisionBox collisionBox, List <CollisionTreeElem> elements) { root.GetElements(collisionBox, elements, ++recurseId); }
public bool BoxMove( CollisionBox box, Vector3 pointStart, Vector3 pointEnd, float frictionFactor, float bumpFactor, uint recurseLevel, out Vector3 pointResult) { return tree.BoxMove(box, pointStart, pointEnd, vertices, frictionFactor, bumpFactor, recurseLevel, out pointResult); }
public CollisionMesh(Model model, uint subdivLevel) { int verticesCapacity = 0; int facesCapacity = 0; foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { verticesCapacity += part.VertexBuffer.VertexCount; facesCapacity += part.PrimitiveCount; } } vertices = new Vector3[verticesCapacity]; faces = new CollisionFace[facesCapacity]; int verticesLength = 0; int facesLength = 0; Matrix[] modelTransforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(modelTransforms); foreach (ModelMesh mesh in model.Meshes) { Matrix meshTransform = modelTransforms[mesh.ParentBone.Index]; foreach (ModelMeshPart part in mesh.MeshParts) { int vertexCount = part.VertexBuffer.VertexCount; CustomVertex[] partVertices = new CustomVertex[vertexCount]; part.VertexBuffer.GetData(partVertices); for (int i = 0; i < vertexCount; i++) { vertices[verticesLength + i] = Vector3.Transform(partVertices[i].Position, meshTransform); } int indexCount = part.IndexBuffer.IndexCount; short[] partIndices = new short[indexCount]; part.IndexBuffer.GetData(partIndices); for (int i = 0; i < part.PrimitiveCount; i++) { faces[facesLength + i] = new CollisionFace( part.StartIndex + i * 3, partIndices, verticesLength + part.VertexOffset, vertices); } verticesLength += vertexCount; facesLength += part.PrimitiveCount; } } CollisionBox box = new CollisionBox(float.MaxValue, -float.MaxValue); for (int i = 0; i < verticesCapacity; i++) { box.AddPoint(vertices[i]); } if (subdivLevel > 6) { subdivLevel = 6; // max 8^6 nodes } tree = new CollisionTree(box, subdivLevel); for (int i = 0; i < facesCapacity; i++) { tree.AddElement(faces[i]); } }
// split in middle point creating 8 children public CollisionBox[] GetChildren() { Vector3 center = 0.5f * (min + max); CollisionBox[] children = new CollisionBox[8]; children[0] = new CollisionBox(min, center); children[1] = new CollisionBox(new Vector3(center.X, min.Y, min.Z), new Vector3(max.X, center.Y, center.Z)); children[2] = new CollisionBox(new Vector3(min.X, center.Y, min.Z), new Vector3(center.X, max.Y, center.Z)); children[3] = new CollisionBox(new Vector3(center.X, center.Y, min.Z), new Vector3(max.X, max.Y, center.Z)); children[4] = new CollisionBox(new Vector3(min.X, min.Y, center.Z), new Vector3(center.X, center.Y, max.Z)); children[5] = new CollisionBox(new Vector3(center.X, min.Y, center.Z), new Vector3(max.X, center.Y, max.Z)); children[6] = new CollisionBox(new Vector3(min.X, center.Y, center.Z), new Vector3(center.X, max.Y, max.Z)); children[7] = new CollisionBox(center, max); return children; }
// constructor from another collision box public CollisionBox(CollisionBox bb) { min = bb.min; max = bb.max; }
public bool BoxIntersect( CollisionBox box, Vector3 rayStart, Vector3 rayEnd, out float intersectDistance, out Vector3 intersectPosition, out Vector3 intersectNormal) { return tree.BoxIntersect(box, rayStart, rayEnd, vertices, out intersectDistance, out intersectPosition, out intersectNormal); }
/// <summary> /// Recursive function to get all elements intersecting a given bounding box /// </summary> public void GetElements( CollisionBox b, List<CollisionTreeElem> e, uint recurseId) { // if selection box does not intersect node box, return if (b.BoxIntersect(box) == false) return; // if any elements in this node add them to selection list if (elems != null) { foreach (CollisionTreeElem elem in elems) { // elements can be repeated in many nodes // only add element to selection list if not already // added by another node in this same recursion if (elem.lastRecurseId < recurseId) { // if selection box intersect the element box if (elem.box.BoxIntersect(b)) // add element to selection list e.Add(elem); // set this recuse id to prevent duplicate results elem.lastRecurseId = recurseId; } } } // if not a leaf node, recurso to all children if (children != null) { foreach (CollisionTreeNode n in children) n.GetElements(b, e, recurseId); } }
public bool PointIntersect(Vector3 ray_start, Vector3 ray_end, Vector3[] vert_pos, out float intersect_distance, out Vector3 intersect_position, out Vector3 intersect_normal) { intersect_distance = 0.0f; intersect_position = ray_start; intersect_normal = Vector3.Zero; Vector3 ray_direction = ray_end - ray_start; float ray_length = ray_direction.Length(); if (ray_length == 0) return false; CollisionBox ray_box = new CollisionBox(float.MaxValue, -float.MaxValue); ray_box.AddPoint(ray_start); ray_box.AddPoint(ray_end); Vector3 inflate = new Vector3(0.001f, 0.001f, 0.001f); ray_box.min -= inflate; ray_box.max += inflate; List<CollisionTreeElem> elems = new List<CollisionTreeElem>(); root.GetElements(ray_box, elems, ++recurse_id); ray_direction *= 1.0f / ray_length; intersect_distance = ray_length; bool intersected = false; foreach (CollisionTreeElem e in elems) { float distance; Vector3 position; Vector3 normal; if (true == e.PointIntersect(ray_start, ray_direction, vert_pos, out distance, out position, out normal)) { if (distance < intersect_distance) { intersect_distance = distance; intersect_position = position; intersect_normal = normal; intersected = true; } } } return intersected; }
public void GetElements(CollisionBox b, List<CollisionTreeElem> e) { root.GetElements(b, e, ++recurse_id); }
public bool BoxMove( CollisionBox box, Vector3 point_start, Vector3 point_end, Vector3[] vert_pos, float friction_factor, float bump_factor, uint recurse_level, out Vector3 point_result) { point_result = point_start; Vector3 delta = point_end - point_start; float delta_len = delta.Length(); if (delta_len < 0.00001f) return false; float total_dist = delta_len; delta *= 1.0f / delta_len; float bias = 0.01f; point_end += delta * bias; bool collision_hit = false; while (recurse_level > 0) { float dist; Vector3 pos, norm; if (false == BoxIntersect(box, point_start, point_end, vert_pos, out dist, out pos, out norm)) { point_start = point_end - delta * bias; break; } collision_hit = true; dist -= bias / Math.Abs(Vector3.Dot(delta, norm)); if (dist > 0) { point_start += delta * dist; total_dist -= dist; } Vector3 reflect_dir = Vector3.Normalize(Vector3.Reflect(delta, norm)); Vector3 n = norm * Vector3.Dot(reflect_dir, norm); Vector3 t = reflect_dir - n; reflect_dir = friction_factor * t + bump_factor * n; point_end = point_start + reflect_dir * total_dist; delta = point_end - point_start; delta_len = delta.Length(); if (delta_len < 0.00001f) break; delta *= 1.0f / delta_len; point_end += delta * bias; recurse_level--; } point_result = point_start; return collision_hit; }
public void GetElements(CollisionBox collisionBox, List<CollisionTreeElem> elements) { root.GetElements(collisionBox, elements, ++recurseId); }
public CollisionMesh(Model model, uint subdiv_level) { int total_num_faces = 0; int total_num_verts = 0; foreach (ModelMesh mesh in model.Meshes) { if (IsDynamicEntity(mesh)) continue; int nv, ni; nv = mesh.VertexBuffer.SizeInBytes / mesh.MeshParts[0].VertexStride; if(mesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ni = mesh.IndexBuffer.SizeInBytes / sizeof(short); else ni = mesh.IndexBuffer.SizeInBytes / sizeof(int); total_num_verts += nv; total_num_faces += ni / 3; } vertices = new Vector3[total_num_verts]; faces = new CollisionFace[total_num_faces]; int vcount = 0; int fcount = 0; foreach (ModelMesh mesh in model.Meshes) { if (IsDynamicEntity(mesh)) continue; int nv = mesh.VertexBuffer.SizeInBytes / mesh.MeshParts[0].VertexStride; if (mesh.MeshParts[0].VertexStride == 16) { VertexPositionColor[] mesh_vertices = new VertexPositionColor[nv]; mesh.VertexBuffer.GetData<VertexPositionColor>(mesh_vertices); for (int i = 0; i < nv; i++) vertices[i + vcount] = mesh_vertices[i].Position; } if (mesh.MeshParts[0].VertexStride == 20) { VertexPositionTexture[] mesh_vertices = new VertexPositionTexture[nv]; mesh.VertexBuffer.GetData<VertexPositionTexture>(mesh_vertices); for (int i = 0; i < nv; i++) vertices[i + vcount] = mesh_vertices[i].Position; } else if (mesh.MeshParts[0].VertexStride == 24) { VertexPositionColorTexture[] mesh_vertices = new VertexPositionColorTexture[nv]; mesh.VertexBuffer.GetData<VertexPositionColorTexture>(mesh_vertices); for (int i = 0; i < nv; i++) vertices[i + vcount] = mesh_vertices[i].Position; } else if (mesh.MeshParts[0].VertexStride == 32) { VertexPositionNormalTexture[] mesh_vertices = new VertexPositionNormalTexture[nv]; mesh.VertexBuffer.GetData<VertexPositionNormalTexture>(mesh_vertices); for (int i = 0; i < nv; i++) vertices[i + vcount] = mesh_vertices[i].Position; } int nf = 0; if (mesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) { short[] mesh_indices = new short[mesh.IndexBuffer.SizeInBytes / sizeof(short)]; mesh.IndexBuffer.GetData<short>(mesh_indices); int count = 0; foreach (ModelMeshPart mesh_part in mesh.MeshParts) { for (int i = 0; i < mesh_part.PrimitiveCount; i++) { faces[nf + fcount] = new CollisionFace(count, mesh_indices, vcount + mesh_part.BaseVertex, vertices); count += 3; nf++; } } } else { int[] mesh_indices = new int[mesh.IndexBuffer.SizeInBytes / sizeof(int)]; mesh.IndexBuffer.GetData<int>(mesh_indices); int count = 0; foreach (ModelMeshPart mesh_part in mesh.MeshParts) { for (int i = 0; i < mesh_part.PrimitiveCount; i++) { faces[nf + fcount] = new CollisionFace(count, mesh_indices, vcount + mesh_part.BaseVertex, vertices); count += 3; nf++; } } } vcount += nv; fcount += nf; } CollisionBox box = new CollisionBox(float.MaxValue, -float.MaxValue); for (int i = 0; i < vcount; i++) box.AddPoint(vertices[i]); if (subdiv_level > 6) subdiv_level = 6; // max 8^6 nodes tree = new CollisionTree(box, subdiv_level); for (int i = 0; i < fcount; i++) tree.AddElement(faces[i]); }
public CollisionTree(CollisionBox box, uint subdivLevel) { root = new CollisionTreeNode(box, subdivLevel); recurseId = 0; }
public bool BoxMove( CollisionBox box, Vector3 pointStart, Vector3 pointEnd, Vector3[] vertices, float frictionFactor, float bumpFactor, uint recurseLevel, out Vector3 pointResult) { pointResult = pointStart; Vector3 delta = pointEnd - pointStart; float deltaLength = delta.Length(); if (deltaLength < 0.00001f) { return(false); } float totalDistance = deltaLength; delta *= 1.0f / deltaLength; float bias = 0.01f; pointEnd += delta * bias; bool collisionHit = false; while (recurseLevel > 0) { float dist; Vector3 pos, norm; if (false == BoxIntersect(box, pointStart, pointEnd, vertices, out dist, out pos, out norm)) { pointStart = pointEnd - delta * bias; break; } collisionHit = true; dist -= bias / Math.Abs(Vector3.Dot(delta, norm)); if (dist > 0) { pointStart += delta * dist; totalDistance -= dist; } Vector3 reflectDirection = Vector3.Normalize(Vector3.Reflect(delta, norm)); Vector3 n = norm * Vector3.Dot(reflectDirection, norm); Vector3 t = reflectDirection - n; reflectDirection = frictionFactor * t + bumpFactor * n; pointEnd = pointStart + reflectDirection * totalDistance; delta = pointEnd - pointStart; deltaLength = delta.Length(); if (deltaLength < 0.00001f) { break; } delta *= 1.0f / deltaLength; pointEnd += delta * bias; recurseLevel--; } pointResult = pointStart; return(collisionHit); }
public void GetElements(CollisionBox b, List <CollisionTreeElem> e) { tree.GetElements(b, e); }
// box intersect face and return intersection distance, point and normal public override bool BoxIntersect(CollisionBox ray_box, Vector3 ray_origin, Vector3 ray_direction, Vector3[] vert_pos, out float intersect_distance, out Vector3 intersect_position, out Vector3 intersect_normal) { intersect_distance = float.MaxValue; intersect_position = ray_origin; intersect_normal = Vector3.Zero; bool intersected = false; Vector3 p1, p2, p3, p4; uint i, j; CollisionBox world_box = new CollisionBox(ray_box.min + ray_origin, ray_box.max + ray_origin); Vector3[] box_verts = world_box.GetVertices(); Vector3[] box_edges = world_box.GetEdges(); // intersect box edges to face edges for (i = 0; i < 12; i++) { // cull edges with normal more than 135 degree from moving direction if (Vector3.Dot(CollisionBox.edge_normals[i], ray_direction) < -0.70710678) continue; p1 = box_edges[i * 2]; p2 = box_edges[i * 2 + 1]; p4 = vert_pos[vertices[0]]; for (j = 0; j < vertices.Length; j++) { p3 = p4; p4 = vert_pos[vertices[(j + 1) % vertices.Length]]; float distance; Vector3 position; if (CollisionFace.EdgeIntersect(p1, p2, ray_direction, p3, p4, out distance, out position)) { if (distance < intersect_distance) { intersect_distance = distance; intersect_position = position; intersect_normal = Vector3.Normalize(Vector3.Cross(p2-p1,p3-p4)); if (Vector3.Dot(ray_direction, intersect_normal) > 0) intersect_normal = Vector3.Negate(intersect_normal); intersected = true; } } } } // intersect from face vertices to box for (i = 0; i < 3; i++) { float tnear, tfar; p1 = vert_pos[vertices[i]]; int box_face_id = world_box.RayIntersect(p1, -ray_direction, out tnear, out tfar); if (box_face_id > -1) { if (tnear < intersect_distance) { intersect_distance = tnear; intersect_position = p1; intersect_normal = -CollisionBox.face_normals[box_face_id]; intersected = true; } } } // intersect from box vertices to face polygon Vector3 v1 = vert_pos[vertices[0]]; Vector3 v2 = vert_pos[vertices[1]]; Vector3 v3 = vert_pos[vertices[2]]; for (i = 0; i < 8; i++) { // cull vertices with normal more than 135 degree from moving direction if (Vector3.Dot(CollisionBox.vertex_normals[i], ray_direction) < -0.70710678) continue; Vector3 uvt; if (CollisionFace.RayTriangleIntersect(box_verts[i], ray_direction, v1, v2, v3, out uvt.Z, out uvt.X, out uvt.Y)) { if (uvt.Z < intersect_distance) { intersect_distance = uvt.Z; intersect_position = (1.0f - uvt.X - uvt.Y) * v1 + uvt.X * v2 + uvt.Y * v3; intersect_normal = Vector3.Normalize(Vector3.Cross(v3 - v1, v2 - v1)); intersected = true; } } } return intersected; }
public CollisionMesh(Model model, uint subdivLevel) { int verticesCapacity = 0; int facesCapacity = 0; foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { verticesCapacity += part.VertexBuffer.VertexCount; facesCapacity += part.PrimitiveCount; } } vertices = new Vector3[verticesCapacity]; faces = new CollisionFace[facesCapacity]; int verticesLength = 0; int facesLength = 0; Matrix[] modelTransforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(modelTransforms); foreach (ModelMesh mesh in model.Meshes) { Matrix meshTransform = modelTransforms[mesh.ParentBone.Index]; foreach (ModelMeshPart part in mesh.MeshParts) { int vertexCount = part.VertexBuffer.VertexCount; CustomVertex[] partVertices = new CustomVertex[vertexCount]; part.VertexBuffer.GetData(partVertices); for (int i = 0; i < vertexCount; i++) { vertices[verticesLength + i] = Vector3.Transform(partVertices[i].Position, meshTransform); } int indexCount = part.IndexBuffer.IndexCount; short[] partIndices = new short[indexCount]; part.IndexBuffer.GetData(partIndices); for (int i = 0; i < part.PrimitiveCount; i++) { faces[facesLength + i] = new CollisionFace( part.StartIndex + i * 3, partIndices, verticesLength + part.VertexOffset, vertices); } verticesLength += vertexCount; facesLength += part.PrimitiveCount; } } CollisionBox box = new CollisionBox(float.MaxValue, -float.MaxValue); for (int i = 0; i < verticesCapacity; i++) box.AddPoint(vertices[i]); if (subdivLevel > 6) subdivLevel = 6; // max 8^6 nodes tree = new CollisionTree(box, subdivLevel); for (int i = 0; i < facesCapacity; i++) tree.AddElement(faces[i]); }
public bool BoxIntersect( CollisionBox box, Vector3 ray_start, Vector3 ray_end, out float intersect_distance, out Vector3 intersect_position, out Vector3 intersect_normal) { return tree.BoxIntersect(box, ray_start, ray_end, vertices, out intersect_distance, out intersect_position, out intersect_normal); }
public bool BoxMove( CollisionBox box, Vector3 point_start, Vector3 point_end, float friction_factor, float bump_factor, uint recurse_level, out Vector3 point_result) { return tree.BoxMove(box, point_start, point_end, vertices, friction_factor, bump_factor, recurse_level, out point_result); }
// check if two bounding boxes have any intersection public bool BoxIntersect(CollisionBox bb) { if (max.X >= bb.min.X && min.X <= bb.max.X && max.Y >= bb.min.Y && min.Y <= bb.max.Y && max.Z >= bb.min.Z && min.Z <= bb.max.Z) return true; return false; }
public void GetElements(CollisionBox b, List<CollisionTreeElem> e) { tree.GetElements(b, e); }
// box intersect face and return intersection distance, point and normal public override bool BoxIntersect( CollisionBox rayBox, Vector3 rayOrigin, Vector3 rayDirection, Vector3[] vertices, out float intersectDistance, out Vector3 intersectPosition, out Vector3 intersectNormal) { intersectDistance = float.MaxValue; intersectPosition = rayOrigin; intersectNormal = Vector3.Zero; bool intersected = false; Vector3 p1, p2, p3, p4; uint i, j; CollisionBox worldBox = new CollisionBox(rayBox.min + rayOrigin, rayBox.max + rayOrigin); Vector3[] boxVerts = worldBox.GetVertices(); Vector3[] boxEdges = worldBox.GetEdges(); float distance; Vector3 position; // intersect box edges to face edges for (i = 0; i < 12; i++) { // cull edges with normal more than 135 degree from moving direction float dot = Vector3.Dot(CollisionBox.edgeNormals[i], rayDirection); if (dot < -0.70710678) { continue; } p1 = boxEdges[i * 2]; p2 = boxEdges[i * 2 + 1]; p4 = vertices[indices[0]]; for (j = 0; j < indices.Length; j++) { p3 = p4; p4 = vertices[indices[(j + 1) % indices.Length]]; if (CollisionFace.EdgeIntersect(p1, p2, rayDirection, p3, p4, out distance, out position)) { if (distance < intersectDistance) { intersectDistance = distance; intersectPosition = position; intersectNormal = Vector3.Cross(p2 - p1, p3 - p4); intersectNormal = Vector3.Normalize(intersectNormal); if (Vector3.Dot(rayDirection, intersectNormal) > 0) { intersectNormal = Vector3.Negate(intersectNormal); } intersected = true; } } } } // intersect from face vertices to box for (i = 0; i < 3; i++) { float tnear, tfar; p1 = vertices[indices[i]]; int box_face_id = worldBox.RayIntersect(p1, -rayDirection, out tnear, out tfar); if (box_face_id > -1) { if (tnear < intersectDistance) { intersectDistance = tnear; intersectPosition = p1; intersectNormal = -CollisionBox.faceNormals[box_face_id]; intersected = true; } } } // intersect from box vertices to face polygon Vector3 v1 = vertices[indices[0]]; Vector3 v2 = vertices[indices[1]]; Vector3 v3 = vertices[indices[2]]; Vector3 uvt; for (i = 0; i < 8; i++) { // cull vertices with normal more than 135 degree from moving direction float dot = Vector3.Dot(CollisionBox.vertexNormals[i], rayDirection); if (dot < -0.70710678) { continue; } if (CollisionFace.RayTriangleIntersect(boxVerts[i], rayDirection, v1, v2, v3, out uvt.Z, out uvt.X, out uvt.Y)) { if (uvt.Z < intersectDistance) { intersectDistance = uvt.Z; intersectPosition = (1.0f - uvt.X - uvt.Y) * v1 + uvt.X * v2 + uvt.Y * v3; intersectNormal = Vector3.Cross(v3 - v1, v2 - v1); intersectNormal = Vector3.Normalize(intersectNormal); intersected = true; } } } return(intersected); }