예제 #1
0
        public void AddNewPolygonList(List<TransparentPolygonReference> p, Transform transform, Frustum frustum, Camera cam)
        {
            foreach (var pp in p)
            {
                var transformed = new Polygon();
                transformed.Vertices.Resize(pp.Polygon.Vertices.Count, () => new Vertex());
                transformed.Transform(pp.Polygon, transform);
                transformed.DoubleSide = pp.Polygon.DoubleSide;

                if(frustum.IsPolyVisible(transformed, cam))
                {
                    addPolygon(ref _root, new BSPFaceRef(transform, pp), transformed);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Check polygon visibility through the portal.
        /// </summary>
        public bool IsPolyVisible(Polygon p, Camera cam)
        {
            if (!p.DoubleSide && p.Plane.Distance(cam.Position) < 0)
                return false;

            // Direction from the camera position to an arbitrary vertex frustum
            StaticFuncs.Assert(Vertices.Any());
            var dir = Vertices[0] - cam.Position;
            var lambda = 0.0f;

            // Polygon fits whole frustum (shouldn't happen, but we check anyway)
            if(p.RayIntersect(dir, cam.Position, ref lambda))
            {
                return true;
            }

            // Generate queue order
            var nextPlaneIdx = 0;
            // 3 neighboring clipping planes
            var currentPlane = Planes.Last();
            var prevPlane = Planes[Planes.Count - 2];
            // in case no intersection
            var ins = true;
            // iterate through all the planes of this frustum
            for (var i = 0; i < Vertices.Count; i++)
            {
                var nextPlane = Planes[nextPlaneIdx];

                // Queue vertices for testing
                var prevVertex = p.Vertices.Last();
                // signed distance from the current point to the previous plane
                var dist0 = currentPlane.Distance(prevVertex.Position);
                var outs = true;
                // iterate through all the vertices of the polygon
                foreach (var currentVertex in p.Vertices)
                {
                    var dist1 = currentPlane.Distance(currentVertex.Position);
                    // the split point in the plane
                    if(Math.Abs(dist0) < SPLIT_EPSILON)
                    {
                        if(prevPlane.Distance(prevVertex.Position) > -SPLIT_EPSILON
                            && nextPlane.Distance(prevVertex.Position) > -SPLIT_EPSILON
                            && Normal.Distance(prevVertex.Position) > -SPLIT_EPSILON)
                        {
                            // Frustum-vertex intersection test is passed
                            return true;
                        }
                    }

                    // vertices from different sides of the plane (or on it)
                    if(dist0 * dist1 < 0 && Math.Abs(dist1) >= SPLIT_EPSILON)
                    {
                        // vector connecting vertices
                        dir = currentVertex.Position - prevVertex.Position;
                        // We are looking for the point of intersection
                        var T = currentPlane.RayIntersect(prevVertex.Position, dir);
                        if(prevPlane.Distance(T) > -SPLIT_EPSILON && nextPlane.Distance(T) > -SPLIT_EPSILON)
                        {
                            // Frustum-ray intersection test is passed
                            return true;
                        }
                    }

                    // point is outside
                    if(dist1 < -SPLIT_EPSILON)
                    {
                        ins = false;
                    }
                    else
                    {
                        outs = false;
                    }

                    // We moved all the vertices of the polygon
                    prevVertex = currentVertex;
                    // We moved all distances
                    dist0 = dist1;
                    // finished with all polygon vertices
                }

                if(outs)
                {
                    // all points are outside of the current plane - definitely exit
                    return false;
                }
                // We moved all the clipping planes
                prevPlane = currentPlane;
                currentPlane = nextPlane;
                nextPlaneIdx++;
                // finished with all planes of this frustum
            }
            if(ins)
            {
                // all the vertices are inside - test is passed
                return true;
            }

            return false;
        }
예제 #3
0
        public void GenClipPlanes(Camera cam)
        {
            if (Vertices.Count == 0)
                return;

            Planes.Resize(Vertices.Count, () => new Plane());

            var curr_v = Vertices.Last();
            var prev_v = Vertices[Vertices.Count - 2];

            for (var i = 0; i < Vertices.Count; i++)
            {
                var V1 = prev_v - cam.Position; // POV-vertx vector
                var V2 = prev_v - curr_v; // vector connecting neighbor vertices
                V1.Normalize();
                V2.Normalize();
                Planes[i].Assign(V1, V2, curr_v);

                prev_v = curr_v;
                curr_v = Vertices[i];
            }
        }
예제 #4
0
        public bool IsOBBVisible(OBB obb, Camera cam)
        {
            var ins = true;
            foreach (var p in obb.Polygons)
            {
                var t = p.Plane.Distance(cam.Position);
                if(t > 0.0 && IsPolyVisible(p, cam))
                {
                    return true;
                }
                if(ins && t > 0)
                {
                    ins = false;
                }
            }

            return ins;
        }
예제 #5
0
        public bool IsAABBVisible(Vector3 bbMin, Vector3 bbMax, Camera cam)
        {
            var poly = new Polygon();
            poly.Vertices = new List<Vertex>(4);
            var ins = true;

            // X AXIS

            if(cam.Position.X < bbMin.X)
            {
                poly.Plane.Normal.X = -1.0f;
                poly.Plane.Dot = -bbMin.X;

                poly.Vertices[0].Position[0] = bbMin[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMin[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if(IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if(cam.Position.X > bbMax.X)
            {
                poly.Plane.Normal.X = 1.0f;
                poly.Plane.Dot = bbMax.X;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMax[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMax[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            // Y AXIS

            poly.Plane.Normal.X = 0;
            poly.Plane.Normal.Z = 0;

            if (cam.Position.Y < bbMin.Y)
            {
                poly.Plane.Normal.Y = -1.0f;
                poly.Plane.Dot = -bbMin.Y;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMin[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if (cam.Position.Y > bbMax.Y)
            {
                poly.Plane.Normal.Y = 1.0f;
                poly.Plane.Dot = -bbMax.Y;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMax[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMax[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            // Z AXIS

            poly.Plane.Normal.X = 0;
            poly.Plane.Normal.Y = 0;

            if (cam.Position.Z < bbMin.Z)
            {
                poly.Plane.Normal.Z = -1.0f;
                poly.Plane.Dot = -bbMin.Z;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMin[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMax[1];
                poly.Vertices[1].Position[2] = bbMin[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if (cam.Position.Z > bbMax.Z)
            {
                poly.Plane.Normal.Z = 1.0f;
                poly.Plane.Dot = -bbMax.Z;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMax[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMax[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMax[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            return ins;
        }
예제 #6
0
        public static void Cam_FollowEntity(Camera cam, Entity ent, float dx, float dz)
        {
            var cameraFrom = new Transform();
            var cameraTo = new Transform();

            // Reset to initial
            cameraFrom.SetIdentity();
            cameraTo.SetIdentity();

            var cb = ent.CallbackForCamera();

            var camPos = cam.Position;

            // Basic camera override, completely placeholder until a system classic-like is created
            if (!ControlStates.MouseLook) // If mouse look is off
            {
                var currentAngle = CamAngles.X * RadPerDeg; // Current is the current cam angle
                var targetAngle = ent.Angles.X * RadPerDeg;
                    // Target is the target angle which is the entity's angle itself
                var rotSpeed = 2.0f; // Speed of rotation

                //@FIXME
                // If Lara is in a specific state we want to rotate -75 deg or +75 deg depending on camera collision
                if(ent.Bf.Animations.LastState == TR_STATE.LaraReach)
                {
                    if(cam.TargetDir == TR_CAM_TARG.Back)
                    {
                        var camPos2 = camPos;
                        cameraFrom.Origin = camPos2;
                        camPos2.X += (float) (Math.Sin((ent.Angles.X - 90.0f) * RadPerDeg) *
                                              ControlStates.CamDistance);
                        camPos2.Y -= (float) (Math.Cos((ent.Angles.X - 90.0f) * RadPerDeg) *
                                              ControlStates.CamDistance);
                        cameraTo.Origin = camPos2;

                        // If collided we want to go right otherwise stay left
                        if(Cam_HasHit(cb, cameraFrom, cameraTo))
                        {
                            camPos2 = camPos;
                            cameraFrom.Origin = camPos2;
                            camPos2.X += (float)(Math.Sin((ent.Angles.X + 90.0f) * RadPerDeg) *
                                             ControlStates.CamDistance);
                            camPos2.Y -= (float)(Math.Cos((ent.Angles.X + 90.0f) * RadPerDeg) *
                                                  ControlStates.CamDistance);
                            cameraTo.Origin = camPos2;

                            // If collided we want to go to back else right
                            cam.TargetDir = Cam_HasHit(cb, cameraFrom, cameraTo) ? TR_CAM_TARG.Back : TR_CAM_TARG.Right;
                        }
                        else
                        {
                            cam.TargetDir = TR_CAM_TARG.Left;
                        }
                    }
                }
                else if(ent.Bf.Animations.LastState == TR_STATE.LaraJumpBack)
                {
                    cam.TargetDir = TR_CAM_TARG.Front;
                }
                // ReSharper disable once RedundantCheckBeforeAssignment
                else if(cam.TargetDir != TR_CAM_TARG.Back)
                {
                    cam.TargetDir = TR_CAM_TARG.Back; // Reset to back
                }

                // If target mis-matches current we need to update the camera's angle to reach target!
                if (currentAngle != targetAngle)
                {
                    switch (cam.TargetDir)
                    {
                        case TR_CAM_TARG.Back:
                            targetAngle = ent.Angles.X * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Front:
                            targetAngle = (ent.Angles.X - 180.0f) * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Left:
                            targetAngle = (ent.Angles.X - 75.0f) * RadPerDeg;
                            break;
                        case TR_CAM_TARG.Right:
                            targetAngle = (ent.Angles.X + 75.0f) * RadPerDeg;
                            break;
                        default:
                            targetAngle = ent.Angles.X * RadPerDeg; // Same as TR_CAM_TARG_BACK (default pos)
                            break;
                    }

                    var dAngle = CamAngles.X - targetAngle;
                    if (dAngle > Rad90)
                    {
                        dAngle -= 1 * RadPerDeg;
                    }
                    else
                    {
                        dAngle += 1 * RadPerDeg;
                    }
                    CamAngles.X =
                        (CamAngles.X +
                         Helper.Atan2((float) Math.Sin(currentAngle - dAngle), (float) Math.Cos(currentAngle + dAngle)) *
                         EngineFrameTime * rotSpeed) % Rad360; // Update camera's angle
                }
            }

            camPos = ent.CamPosForFollowing(dz);

            // Code to manage screen shaking effects
            if(Renderer.Camera.ShakeTime > 0.0f && Renderer.Camera.ShakeValue > 0.0f)
            {
                camPos = camPos.AddF((Helper.CPPRand() % Math.Abs(Renderer.Camera.ShakeValue) -
                                     Renderer.Camera.ShakeValue / 2.0f) * Renderer.Camera.ShakeTime);
                Renderer.Camera.ShakeTime = Renderer.Camera.ShakeTime < 0.0f
                    ? 0.0f
                    : Renderer.Camera.ShakeTime - EngineFrameTime;
            }

            cameraFrom.Origin = camPos;
            camPos.Z += dz;
            cameraTo.Origin = camPos;
            if(Cam_HasHit(cb, cameraFrom, cameraTo))
            {
                Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
            }

            if(dx != 0.0f)
            {
                cameraFrom.Origin = camPos;
                camPos += dx * cam.RightDirection;
                cameraTo.Origin = camPos;
                if (Cam_HasHit(cb, cameraFrom, cameraTo))
                {
                    Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                    camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
                }

                cameraFrom.Origin = camPos;

                var cosAy = Math.Cos(CamAngles.Y);
                var camDx = Math.Sin(CamAngles.X) * cosAy;
                var camDy = -Math.Cos(CamAngles.X) * cosAy;
                var camDz = -Math.Sin(CamAngles.Y);
                camPos.X += (float) (camDx * ControlStates.CamDistance);
                camPos.Y += (float) (camDy * ControlStates.CamDistance);
                camPos.Z += (float) (camDz * ControlStates.CamDistance);

                cameraTo.Origin = camPos;
                if (Cam_HasHit(cb, cameraFrom, cameraTo))
                {
                    Helper.SetInterpolate3(out camPos, cameraFrom.Origin, cameraTo.Origin, cb.ClosestHitFraction);
                    camPos += (cb.HitNormalWorld * 2.0f).ToOpenTK();
                }
            }

            // Update cam pos
            cam.Position = camPos;

            // Modify cam pos for quicksand rooms
            cam.CurrentRoom = Room.FindPosCogerrence(cam.Position - new Vector3(0, 0, 128), cam.CurrentRoom);
            if(cam.CurrentRoom != null && cam.CurrentRoom.Flags.HasFlagUns(RoomFlag.Quicksand))
            {
                var pos = cam.Position;
                pos.Z = cam.CurrentRoom.BBMax.Z + 2.0f * 64.0f;
                cam.Position = pos;
            }

            cam.SetRotation(CamAngles);
            cam.CurrentRoom = Room.FindPosCogerrence(cam.Position, cam.CurrentRoom);
        }
예제 #7
0
        public bool IsVisibleInRoom(Room room, Camera cam)
        {
            var polys = Polygons;

            if (room.Frustum.Count == 0)
            {
                var ins = true;
                foreach (var polygon in polys)
                {
                    var t = polygon.Plane.Distance(EngineCamera.Position);
                    if (t > 0 && EngineCamera.Frustum.IsPolyVisible(polygon, cam))
                    {
                        return true;
                    }
                    if (ins && t > 0)
                    {
                        ins = false;
                    }
                }
                return ins;
            }

            return room.Frustum.Any(frustum => (from polygon in polys
                                                let t = polygon.Plane.Distance(cam.Position)
                                                where t > 0 && frustum.IsPolyVisible(polygon, cam)
                                                select polygon).Any());
        }