【问题标题】:Model moves around with camera, instead of staying still模型用相机四处移动,而不是静止不动
【发布时间】:2016-01-14 19:27:29
【问题描述】:

我正在创建一个 Monogame 第一人称射击游戏,至少在学习这样做,但我遇到了一个我似乎无法弄清楚的问题。我有一个带鼠标+键盘输入的第一人称相机,还有一个可以移动的地板,所以本质上是一个基本的“3d 世界”。

现在我想在位置 0、10、0(或其他任何地方)绘制一个球的 3D 模型,但是当我在相机周围移动时,球会保持在相机中心并与我一起移动。

有人知道这些问题吗?我有一个相机类,并试图在游戏类中绘制我的模型。我认为这与我使用多个矩阵有关吗?

相机类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Game7
{
    class Camera : GameComponent
    {
        private Vector3 cameraPosition;
        private Vector3 cameraRotation;
        private float cameraSpeed;
        private Vector3 cameraLookAt;

        private Vector3 mouseRotationBuffer;
        private MouseState currentMouseState;
        private MouseState previousMouseState;



        // Properties

        public Vector3 Position
        {
            get { return cameraPosition; }
            set
            {
                cameraPosition = value;
                UpdateLookAt();
            }
        }

        public Vector3 Rotation
        {
            get { return cameraRotation; }
            set
            {
                cameraRotation = value;
                UpdateLookAt();
            }
        }

        public Matrix Projection
        {
            get;
            protected set;
        }

        public Matrix View
        {
            get
            {
                return Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);
            }
        }

        //Constructor 
        public Camera(Game game, Vector3 position, Vector3 rotation, float speed)
            : base(game)
        {
            cameraSpeed = speed;

            // projection matrix
            Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.PiOver4, 
                Game.GraphicsDevice.Viewport.AspectRatio,
                0.05f, 
                1000.0f);

            // set camera positiona nd rotation
            MoveTo(position, rotation);

            previousMouseState = Mouse.GetState();
        }

        // set Camera's position and rotation
        private void MoveTo(Vector3 pos, Vector3 rot)
        {
            Position = pos;
            Rotation = rot;
        }

        //update the look at vector
        private void UpdateLookAt()
        {
            // build rotation matrix
            Matrix rotationMatrix = Matrix.CreateRotationX(cameraRotation.X) * Matrix.CreateRotationY(cameraRotation.Y);
            // Look at ofset, change of look at
            Vector3 lookAtOffset = Vector3.Transform(Vector3.UnitZ, rotationMatrix);
            // update our cameras look at vector
            cameraLookAt = cameraPosition + lookAtOffset;
        }

        // Simulated movement
        private Vector3 PreviewMove(Vector3 amount)
        {
            // Create rotate matrix
            Matrix rotate = Matrix.CreateRotationY(cameraRotation.Y);
            // Create a movement vector
            Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
            movement = Vector3.Transform(movement, rotate);

            return cameraPosition + movement; 

        }

        // Actually move the camera
        private void Move(Vector3 scale)
        {
            MoveTo(PreviewMove(scale), Rotation);
        }

        // updat method
        public override void Update(GameTime gameTime)
        {
            // smooth mouse?
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            currentMouseState = Mouse.GetState();

            KeyboardState ks = Keyboard.GetState();

            // input

            Vector3 moveVector = Vector3.Zero;

            if (ks.IsKeyDown(Keys.W))
                moveVector.Z = 1;
            if (ks.IsKeyDown(Keys.S))
                moveVector.Z = -1;
            if (ks.IsKeyDown(Keys.A))
                moveVector.X = 1;
            if (ks.IsKeyDown(Keys.D))
                moveVector.X = -1;

            if (moveVector != Vector3.Zero)
            {
                //normalize it
                //so that we dont move faster diagonally
                moveVector.Normalize();
                // now smooth and speed
                moveVector *= dt * cameraSpeed;
                // move camera
                Move(moveVector);
            }

            // Handle mouse input

            float deltaX;
            float deltaY;

            if(currentMouseState != previousMouseState)
            {
                //Cache mouse location
                deltaX = currentMouseState.X - (Game.GraphicsDevice.Viewport.Width / 2);
                deltaY = currentMouseState.Y - (Game.GraphicsDevice.Viewport.Height / 2);

                // smooth mouse ? rotation
                mouseRotationBuffer.X -= 0.01f * deltaX * dt;
                mouseRotationBuffer.Y -= 0.01f * deltaY * dt;

                if (mouseRotationBuffer.Y < MathHelper.ToRadians(-75.0f))
                    mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(-75.0f));
                if (mouseRotationBuffer.Y > MathHelper.ToRadians(75.0f))
                    mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(75.0f));

                Rotation = new Vector3(-MathHelper.Clamp(mouseRotationBuffer.Y, MathHelper.ToRadians(-75.0f), MathHelper.ToRadians(75.0f)), MathHelper.WrapAngle(mouseRotationBuffer.X), 0);

                deltaX = 0;
                deltaY = 0;

            }

            // Alt + F4 to close now.
            Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);

            previousMouseState = currentMouseState;

                base.Update(gameTime);
        }


    }
}

