我尝试在 monogame 框架上为我的 3d 游戏创建一些小行星,从网站下载模型并通过内容管理器将它们上传到 monogame。当我尝试将它们渲染到世界中并让它们旋转时,有时会有一些表面明显位于小行星后面,但正在渲染在上面。 小行星模型链接 链接到使用的纹理 包括使用的代码:
///////////////////////////////////////////////////////////////////
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 模型,但都没有达到一定程度,它们都有同样的问题。
这看起来很像渲染网格时没有进行深度测试。在“_spriteBatch.End();”之后尝试一下:
Device.DepthStencilState = new() {
DepthBufferEnable = true,
DepthBufferWriteEnable = true,
DepthBufferFunction = CompareFunction.LessEqual
};
如果您使用自定义着色器(效果),您还可以使用以下内容:
pass P0 {
ZFunc = LESSEQUAL;
ZWriteEnable = true;
...
...
}
让我知道这是否有帮助!