尝试绘制模型时出现黑屏 [阅读编辑]
Black screen when trying to draw model [read edit]
我正在尝试制作一个可以使用相机并一次绘制多个模型的世界对象,每个模型都有自己的位置(以及将来的旋转等)。除了它出现黑屏,我不知道为什么。
我试过改变矩阵的创建方式,调整位置,但什么都没有。
世界:
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);
}
}
}
}
}
相机:
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;
}
}
}
模型对象:
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();
}
}
}
}
是的,我已确保正确调用了所有方法。屏幕上应该显示的是我的风景模型。
编辑:已解决。出于一些愚蠢、令人沮丧的原因,如果您的相机的 X 和 Y(不是向上矢量)均为 0,MonoGame 将不会渲染您的模型。如果有人能以某种方式解释这一点,我将不胜感激。
已修复。我所要做的就是将我的相机从 0,0,0 移开。 0,1,0 1,0,0 和 1,1,0 似乎都有效,这意味着相机的其他两个坐标(不是确定它是向上还是向下的坐标)不能在原点。不太清楚为什么会这样,但至少现在已经修复了。
您相机的 Position
和 LookAt
向量不能在垂直于 Up
向量的两个轴上都相等。这导致 NaN(不是数字)。
这种情况也可以描述为Gimbol Lock,因为围绕X(Roll)
和Y(Pitch)
轴的旋转是对齐的,因此无法确定Z(Yaw)
根据提供的信息。
在以下行中创建 View
矩阵时出现问题:
effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);
替换参数值:
effect.View = Matrix.CreateLookAt(new Vector3(0,0,1), new Vector3(0,0,0), new Vector3(0,0,1));
CreateLookAt at implementation(see here 的注释部分源代码用于传递直通调用)
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)
*确定
var vector2 = Vector3.Normalize(Vector3.Cross(cameraUpVector, vector));
由内而外工作:
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)
*数学上可以,几何上未定义(未定义垂直于输入点的平面)
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
NaN
是除以零的结果,其中 0 是无符号的,如 IEEE 754 所定义。
因为对 NaN
的任何操作都会导致 NaN
。 NaN
传播到 World
和 Projection
矩阵,导致黑屏。
换句话说:
如果你站着看(Camera.Position
=(0,0,6)
),忽略你的头必须倾斜才能看到它们的事实,在你的脚下(Camera.LookAt
=(0,0,0)
), 是否可以确定您所面对的 Up
矢量等于 Vector3.UnitZ
的罗盘方向?不,这不可能,你在飞机上可能面向任何方向。
如果我要求你脚前一个单位的世界坐标(1,0,0)
,我就能知道你面向哪个方向。
我正在尝试制作一个可以使用相机并一次绘制多个模型的世界对象,每个模型都有自己的位置(以及将来的旋转等)。除了它出现黑屏,我不知道为什么。
我试过改变矩阵的创建方式,调整位置,但什么都没有。
世界:
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);
}
}
}
}
}
相机:
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;
}
}
}
模型对象:
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();
}
}
}
}
是的,我已确保正确调用了所有方法。屏幕上应该显示的是我的风景模型。
编辑:已解决。出于一些愚蠢、令人沮丧的原因,如果您的相机的 X 和 Y(不是向上矢量)均为 0,MonoGame 将不会渲染您的模型。如果有人能以某种方式解释这一点,我将不胜感激。
已修复。我所要做的就是将我的相机从 0,0,0 移开。 0,1,0 1,0,0 和 1,1,0 似乎都有效,这意味着相机的其他两个坐标(不是确定它是向上还是向下的坐标)不能在原点。不太清楚为什么会这样,但至少现在已经修复了。
您相机的 Position
和 LookAt
向量不能在垂直于 Up
向量的两个轴上都相等。这导致 NaN(不是数字)。
这种情况也可以描述为Gimbol Lock,因为围绕X(Roll)
和Y(Pitch)
轴的旋转是对齐的,因此无法确定Z(Yaw)
根据提供的信息。
在以下行中创建 View
矩阵时出现问题:
effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);
替换参数值:
effect.View = Matrix.CreateLookAt(new Vector3(0,0,1), new Vector3(0,0,0), new Vector3(0,0,1));
CreateLookAt at implementation(see here 的注释部分源代码用于传递直通调用)
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)
*确定
var vector2 = Vector3.Normalize(Vector3.Cross(cameraUpVector, vector));
由内而外工作:
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)
*数学上可以,几何上未定义(未定义垂直于输入点的平面)
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
NaN
是除以零的结果,其中 0 是无符号的,如 IEEE 754 所定义。
因为对 NaN
的任何操作都会导致 NaN
。 NaN
传播到 World
和 Projection
矩阵,导致黑屏。
换句话说:
如果你站着看(Camera.Position
=(0,0,6)
),忽略你的头必须倾斜才能看到它们的事实,在你的脚下(Camera.LookAt
=(0,0,0)
), 是否可以确定您所面对的 Up
矢量等于 Vector3.UnitZ
的罗盘方向?不,这不可能,你在飞机上可能面向任何方向。
如果我要求你脚前一个单位的世界坐标(1,0,0)
,我就能知道你面向哪个方向。