I am probably going to smack myself in the face once the answer becomes clear, but I'm afraid I can't figure out what to do with my camera in order to effectively mix scrolling 2D and 3D objects.
Currently I'm using a displacement camera, which I implemented when this was still just a 2D project. The camera displaces the draw position of all 2D objects based on where its position is in the world. In case that's not clear, here's the code:
public void DrawSprite(Sprite sprite)
{
Vector2 drawtopLeftPosition = ApplyTransformation(sprite.Position);
//TODO: add culling logic here
sprite.Draw(spriteBatch, drawtopLeftPosition);
}
private Vector2 ApplyTransformation(Vector2 spritetopLeftPosition)
{
return (spritetopLeftPosition - topLeftPosition);
}
Simple enough. This worked effectively until I tried to push 3D into the equation. I have several spheres which I want to display alongside the 2D game objects. I have already figured out how to Z-order everything properly, but I cannot get the spheres to project correctly. They appear and disappear depending on where the camera is and often fly around erratically with even the slightest camera movement. Here are my camera matrices:
viewMatrix = Matrix.CreateLookAt(new Vector3(Position, 1f), new Vector3(Position , 0), Vector3.Up);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, graphics.Viewport.AspectRatio, 1f, 1000f);
Note that the Vector2 Position is the absolute center of the camera viewport, not the top left or anything like that. I have also tried using OrthographicOffCenter and Orthographic projections. The viewMatrix updates each frame with the same CreateLookAt function based on the current camera position. Here is the Camera method which draws a 3D object:
public void DrawModel(Sprite3D sprite, GraphicsDevice device)
{
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
device.SamplerStates[0] = SamplerState.LinearWrap;
sprite.DrawBasic(this, device);
}
My main point of confusion is whether I should displace the 3D objects as well as the 2D. I have tried doing this but have had more success actually glimpsing the 3D objects on screen if I do not.
Here is the Sprite3D section for drawing:
public Matrix GenerateWorld()
{
return Matrix.CreateScale(Scale) * Matrix.CreateTranslation(new Vector3(Position, -ZPosition)) * Matrix.CreateFromYawPitchRoll(Rotation3D.X, Rotation3D.Y, Rotation3D.Z);
}
private Matrix GenerateDEBUGWorld()
{
return Matrix.CreateScale(Scale) * Matrix.CreateTranslation(Vector3.Zero);
}
public void DrawBasic(Camera camera, GraphicsDevice device)
{
Matrix[] transforms = new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in Model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = (transforms[mesh.ParentBone.Index] * GenerateDEBUGWorld());
effect.View = camera.ViewMatrix;
effect.Projection = camera.ProjectionMatrix;
}
mesh.Draw();
}
}
GenerateDEBUGWorld simply places the sphere at 0,0 so that I always know where it should be.
A few things I've noticed:
- If I set the Z position of the camera to a larger number (say, 10), spheres move less erratically but still wrongly
- Using OrthographicOffCenter projection displays tiny little spheres at the center of the screen which do not change in position or scale, even if I multiply the Sprite3D's Scale variable by 1000.
So, the main question: should I even use a displacement camera, or is ther开发者_运维百科e a better way to mix 2D and 3D effectively (billboarding, perhaps? but I don't want to add unnecessary complexity to this project)? And, if I do use displacement, should I displace the 3D objects as well as the 2D? Finally, what sort of projection should be used?
Update: If I move the camera back to z position of 100 and make the spheres scale up by 100%, they behave somewhat normally-- when the camera moves left they move right, up they move down, etc, as you'd expect for a perspective projection. However they move far too much in relation to the rest of the 2D objects. Is this a matter of scale? I feel like it's very difficult to reconcile the way sprites are shown and the way 3D objects are shown onscreen...
It sounds like what you're looking for is Unproject - this will take a 2D point and "cast it" into 3D space. If all of your objects are in 3D space, your typical Ortho/LookAt camera should work as you'd expect...I'm also going completely from memory here, since I can't be arsed to look it up. ;)
Just a thought, but your Z in your view matrix is being constrained between 1 and 0. Update the Z component of those Vector3's to be the actual Z of the camera and see what that does for you.
<2 cents/>
精彩评论