Xbox LIVE Indie Games
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 1 (4 posts)

Help - Third Person 3D Camera Collision

Last post 4/16/2009 5:16 PM by derekadams32. 3 replies.
  • 4/9/2009 4:20 PM

    Help - Third Person 3D Camera Collision

    So I'm in charge of creating the camera for a third person game in development called MORPH.  (Its still in early stages).

    Having never done camera collision before, I'm struggling to understand how to adjust its location based on the walls/objects in the game.
    I've posted the update function within my camera class.

    I initially tried to do the collision with a bounding sphere around the camera, but it made it difficult to find the correct location to reposition the camera so the character (blob) wasnt blocked.  I've switched over to a Ray (called camAdjust) that extends from the camera location (futureMove, the next position for the camera as long as there are no intersections) in the direction of the character.  I am pretty sure it is set up correctly and that the intersections are taking place, but I guess I don't understand how to update the camera. 

    Basically, if a wall comes between the camera and the player, then the camera should be placed just in front of that wall to see the player again.  If the camera slides along a wall, then it should never pass through that wall, always keeping the player in view. 

    Any suggestions?
    Thanks in advance
    -Derek
    public override void Update(GameTime gameTime) 
            { 
                 
                Vector3 moveVector = Vector3.Zero; 
                float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; 
                MouseState mState = Mouse.GetState(); 
     
                float mouseX = mState.X - mStateCashe.X; 
                float mouseY = mState.Y - mStateCashe.Y; 
     
                cameraPitch -= (mouseY * 0.3f) * deltaTime; 
                cameraYaw -= (mouseX * 0.3f) * deltaTime; 
     
                Matrix cameraViewRotationMatrix = Matrix.CreateRotationX(cameraPitch) * Matrix.CreateRotationY(cameraYaw); 
                Matrix cameraMoveRotationMatrix = Matrix.CreateRotationY(cameraYaw); 
                Vector3 transformedCameraReference = Vector3.Transform(cameraReference, cameraViewRotationMatrix); 
     
                cameraPitch = MathHelper.Clamp(cameraPitch, MathHelper.ToRadians(-89.9f), MathHelper.ToRadians(89.9f));  
                cameraTarget += Vector3.Transform(moveVector, cameraMoveRotationMatrix); 
                //cameraPosition = transformedCameraReference + cameraTarget; 
     
                Vector3 futureMove = transformedCameraReference + cameraTarget; 
                bsCamera = new BoundingSphere(new Vector3(futureMove.X, futureMove.Y, futureMove.Z), 3.0f);// radius = 1/Math.Cos(half_FOV) 
                Vector3 distance = new Vector3(futureMove.X, futureMove.Y, futureMove.Z) - cameraTarget; 
                distance.Normalize(); 
                float length = distance.Length(); 
                Ray camAdjust = new Ray(futureMove, distance); 
                 
                //CAMERA collision detection 
                // bsCamera.Center += futureMove; 
                collideX = false
                collideZ = false
                 
                foreach (BoundingBox drawObj in wall1) 
                { 
                    float? check = camAdjust.Intersects(drawObj); 
                    if (check != null
                    { 
                        if (check < length) 
                        { 
                            if (drawObj.Min.X == drawObj.Max.X) 
                                collideX = true
                            if (drawObj.Min.Z == drawObj.Max.Z) 
                                collideZ = true
                        } 
                    } 
                } 
                 
                if (collideX && collideZ) 
                { 
                    cameraReference = cameraReference * (cameraReference.Length() / length ); 
                    //bsCamera.Center -= futureMove; 
                    //cameraPosition -= futureMove; 
                } 
                else if (collideX) 
                { 
                    //cameraTarget = new Vector3(cameraTarget.X, cameraTarget.Y, bsCamera.Center.Z); 
                    cameraReference = cameraReference * (cameraReference.Length() / length); 
                    cameraPosition.X = futureMove.X; 
                } 
                else if (collideZ) 
                { 
                    //CameraTarget = new Vector3(bsCamera.Center.X, cameraTarget.Y, cameraTarget.Z); 
                    cameraReference = cameraReference * (cameraReference.Length() / length); 
                    cameraPosition.Z = futureMove.Z; 
                } 
                else 
                { 
                    //cameraTarget = bsCamera.Center; 
                    //cameraReference = cameraReference * (cameraReference.Length() / length); 
                    cameraPosition = futureMove; 
                } 
                transformedCameraReference = Vector3.Transform(cameraReference, cameraViewRotationMatrix); 
                cameraPitch = MathHelper.Clamp(cameraPitch, MathHelper.ToRadians(-89.9f), MathHelper.ToRadians(89.9f)); 
                cameraTarget += Vector3.Transform(moveVector, cameraMoveRotationMatrix); 
                 
                //Mouse.SetPosition(games.GraphicsDevice.Viewport.Width / 2, games.GraphicsDevice.Viewport.Height / 2); 
     
                // Keep the camera just above the height of the floor. 
                if (cameraPosition.Y < 0.1f) 
                { 
                    cameraPosition.Y = 0.1f; 
                } 
                if (cameraPosition.Y > 12.0f) 
                { 
                    cameraPosition.Y = 11.9f; 
                } 
     
                mStateCashe = mState; 
     
                base.Update(gameTime); 
            } 

  • 4/9/2009 4:37 PM In reply to

    Re: Help - Third Person 3D Camera Collision

    Instead of casting a ray from the camera to the character, try casting a ray from your character's head (or a point just above it, or elsewhere as appropriate for your game) to where the camera would be assuming no walls. If the ray hits something... stop at that point, and place the camera there instead. Like this:

           W
    P-----CW    V 
           W

    P = Player
    - = hit ray
    C = final Camera position
    W = Wall
    V = 'virtual' camera position, where it would be if the wall wasn't there

    Hope that makes sense. That's the simplest solution but there are (obviously) complications. For example, that'll give a very 'jerky' effect... the camera will be 10m from the player, but then a wall gets in the way, bam! it jumps to 5m from the player. So, you'll want to cast more rays, to the left and right of where the camera really "is", so it can detect there will be a hit if the camera is rotated and start moving forward before the wall actually gets in the way (and back when the wall disappears, etc).

    Also, what it the thing it hits is just a lamp-post or something? You don't really want the camera to be blocked by something so thin, just let the player be partially obscured by it, no worries. But then, if you don't hit it at all, you could end up with the camera inside it! So there's two choices... ignore it, but add a special case for when you're inside it; or, detach the camera completely. Treat it as a separate entity rather than something cast by a ray. It'll need AI to keep the character in view. Much more complicated but could give better results... if you get it right...!

    I worked on a 3D third person camera for the Xbox 360 launch title Kameo: Elements of Power, and these kinds of issues took up probably 40-50% of my time for three years! It's not a trivial problem. (Although, Kameo had 11 different player characters and over 20 different camera modes... your game may be simpler). On the other hand, many games get away with cameras much less intelligent than Kameo's, and (as with with all things) you can get 90% of the way there in 10% of the time. Good luck!
  • 4/16/2009 5:14 PM In reply to

    Re: Help - Third Person 3D Camera Collision

    public override void Update(GameTime gameTime) 
            { 
                GamePadState padState = GamePad.GetState(PlayerIndex.One); 
                Vector3 moveVector = Vector3.Zero; 
                float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; 
                MouseState mState = Mouse.GetState(); 
     
                //float mouseX = mState.X - mStateCashe.X; 
                //float mouseY = mState.Y - mStateCashe.Y; 
                float mouseX = padState.ThumbSticks.Right.X * 8.0f;// -mStateCashe.X; 
                float mouseY = -padState.ThumbSticks.Right.Y * 8.0f;// -mStateCashe.Y; 
     
                cameraPitch -= (mouseY * 0.3f) * deltaTime; 
                cameraYaw -= (mouseX * 0.3f) * deltaTime; 
     
                Matrix cameraViewRotationMatrix = Matrix.CreateRotationX(cameraPitch) * Matrix.CreateRotationY(cameraYaw); 
                Matrix cameraMoveRotationMatrix = Matrix.CreateRotationY(cameraYaw); 
                Vector3 transformedCameraReference = Vector3.Transform(cameraReference, cameraViewRotationMatrix); 
     
                cameraPitch = MathHelper.Clamp(cameraPitch, MathHelper.ToRadians(-89.9f), MathHelper.ToRadians(89.9f));  
                cameraTarget += Vector3.Transform(moveVector, cameraMoveRotationMatrix); 
                //cameraPosition = transformedCameraReference + cameraTarget; 
     
                Vector3 futureMove = transformedCameraReference + cameraTarget;             
                bsCamera = new BoundingSphere(new Vector3(futureMove.X, futureMove.Y, futureMove.Z), 3.0f); 
                 
                Vector3 distance = futureMove - cameraTarget; 
                float length = distance.Length(); 
                distance.Normalize();             
                Ray camAdjust = new Ray(cameraTarget, distance); 
                 
                //CAMERA collision detection 
                collideX = false
                collideZ = false
                float checkMin = 10000.0f; 
                 
                foreach (BoundingBox drawObj in wall1) 
                { 
                    float? check = camAdjust.Intersects(drawObj); 
                    if (check != null
                    { 
                        if (check < checkMin) 
                        { 
                            checkMin = (float)check; 
                        } 
                        if (checkMin < length) 
                        { 
                            futureMove = cameraTarget + (distance * (float)checkMin);                         
                        } 
                    }                 
                } 
                 
                if ((int)CameraReference.Length() > (int)length) 
                { 
                    cameraReference.X = cameraReference.X * 1.01f; 
                    cameraReference.Z = cameraReference.Z * 1.01f; 
                } 
                /*
                if (futureMove.Y < 0.8f)
                {
                    //cameraPosition.Y = 0.8f;
                    futureMove.Y = 0.8f;
                }
                if (futureMove.Y > 12.0f)
                {
                    //cameraPosition.Y = 11.9f;
                    futureMove.Y = 11.9f;
                }
                 */  
                cameraPosition = futureMove; 
                 
                transformedCameraReference = Vector3.Transform(cameraReference, cameraViewRotationMatrix); 
                cameraPitch = MathHelper.Clamp(cameraPitch, MathHelper.ToRadians(-89.9f), MathHelper.ToRadians(89.9f)); 
                cameraTarget += Vector3.Transform(moveVector, cameraMoveRotationMatrix); 
                 
                //Mouse.SetPosition(games.GraphicsDevice.Viewport.Width / 2, games.GraphicsDevice.Viewport.Height / 2); 
     
                 
     
                mStateCashe = mState; 
     
                base.Update(gameTime); 
            } 
        }

  • 4/16/2009 5:16 PM In reply to

    Re: Help - Third Person 3D Camera Collision

    Thanks for the help.  I definitely used a RAY extending from the camera target back in the direction of the camera location.  Works well, but without smooth transitions like you mentioned.  Still working on that.

    -Derek
Page 1 of 1 (4 posts) Previous Discussion Next Discussion