还有游戏类:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Game7
{
    /// <summary>
    /// This is the main type for your game.
    /// </summary>
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Camera camera;
        Floor floor;
        BasicEffect effect;

        Model ball;

        private Matrix world = Matrix.CreateTranslation(new Vector3(0, 10, 0));
        private Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0), Vector3.UnitY);
        private Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 480f, 0.1f, 100f);

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            camera = new Camera(this, new Vector3(10f, 1f, 5f), Vector3.Zero, 5f);
            Components.Add(camera);
            floor = new Floor(GraphicsDevice, 40, 40);
            effect = new BasicEffect(GraphicsDevice);



            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            ball = Content.Load<Model>("Ball DAE");

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// game-specific content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            floor.Draw(camera, effect);
            DrawModel(ball, world, view, projection);
            base.Draw(gameTime);
        }

        private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    //effect.World = world;
                    effect.View = view;
                    effect.Projection = projection;
                }

                mesh.Draw();
            }
        }
    }
}

感谢您的帮助。

哦,如果我取消对 effect.world = world 的注释,那么球根本不会绘制。

【问题讨论】:

    标签: c# 3d camera xna monogame


    【解决方案1】:

    ou要绘制模型,效果需要一个世界、视图和投影矩阵。你的代码表明你没有清楚地掌握什么去哪里。

    世界是一个矩阵,表示模型相对于世界的旋转和位置。该矩阵会随着模型的移动或旋转而变化。

    视图是一个矩阵,表示相机相对于世界的旋转和位置(更准确地说,是世界相对于相机的位置/旋转)。该矩阵通常归相机类所有,并且相同的视图矩阵用于绘制所有对象。

    投影矩阵表示世界的外观。有点像相机上的镜头。该矩阵通常也归相机类所有,并且使用相同的投影矩阵来绘制所有对象。

    您的游戏类具有用于绘制模型的私有世界、视图和投影矩阵。您还可以在绘制地板的相机类中创建视图和投影矩阵。您必须对地板和球使用相同的视图和投影。所以可能你应该使用相机的视图和投影来画球,就像你在地板上一样。

    effect.View = camera.View;
    effect.Projection = camera.Projection;
    

    【讨论】:

    • 这有点像我想的那样,遗憾的是它仍然没有解决问题。球现在根本不画。
    • 看来,您已注释掉的世界矩阵会将球放置在相机观察点上方 10 个单位处。它可能只是在视线之外。将世界矩阵更改为 Matrix.Identity 并查看是否有帮助。此外,您的相机类很难跟上,看起来过于复杂并且可能容易出错。这是一个简化的相机类,它提供了你所做的那种运动。 pastebin.com/sKqhtyqJ
    • 哦,天哪,太尴尬了,哈哈,它在天空中盘旋在我上方。没想到一路向上看。感谢您的时间和帮助!
    猜你喜欢
    • 2018-11-17
    • 1970-01-01
    • 2019-11-23
    • 2017-10-03
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    相关资源
    最近更新 更多