【发布时间】:2011-06-29 13:22:50
【问题描述】:
我正在尝试包括对围绕视口中心缩放和旋转我的相机类的支持。
在我的应用程序中,在输入 SpriteBatch.Begin 代码之前,我已经根据相机的位置手动定位了精灵(以便更容易实现剔除)。虽然每个精灵都是手动定位的,但我不想单独旋转和缩放每个精灵。
因此,我尝试在 SpriteBatch.Begin 方法中使用 matrixTransform 参数。
下面是我为说明问题而制作的硬编码应用程序(使用 Car.png 内容图像)。旋转没有我预期的那么快(每帧旋转 10 度?),它围绕左上角旋转/缩放。我希望它围绕屏幕中心旋转,这将始终保持中间汽车在中心,并从该点开始缩放。
我尝试了几种创建矩阵平移的组合,重新排序/添加/乘/平移视口的中途距离,但我不太了解矩阵是如何工作的。我还在几个网站上尝试了解决方案,但我无法为我工作。
谁能告诉我我必须创建的矩阵翻译,或者指出您认为适合我的设置的网站的方向?
Windows XNA 应用程序演示问题:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace RenderTest
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D _carTexture;
float _zoom = 1.0f;
float _rotationInDegrees = 0.0f;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
_carTexture = Content.Load<Texture2D>("Car");
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up)) // Zoom in key
_zoom *= 1.1f;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down)) // Zoom out key
_zoom /= 1.1f;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left)) // Rotate anticlockwise key
_rotationInDegrees -= 10;
if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right)) // Rotate clockwise key
_rotationInDegrees += 10;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullNone, null, GetMatrix(GraphicsDevice));
spriteBatch.Draw(_carTexture, new Rectangle(0, 0, 50, 50), Color.White);//Square car placed top left
spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 - 25, GraphicsDevice.Viewport.Height / 2 - 50, 50, 100), Color.Green);//Car placed centre
spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 + 100, GraphicsDevice.Viewport.Height / 2 + 100, 50, 50), Color.Black);//Off centre but always within screen
spriteBatch.End();
base.Draw(gameTime);
}
Matrix GetMatrix(GraphicsDevice graphicsDevice)
{
Matrix translationMatrix = Matrix.CreateTranslation(0, 0, 0);
Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(MathHelper.ToRadians(_rotationInDegrees)));
Matrix zoomMatrix = Matrix.CreateScale(_zoom);
Matrix compositeMatrix = translationMatrix * rotationMatrix * zoomMatrix;
return compositeMatrix;
}
}
}
谢谢,
李
解决方案
Matrix GetMatrix(GraphicsDevice graphicsDevice)
{
Matrix translateToOrigin = Matrix.CreateTranslation(-graphicsDevice.Viewport.Width / 2, -graphicsDevice.Viewport.Height / 2, 0);
Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(_rotationInDegrees));
Matrix zoomMatrix = Matrix.CreateScale(_zoom);
Matrix translateBackToPosition = Matrix.CreateTranslation(graphicsDevice.Viewport.Width / 2, graphicsDevice.Viewport.Height / 2, 0);
Matrix compositeMatrix = translateToOrigin * rotationMatrix * zoomMatrix * translateBackToPosition;
return compositeMatrix;
}
【问题讨论】:
-
值得指出的是,对于
SpriteBatch,剔除很少是值得优化的,即使是这样,您通常也不必太准确(您可以忽略旋转并简单地绘制面积更大)。 (See this answer.)