为什么被遮挡的表面会在前表面上方渲染?

问题描述 投票:0回答:1

我尝试在 monogame 框架上为我的 3d 游戏创建一些小行星,从网站下载模型并通过内容管理器将它们上传到 monogame。当我尝试将它们渲染到世界中并让它们旋转时,有时会有一些表面明显位于小行星后面,但正在渲染在上面。 bug example 小行星模型链接 链接到使用的纹理 包括使用的代码:

///////////////////////////////////////////////////////////////////
internal class Object3D
{
    protected Model model3d;

    protected Matrix position_matrix;
    protected Matrix rotation_matrix;
    protected Matrix reposition_matrix = Matrix.CreateRotationX(0f) *
                                         Matrix.CreateRotationY(0f) *
                                         Matrix.CreateRotationZ(0f);

    protected Vector3 position;
    protected Vector3 rotation;
    protected Vector3 rotation_speed = Vector3.Zero;
    protected Vector3 speed = Vector3.Zero;

    public Object3D(Vector3 start_position, Vector3 start_rotation)
    {
        setPosition(start_position);
        setRotation(start_rotation);
    }

    public Object3D(Vector3 start_position)
    {
        setPosition(start_position);
        setRotation(Vector3.Zero);
    }
    public Object3D()
    {
        setPosition(Vector3.Zero);
        setRotation(Vector3.Zero);
    }

    public void setRotation(Vector3 new_rotation)
    {
        rotation.X = new_rotation.X % 360;
        rotation.Y = new_rotation.Y % 360;
        rotation.Z = new_rotation.Z % 360;
        rotation_matrix = Matrix.CreateRotationX(MathHelper.ToRadians(new_rotation.X)) *
                          Matrix.CreateRotationY(MathHelper.ToRadians(new_rotation.Y)) *
                          Matrix.CreateRotationZ(MathHelper.ToRadians(new_rotation.Z));
    }

    public void setPosition(Vector3 new_position)
    {
        position = new_position;
        position_matrix = Matrix.CreateTranslation(new_position);
    }

    public void setSpeed(Vector3 new_speed) => speed = new_speed;

    public void setReposition(Matrix new_reposition) => reposition_matrix = new_reposition;

    public void setRotationSpeed(Vector3 new_rotation_speed) => rotation_speed = new_rotation_speed;

    public void setRotationSpeedX(float rotation_speed_x) => rotation_speed.X = rotation_speed_x % 360;

    public void setRotationSpeedY(float rotation_speed_y) => rotation_speed.Y = rotation_speed_y % 360;

    public void setRotationSpeedZ(float rotation_speed_z) => rotation_speed.Z = rotation_speed_z % 360;

    public void loadModel(ContentManager content, string name)
    {
        try
        {
            model3d = content.Load<Model>(name);
        }
        catch 
        {
            model3d = content.Load<Model>("Ship");
        }
    }

    public Matrix getRotationMatrix() => rotation_matrix;

    public Vector3 getRotation() => rotation;

    public Matrix getPositionMatrix() => position_matrix;

    public Vector3 getPosition() => position;

    public Vector3 getSpeed() => speed;

    public Vector3 getRotationSpeed() => rotation_speed;

    public Matrix getDrawMatrix(Matrix relative) => relative * reposition_matrix * rotation_matrix * position_matrix;

    public Model getModel() => model3d;

    public void move()
    {
        setPosition(position + speed);
        setRotation(rotation + rotation_speed);
    }

    public virtual void Update() { }
}
///////////////////////////////////////////////////////////////////
internal class Asteroid : Object3D
{
    public Asteroid() : base() { }

    public Asteroid(Vector3 start_position) : base(start_position) { }

    public override void Update()
    {
        move();
    }
}
///////////////////////////////////////////////////////////////////
internal class Camera
{
    private Matrix view;
    private Matrix projection;

    private Vector3 position;
    private Vector3 abs_position;
    private Vector3 target_position;
    private Vector3 up_vector;

