简体   繁体   中英

Black screen when trying to draw model [read edit]

I'm trying to make a world object that can use a camera and draw multiple models at once, each with their own position (and rotation, etc. in the future). Except it comes up with a black screen and I don't know why.

I've tried changing the way the matrices are created, adjusted the positions, and nothing.

World:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Xna.Framework;

using Simple3DWorld.Objects;

namespace Simple3DWorld
{
    public class World
    {
        public Camera Camera;
        public ModelObject[] Objects;

        public World()
        {
            Camera = new Camera(new Vector3(0, 0, 1), Vector3.Zero);
            Objects = new ModelObject[100];
            AddObject(new Landscape(new Vector3(0, 0, -1)));
        }

        public void AddObject(ModelObject obj)
        {
            bool added = false;

            for (int i = 0; i < Objects.Length && !added; i++)
            {
                if (Objects[i] == null)
                {
                    Objects[i] = obj;
                    added = true;
                }
            }
        }

        public void Update(GameTime gt)
        {
            for (int i = 0; i < Objects.Length; i++)
            {
                if (Objects[i] != null)
                {
                    Objects[i].Update(gt);
                }
            }
        }

        public void Draw()
        {
            for (int i = 0; i < Objects.Length; i++)
            {
                if (Objects[i] != null)
                {
                    Objects[i].Draw(Camera);
                }
            }
        }
    }
}

Camera:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

namespace Simple3DWorld
{
    public class Camera
    {
        public Vector3 Position;
        public Vector3 LookingAt;
        public float FieldOfView;
        public float AspectRatio;

        public Camera(Vector3 pos, Vector3 lookAt)
        {
            Position = pos;
            LookingAt = lookAt;
            FieldOfView = MathHelper.PiOver4;
            AspectRatio = STDW.Width / STDW.Height;
        }
    }
}

ModelObject:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

namespace Simple3DWorld
{
    public class ModelObject
    {
        public Model Model;
        public Vector3 Position;

        public ModelObject(Model model, Vector3 pos)
        {
            Model = model;
            Position = pos;
        }

        public virtual void Update(GameTime gt)
        {

        }

        public virtual void Draw(Camera camera)
        {
            foreach (ModelMesh mesh in Model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    effect.World = Matrix.CreateTranslation(Position);
                    effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);
                    effect.Projection = Matrix.CreatePerspectiveFieldOfView(camera.FieldOfView, camera.AspectRatio, 1f, 100f);
                }

                mesh.Draw();
            }
        }
    }
}

And yes, I have made sure that all methods are being called correctly. What should be showing on screen is my landscape model.

EDIT: Solved. For some stupid, frustrating reason, MonoGame will not render your models if your camera's X and Y (not the up vector) are both 0. If anyone could somehow explain this, I would be infinitely grateful.

Your Camera's Position and LookAt vectors cannot both be equal on the two axes perpendicular to the Up vector. This results in a NaN(not a number).

This situation can also be characterized as a Gimbol Lock , since the rotations about the X(Roll) and Y(Pitch) axes are aligned, making it impossible to determine the Z(Yaw) from the information provided.

The problem occurs in the creation of the View matrix in the following line:

effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);

Substituting the argument values:

effect.View = Matrix.CreateLookAt(new Vector3(0,0,1), new Vector3(0,0,0), new Vector3(0,0,1));

Annotated partial source for CreateLookAt at implementation(see here for pass the through call)

 public static void CreateLookAt(ref Vector3 cameraPosition, ref Vector3 cameraTarget, ref Vector3 cameraUpVector, out Matrix result)
 {
    var vector = Vector3.Normalize(cameraPosition - cameraTarget);

Normalize((0,0,1) - (0,0,0)) -> (x,y,z)/Length

Length = (0 - 0)² + (0 - 0)² + (0 - 1)² -> 1

(0/Length,0/Length,1/Length) -> (0/1,0/1,1/1) -> (0,0,1) *OK

    var vector2 = Vector3.Normalize(Vector3.Cross(cameraUpVector, vector));

Working inside out:

Cross((0,0,1),(0,0,1)) -> (y1 * z2 - z1 * y2, z1 * x2 - x1 *z2, x1 * y2 - y1 *x2) ->

(0 * 1 - 1 * 0, 1 * 0 - 0 * 1, 0 * 0 - 0 * 0) -> (0,0,0) *Mathematically OK, Geometrically undefined(does not define a plane perpendicular to the input points)

Normalize(Cross((0,0,1),(0,0,1))) -> Normalize(0,0,0)

Length = (0 - 0)² + (0 - 0)² + (0 - 0)² -> 0

(0/Length,0/Length,0/Length) -> (0/0,0/0,0/0) -> (NaN,NaN,NaN) *UH-OH

The NaN results from the division by zero with the 0 being unsigned as defined by IEEE 754 .

Since any operation on a NaN results in NaN . The NaN propagates to the World and Projection matrices, resulting in a black screen.

To put it another way:

If you were standing up looking ( Camera.Position = (0,0,6) ), ignoring the fact your head has to tilt to see them, at your feet( Camera.LookAt = (0,0,0) ), is it possible to determine the compass direction, where the Up vector equals Vector3.UnitZ , that you are facing? No. It is not possible, you could be facing any direction on the plane.

If I ask for the World coordinate one unit in front of your feet (1,0,0) , I can tell which direction you are facing.

Fixed. All I had to do was move my camera off of 0,0,0. 0,1,0 1,0,0 and 1,1,0 all seemed to work, which means the camera's other two coordinates (not the one that determines whether it's up or down) can't be at the origin. Not too sure why this is a thing, but at least it's fixed now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM