我如何绘制多条通过SlimDX通过“节点”连接的线路?

我目前用以下scheme读出XML数据:位置x,y,z

我尝试为每个位置节点添加一个新的顶点并将其添加到顶点数组。

然后我尝试渲染这个顶点列表,这样我就可以将所有这些连线代表一个空间的“path”。 (空间是3D)

我到目前为止所尝试的是:

[STAThread] static void Main() { var form = new RenderForm("SlimDX - MiniTri Direct3D9 Sample"); var device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle, CreateFlags.HardwareVertexProcessing, new PresentParameters() { BackBufferWidth = form.ClientSize.Width, BackBufferHeight = form.ClientSize.Height }); form.Height = 900; form.Width = 900; LineVertex[] waypoints = new LineVertex[1024]; XmlDocument paths = new XmlDocument(); paths.Load("data.xml"); XmlNode rootNode = paths.DocumentElement; int index = 0; foreach (XmlNode waypoint in rootNode) { foreach (XmlNode position in waypoint) { Console.WriteLine(position.ChildNodes[0].InnerText); float b = 1000.0f; float x, y, z; x = (float.Parse(position.ChildNodes[0].InnerText) / (b * b)); y = (float.Parse(position.ChildNodes[1].InnerText) / (b * b); z = (float.Parse(position.ChildNodes[2].InnerText) / (b * b)); Console.WriteLine(x.ToString() + " / " + y.ToString() + " / " + z.ToString()); if (index % 2 > 0) waypoints[index].Color = Color.Yellow.ToArgb(); else waypoints[index].Color = Color.Red.ToArgb(); waypoints[index].Position = new Vector3(x, y, 0.0f); } } MessagePump.Run(form, () => { device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue.ToArgb(), 0f, 1); // Since we don't have any lights in our scene, our lines won't receive // any light and will therefore be black... // ...but we want them golden as an asinus aureus, so let's disable lighting. device.SetRenderState(RenderState.Lighting, true); device.BeginScene(); // Our struct was meant to describe a position and a color, // let's tell the device about it. device.VertexFormat = VertexFormat.Position | VertexFormat.Diffuse; // In this particular case SlimDX does not need the // vertex stride, it will be automatically calculated. device.DrawUserPrimitives(PrimitiveType.LineList, 0, waypoints.Length / 2, waypoints); device.EndScene(); device.Present(); }); foreach (var item in ObjectTable.Objects) item.Dispose(); } } 

但这不行,我相信这是完全错误的做法!

编辑:到目前为止一个解决scheme解决,但不是很好。 而且我还需要在运行时更改顶点,所以我locking了文档和示例,它们始终使用VertexBuffer(),以便使用DataStream作为VertexBuffer的input来dynamic更改顶点。

我仍然面临的一个问题是,由于我习惯于“更新(时间)”格式,DX / OpenGL的程序仍然让我困惑。 所以我假设MessagePump.Run()代表每帧重复的绘图调用。 因此,如果绘图调用之前的某些值像Vertex一样更改,将其放入数据stream中,则可以立即在屏幕上看到更新后的结果。 这个假设是对的吗?

从SlimDX开始,我已经有一段时间了,所以我想画一些线来记住它的感觉:)好吧,它看起来像是我们需要的几条彩色线条,所以我们把顶点排列成一个列表,描述它的顺序和绘制它:

 // Simple vertex with position and color. public struct LineVertex { public Vector3 Position; public int Color; } /* ...typical device initialization skipped here... */ var lines = new LineVertex[100]; var random = new Random(); // Prepare line vertices. // You will fill this array from XML instead of random generator. // LineList will be used as a 3D primitive, so a line will be drawn // between each pair of vertices, total of 50 lines in our case. for (int i = 0; i < lines .Length; i++) { lines[i] = new LineVertex(); float x = (float)(random.NextDouble() * 2) - 1; float y = (float)(random.NextDouble() * 2) - 1; lines[i].Position = new Vector3(x, y, 0f); lines[i].Color = Color.Gold.ToArgb(); } MessagePump.Run(form, () => { device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue.ToArgb(), 0f, 1); // Since we don't have any lights in our scene, our lines won't receive // any light and will therefore be black... // ...but we want them golden as an asinus aureus, so let's disable lighting. device.SetRenderState(RenderState.Lighting, false); device.BeginScene(); // Our struct was meant to describe a position and a color, // let's tell the device about it. device.VertexFormat = VertexFormat.Position | VertexFormat.Diffuse; // In this particular case SlimDX does not need the // vertex stride, it will be automatically calculated. device.DrawUserPrimitives(PrimitiveType.LineList, 0, lines.Length / 2, lines); device.EndScene(); device.Present(); }); 

你可能会注意到这些线条看起来不太漂亮。 在你的开发周期的后期,你可能会想用自定义纹理的三角形来代替它们。 在这一点上,查看关于DirectX的一些不错的书可能会比较容易,而不是自己去争取。

编辑:你想顶点缓冲区和互连线? 实际上,记住这些东西是如何工作的,这将是一个很好的练习,所以让我们尝试一下:

 /* skipped device initialization */ var rnd = new Random(); // The maximum number of vertices we will ever have in a buffer, // basically a buffer size limit. const int maxVertexCount = 1024; int lineVertexSize = Marshal.SizeOf(typeof(LineVertex)); // Create buffers once. // You may notice Dynamic flag. This usage flag causes Direct3D to optimize for frequent lock operations. // It's only useful when the buffer is locked frequently, // otherwise a static vertex or index buffer should be used. var vertexBuffer = new VertexBuffer(device, maxVertexCount * lineVertexSize, Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default); // Why such number of max indices? Read further :) var indexBuffer = new IndexBuffer(device, sizeof(int) * maxVertexCount * 2 - 2, Usage.WriteOnly | Usage.Dynamic, Pool.Default, false); MessagePump.Run(form, () => { device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue.ToArgb(), 0f, 1); device.SetRenderState(RenderState.Lighting, false); device.BeginScene(); device.VertexFormat = VertexFormat.Position | VertexFormat.Diffuse; // Simulate variable vertex count. int vertexCount = rnd.Next(1, 51) * 2; // Create a new vertex data each frame and setup vertices by changing their properties randomly. var vertexData = new LineVertex[vertexCount]; for (int i = 0; i < vertexData.Length; i++) { float x = (float)(rnd.NextDouble() * 2) - 1; float y = (float)(rnd.NextDouble() * 2) - 1; vertexData[i].Position = new Vector3(x, y, 0f); vertexData[i].Color = (rnd.Next(2) == 0) ? Color.Gold.ToArgb() : Color.GreenYellow.ToArgb(); } // Setup indices each frame in a special interconnected way: // the end point of the first line is the start point of the second line. var indices = new int[(vertexCount * 2) - 2]; for (int i = 0; i < vertexCount - 1; i++) { indices[i * 2] = i; indices[(i * 2) + 1] = i + 1; } // Write generated vertices to the vertex buffer. // Lets receive a free performance improvement and use a // Discard flag since we aren't using old buffer data. // This flag tells Direct3D not to need to keep the old vertex or // index data in the buffer. var vertexStream = vertexBuffer.Lock(0, 0, LockFlags.Discard); vertexStream.WriteRange(vertexData); vertexBuffer.Unlock(); // Write generated indices to the index buffer. var indexStream = indexBuffer.Lock(0, 0, LockFlags.Discard); indexStream.WriteRange(indices); indexBuffer.Unlock(); device.SetStreamSource(0, vertexBuffer, 0, lineVertexSize); device.Indices = indexBuffer; device.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, vertexCount, 0, indices.Length / 2); device.EndScene(); device.Present(); }); 

有几件事你不应该做。 你也似乎有一个types在你调用WriteRange的行上或附近,因为在代码中有一个错误}将使其不可编译。 与调用DrawIndexedPrimitives – 这使得很难DrawIndexedPrimitives问题的实际原因。 如果你描述失败比“不起作用”更好,这也会有所帮助。

这就是说,这里有一些我注意到你的代码的东西:

  1. 你创建一个1024个顶点的数组,你使用WriteRange写入你的顶点缓冲区。 这是不好的,因为它会尝试写入数组的所有1024个元素(它利用数组的Length属性),而你的缓冲区只有60个字节。
  2. 您可以对顶点缓冲区的大小,原始数量和顶点的步幅进行硬编码。 您应该从顶点types和顶点列表本身获取这些信息。
  3. 您正在使用预先转换的位置,这意味着您的数据必须已经在屏幕空间坐标中(沿X和Y轴的-1到1)。 如果顶点的位置在该范围之外,则位于屏幕可见区域外。 一般情况下,您不应该使用预先转换的坐标,除非您了解它们的含义(转换管道将不会运行)。

这与您的问题没有直接关系,但依靠迭代对象表的能力并对其所有成员调用Dispose也是不好的。 这个function将在SlimDX的V2版本中消失,它只是鼓励马虎参考处理。