    public Camera(Vector3 start_position, Vector3 start_target_position, GraphicsDeviceManager _graphics)
    {
        position = start_position;
        target_position = start_target_position;
        up_vector = Vector3.Up;
        view = Matrix.CreateLookAt(position, target_position, up_vector);
        projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
                                                        _graphics.PreferredBackBufferWidth / _graphics.PreferredBackBufferHeight,
                                                        0.1f,
                                                        200f);
        abs_position = position;
    }

    public Camera(Vector3 start_position, GraphicsDeviceManager _graphics)
    {
        position = start_position;
        target_position = Vector3.Zero;
        up_vector = Vector3.Up;
        view = Matrix.CreateLookAt(position, target_position, up_vector);
        projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
                                                        _graphics.PreferredBackBufferWidth / _graphics.PreferredBackBufferHeight,
                                                        0.1f,
                                                        200f);
        abs_position = position;
    }

    public Camera(GraphicsDeviceManager _graphics)
    {
        position = Vector3.Zero;
        target_position = Vector3.Zero;
        up_vector = Vector3.Up;
        view = Matrix.CreateLookAt(position, target_position, up_vector);
        projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
                                                        _graphics.PreferredBackBufferWidth / _graphics.PreferredBackBufferHeight,
                                                        0.1f,
                                                        200f);
        abs_position = position;
    }

    public void updateView() => view = Matrix.CreateLookAt(position, target_position, up_vector);

    public void setPosition(Vector3 new_position)
    {
        position = new_position;
        updateView();
    }

    public void setTargetPosition(Vector3 new_target_position)
    {
        target_position = new_target_position;
        updateView();
    }

    public void setUpVector(Vector3 new_up_vector)
    {
        up_vector = new_up_vector;
        updateView();
    }

    public Vector3 getPosition() => position;

    public Vector3 getAbsPosition() => abs_position;

    public Vector3 getTargetPosition() => target_position;

    public Matrix getView() => view;

    public Matrix getProjection() => projection;
}
///////////////////////////////////////////////////////////////////
public class Game1 : Game
{
    Matrix world;
    
    Ship ship;
    Camera camera;

    Asteroid[] asteroids;

    SpriteFont font;

    VertexBuffer vertexBuffer;
    VertexPositionColor[] vertices;
    BasicEffect effectLine;

    private GraphicsDeviceManager _graphics;
    private SpriteBatch _spriteBatch;

    public Game1()
    {
        _graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        IsMouseVisible = true;
    }

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        ship = new Ship();
        camera = new Camera(new Vector3(0f, 10f, 10f), ship.getPosition(), _graphics);
        world = Matrix.CreateWorld(Vector3.Zero, Vector3.Forward, Vector3.Up);

        vertices = new VertexPositionColor[8];
        vertices[0] = new VertexPositionColor(Vector3.Zero, Color.Yellow);
        vertices[1] = new VertexPositionColor(ship.getSpeed() * 5, Color.Yellow);

        vertices[2] = new VertexPositionColor(Vector3.Zero, Color.Red);
        vertices[3] = new VertexPositionColor(Vector3.UnitX * 10, Color.Red);

        vertices[4] = new VertexPositionColor(Vector3.Zero, Color.Green);
        vertices[5] = new VertexPositionColor(Vector3.UnitY * 10, Color.Green);

        vertices[6] = new VertexPositionColor(Vector3.Zero, Color.Purple);
        vertices[7] = new VertexPositionColor(Vector3.UnitZ * 10, Color.Purple);

        vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.None);
        vertexBuffer.SetData(vertices);

        effectLine = new BasicEffect(GraphicsDevice);
        effectLine.VertexColorEnabled = true;

        asteroids = new Asteroid[8];

        var distance = 100f;

        asteroids[0] = new Asteroid(new Vector3(distance, distance, distance));
        asteroids[1] = new Asteroid(new Vector3(distance, distance, -distance));
        asteroids[2] = new Asteroid(new Vector3(-distance, distance, -distance));
        asteroids[3] = new Asteroid(new Vector3(-distance, distance, distance));

        asteroids[4] = new Asteroid(new Vector3(distance, -distance, distance));
        asteroids[5] = new Asteroid(new Vector3(distance, -distance, -distance));
        asteroids[6] = new Asteroid(new Vector3(-distance, -distance, -distance));
        asteroids[7] = new Asteroid(new Vector3(-distance, -distance, distance));

        base.Initialize();
    }

    protected override void LoadContent()
    {
        _spriteBatch = new SpriteBatch(GraphicsDevice);

        ship.loadModel(Content, "Ship");
        ship.setReposition(Matrix.CreateRotationX(MathHelper.ToRadians(-90f)) * Matrix.CreateRotationY(MathHelper.ToRadians(180f)));
        font = Content.Load<SpriteFont>("File");

        for(int i = 0; i < asteroids.Length / 2; i++)
        {
            asteroids[i].loadModel(Content, "Asteroid1"); //Change to asteroid model
        }

        for (int i = asteroids.Length / 2; i < asteroids.Length; i++)
        {
            asteroids[i].loadModel(Content, "Asteroid1"); //Change to asteroid model
        }

        var rand = new Random();
        foreach (Asteroid asteroid in asteroids) 
            asteroid.setRotationSpeed(new Vector3((float)rand.NextDouble() * 3, (float)rand.NextDouble() * 3, (float)rand.NextDouble() * 3));
        // TODO: use this.Content to load your game content here

    }

    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

        ship.Update();

        if (Keyboard.GetState().IsKeyUp(Keys.P))
        {
            foreach (Asteroid asteroid in asteroids)
                asteroid.Update();
        }
        
        camera.setTargetPosition(ship.getPosition());
        camera.setUpVector(Vector3.Transform(Vector3.Up, ship.getRotationMatrix()));
        camera.setPosition(Vector3.Transform(camera.getAbsPosition(), ship.getRotationMatrix() * ship.getPositionMatrix()));

        vertices[1].Position = ship.getSpeed() * 5;

        vertexBuffer.SetData(vertices);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Blue);
        // TODO: Add your drawing code here
        _spriteBatch.Begin();
        _spriteBatch.DrawString(font, $"Velocity( X:{ship.getSpeed().X} Y:{ship.getSpeed().Y} Z:{ship.getSpeed().Z} )", new Vector2(10, 10), Color.Black);
        _spriteBatch.DrawString(font, $"Position( X:{ship.getPosition().X} Y:{ship.getPosition().Y} Z:{ship.getPosition().Z} )", new Vector2(10, 100), Color.Black);
        _spriteBatch.End();

        foreach (Asteroid asteroid in asteroids)
        {
            foreach (ModelMesh mesh in asteroid.getModel().Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = asteroid.getDrawMatrix(world);
                    effect.View = camera.getView();
                    effect.Projection = camera.getProjection();
                }
                mesh.Draw();
            }
        }

        foreach (ModelMesh mesh in ship.getModel().Meshes)
        {
            foreach(BasicEffect effect in mesh.Effects)
            {
                effect.World = ship.getDrawMatrix(world);
                effect.View = camera.getView();
                effect.Projection = camera.getProjection();
            }
            mesh.Draw();
        }

        effectLine.World = world * ship.getPositionMatrix();
        effectLine.View = camera.getView();
        effectLine.Projection = camera.getProjection();

        GraphicsDevice.SetVertexBuffer(vertexBuffer);
        foreach (EffectPass pass in effectLine.CurrentTechnique.Passes)
        {
            pass.Apply();

            GraphicsDevice.DrawUserPrimitives<VertexPositionColor>
                (PrimitiveType.LineList, vertices, 0, 4);
        }

        base.Draw(gameTime);
    }
}

我为小行星模型使用了不同的纹理。我将模型导入到搅拌机中,并将使用的纹理设置为它,然后将纹理大小设置为 1024x1024。 我不知道这是我的模型的问题还是单游戏的内部工作和 3D 模型渲染的问题。如果有人能在这种情况下提供建议,我将不胜感激。在我的程序中,我一直使用 .fbx 模型。我已经尝试了几种 .fbx 模型,但都没有达到一定程度,它们都有同样的问题。

graphics 3d rendering monogame surface
1个回答
0
投票

这看起来很像渲染网格时没有进行深度测试。在“_spriteBatch.End();”之后尝试一下:

    Device.DepthStencilState = new() {
        DepthBufferEnable = true,
        DepthBufferWriteEnable = true,
        DepthBufferFunction = CompareFunction.LessEqual
    };

如果您使用自定义着色器(效果),您还可以使用以下内容:

pass P0 {
    ZFunc = LESSEQUAL;
    ZWriteEnable = true;
    ...
    ...
}

让我知道这是否有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.