Exemplo n.º 1
0
        public bool Raycast(FRay ray, out float hitDistance, bool returnFirstHit = false)
        {
            // Raycast against the bounding box of the entire mesh first to see if we can save ourself a bunch of time.
            bool hitsAABB = WMath.RayIntersectsAABB(ray, BoundingBox.Min, BoundingBox.Max, out hitDistance);

            if (!hitsAABB)
            {
                return(false);
            }

            // Okay, they've intersected with our big bounding box, so now we'll trace against individual mesh bounding box.
            // However, if they've applied skinning data to the meshes then these bounding boxes are no longer valid, so this
            // optimization step only counts if they're not applying any skinning.
            bool canSkipShapeTriangles = m_currentBoneAnimation == null;
            bool rayDidHit             = false;

            foreach (var shape in SHP1Tag.Shapes)
            {
                if (canSkipShapeTriangles)
                {
                    hitsAABB = WMath.RayIntersectsAABB(ray, shape.BoundingBox.Min, shape.BoundingBox.Max, out hitDistance);

                    // If we didn't intersect with this shape, just go onto the next one.
                    if (!hitsAABB)
                    {
                        continue;
                    }
                }

                // We either intersected with this shape's AABB or they have skinning data applied (and thus we can't skip it),
                // thus, we're going to test against every (skinned!) triangle in this shape.
                bool hitTriangle = false;
                var  vertexList  = shape.OverrideVertPos.Count > 0 ? shape.OverrideVertPos : shape.VertexData.Position;

                for (int i = 0; i < shape.Indexes.Count; i += 3)
                {
                    float triHitDist;
                    hitTriangle = WMath.RayIntersectsTriangle(ray, vertexList[shape.Indexes[i]], vertexList[shape.Indexes[i + 1]], vertexList[shape.Indexes[i + 2]], true, out triHitDist);

                    // If we hit this triangle and we're OK to just return the first hit on the model, then we can early out.
                    if (hitTriangle && returnFirstHit)
                    {
                        hitDistance = triHitDist;
                        return(true);
                    }

                    // Otherwise, we need to test to see if this hit is closer than the previous hit.
                    if (hitTriangle)
                    {
                        if (triHitDist < hitDistance)
                        {
                            hitDistance = triHitDist;
                        }
                        rayDidHit = true;
                    }
                }
            }

            return(rayDidHit);
        }
Exemplo n.º 2
0
        private CollisionTriangle Raycast(FRay ray)
        {
            if (World.Map == null || ActiveCollisionMesh == null)
            {
                return(null);
            }

            CollisionTriangle closestResult   = null;
            float             closestDistance = float.MaxValue;

            foreach (var tri in ActiveCollisionMesh.Triangles)
            {
                float dist = float.MaxValue;

                if (WMath.RayIntersectsTriangle(ray, tri.Vertices[1], tri.Vertices[0], tri.Vertices[2], true, out dist))
                {
                    if (dist < closestDistance)
                    {
                        closestDistance = dist;
                        closestResult   = tri;
                    }
                }
            }

            return(closestResult);
        }
Exemplo n.º 3
0
        private float GetCollisionDistanceFromCamera()
        {
            if (World.Map == null)
            {
                return(-1);
            }

            List <WCollisionMesh> meshes;

            if (World.Map.FocusedScene is WStage)
            {
                // If a stage is selected, raycast against the collision meshes for all rooms that are loaded.
                meshes = new List <WCollisionMesh>();
                foreach (var scene in World.Map.SceneList)
                {
                    meshes.AddRange(scene.GetChildrenOfType <WCollisionMesh>());
                }
            }
            else
            {
                // If a room is selected, raycast against the collision mesh for only that room.
                meshes = World.Map.FocusedScene.GetChildrenOfType <WCollisionMesh>();
            }

            if (meshes.Count == 0)
            {
                return(-1);
            }

            WCamera camera = World.GetFocusedSceneView().ViewCamera;

            Vector3 dir = Vector3.Transform(new Vector3(0.0f, 0.0f, -1.0f), camera.Transform.Rotation);

            dir.Normalize();
            FRay ray = new FRay(camera.Transform.Position, dir);

            CollisionTriangle closestResult   = null;
            float             closestDistance = float.MaxValue;

            foreach (var mesh in meshes)
            {
                foreach (var tri in mesh.Triangles)
                {
                    float dist = float.MaxValue;

                    if (WMath.RayIntersectsTriangle(ray, tri.Vertices[1], tri.Vertices[0], tri.Vertices[2], true, out dist))
                    {
                        if (dist < closestDistance)
                        {
                            closestDistance = dist;
                            closestResult   = tri;
                        }
                    }
                }
            }

            if (closestResult == null)
            {
                return(-1.0f);
            }

            return(closestDistance);
        }