我正在查看 Shawn Hargreave 的关于广告牌 2D 精灵的旧 xna 教程,在最后一个示例中,他展示了如何使用 spritebatch 在单个 SpriteBatch.Begin 和 End 中绘制所有广告牌精灵。
然而,他提出的方法会导致广告牌精灵面对相机,无论相机在哪里。例如,如果相机位于精灵的正上方,则精灵看起来就像仰卧着一样。这也是角度较小的问题,可能导致精灵夹入 3D 对象。
以下是博客中的相关代码:
`矩阵 invertY = Matrix.CreateScale(1, -1, 1);
basicEffect.World = invertY;
basicEffect.View = Matrix.Identity;
basicEffect.Projection = projection;
spriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, basicEffect);
for each billboard sprite
{
Vector3 textPosition = new Vector3(0, 45, 0);
Vector3 viewSpaceTextPosition = Vector3.Transform(textPosition, view * invertY);
const string message = "hello, world!";
Vector2 textOrigin = spriteFont.MeasureString(message) / 2;
const float textSize = 0.25f;
spriteBatch.DrawString(spriteFont, message, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), Color.White, 0, textOrigin, textSize, 0, viewSpaceTextPosition.Z);
}
spriteBatch.End(); `
它是轻微的伪代码,但我认为这可能只是他的一个拼写错误。请注意,他不需要多次更改基本效果。
我不是矩阵数学方面的专家,我希望有某种简单的解决方案来强制精灵仅绕其 Y(向上)轴旋转(删除间距)。
我可以使用自定义着色器获得所需的效果,但这排除了 spritebatch 及其内置的良好排序系统。
如果您将相机(视图)角度控制为欧拉角(例如围绕 X 轴的 XRot 和围绕 Y 轴的 YRot,例如圆顶式相机),您可以执行类似的操作(假设您的 XRot 和 YRot 角度以度为单位) ):
...
var invertY = Matrix.CreateScale(1, -1, 1);
var invertXAngle = Matrix.CreateFromAxisAngle(new(1, 0, 0), (-XRot + 90) * MathF.PI / 180f);
var world = invertY * invertXAngle;
basicEffect.World = world;
basicEffect.View = Matrix.Identity;
basicEffect.Projection = Projection;
...
这个:
...
Vector3 viewSpaceTextPosition = Vector3.Transform(textPosition, View * invertY)
...
...然后变成:
...
Vector3 viewSpaceTextPosition = Vector3.Transform(textPosition, View * world);
...
这会在精灵局部基础上从相机视图矩阵中“删除”X 旋转。根据您对相机旋转的解释,(-XRot + 90) 也可以是 (-XRot - 90)。
为了提高速度,您还可以缓存“View * world”,因为它不会针对每个精灵而改变。让我知道这是否有帮助。