Answers:
渲染线-方法1(原语)
对于3D空间中的简单线条,您可以使用LineList
或LineStrip
图元进行绘制。这是添加到空XNA项目中才能使它从(0,0,0)到(0,0,-50)的线的最少代码量。无论相机位于何处,该线的宽度应看起来大致相同。
// Inside your Game class
private BasicEffect basicEffect;
private Vector3 startPoint = new Vector3(0, 0, 0);
private Vector3 endPoint = new Vector3(0, 0, -50);
// Inside your Game.LoadContent method
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.View = Matrix.CreateLookAt(new Vector3(50, 50, 50), new Vector3(0, 0, 0), Vector3.Up);
basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f), GraphicsDevice.Viewport.AspectRatio, 1f, 1000f);
// Inside your Game.Draw method
basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new[] { new VertexPositionColor(startPoint, Color.White), new VertexPositionColor(endPoint, Color.White) };
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vertices, 0, 1);
我基本上创建了一个简单的BasicEffect
视图和投影转换,并将两个顶点(存储位置和颜色)传递给该GraphicsDevice.DrawUserPrimitives
方法以将其渲染为LineList
。
当然,有很多方法可以对其进行优化,其中大多数方法涉及创建一个VertexBuffer
存储所有顶点的方法,以及将尽可能多的线批处理到一个Draw调用中,但这与问题无关。
渲染点-方法1(SpriteBatch)
至于绘制点,以前使用点精灵很容易,但是它们已从XNA 4.0中删除。虽然有一些替代方法。最简单的方法是创建一个1x1白色Texture2D
对象,并SpriteBatch
在正确的屏幕位置使用渲染,您可以使用Viewport.Project方法轻松找到它。
您可以这样创建所需的Texture2D
对象:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
并在位置(x,y,z)处进行渲染,如下所示:
// Find screen equivalent of 3D location in world
Vector3 worldLocation = new Vector3(0, 0, 50);
Vector3 screenLocation = GraphicsDevice.Viewport.Project(worldLocation, projectionMatrix, viewMatrix, Matrix.Identity);
// Draw our pixel texture there
spriteBatch.Begin();
spriteBatch.Draw(pixel, new Vector2(screenLocation.X, screenLocation.Y), Color.White);
spriteBatch.End();
渲染线-方法2(SpriteBatch)
另外,您也可以SpriteBatch
使用此处描述的技术使用画线。在这种情况下,您只需要找到3D线两端的屏幕空间坐标(再次使用Viewport.Project
),然后在它们之间绘制一条规则线即可。
渲染点-方法2(带有基元的小线)
在评论中,电子商务提出了以下问题:
起点和终点相同的线会不会产生一个点呢?还是仅仅是看不见?
我尝试了一下,并LineList
使用相同的起点和终点进行渲染,结果什么也没画。不过,我找到了解决方法,因此在这里我将对其进行完整描述。
诀窍不是使用相同的起点和终点,而是绘制一条很小的线,以使其在绘制时仅显示为一个像素。因此,为了选择正确的端点,我首先将世界空间点投影到屏幕空间中,将其在屏幕空间中向右移动一个像素,最后将其投影回到世界空间中。那是您的线条的终点,以使其看起来像点。像这样:
Vector3 GetEndPointForDot(Vector3 start)
{
// Convert start point to screen space
Vector3 screenPoint = GraphicsDevice.Viewport.Project(start, projection, view, Matrix.Identity);
// Screen space is defined in pixels so adding (1,0,0) moves it right one pixel
screenPoint += Vector3.Right;
// Finally unproject it back into world space
return GraphicsDevice.Viewport.Unproject(screenPoint, projection, view, Matrix.Identity);
}
随后将其渲染为普通线图元。
示范
这就是我使用线列表图元在3D空间中绘制白线,并使用1x1纹理和SpriteBatch在线的两端绘制红点的方法。所使用的代码几乎是我上面编写的代码。我也放大了,因此您可以确认它们恰好是一个像素宽:
这被标记为XNA,所以我假设这就是您要问的?
如果是这样,那么本文对以下几行应该有所帮助:
http://msdn.microsoft.com/zh-CN/library/bb196414(v=xnagamestudio.40).aspx
当然,您可以使用自己的视图/投影矩阵来代替它们。基本上PrimitiveType.LineList
还是LineStrip
在GPU级别上画线。
至于点,您不再可以在XNA 4.0中使用PrimitiveType.PointList绘制点。相反,您必须制作非常小的三角形。该示例提供了一个良好的基准:
http://create.msdn.com/education/catalog/sample/primitives_3d
对于早期版本的XNA,如果您使用的是其中一种,则可以继续阅读上述文章的XNA 3.0版本的Point部分:
http://msdn.microsoft.com/zh-CN/library/bb196414(v=xnagamestudio.30).aspx
请注意,该链接具有:
graphics.GraphicsDevice.RenderState.PointSize = 10;
显然将其更改为1
。