Ben*_*y33 1 c# directx direct3d
我对directX并不是很了解,但我会尽力解释.首先,我有多个模型对象(带顶点数据的自定义对象).目前,我的代码(见下文)可以使用该模型的vertexBuffer和indexBuffer在场景中渲染单个模型.我想做的是给出一系列模型.在一个场景中渲染它们.这是我目前的代码:
private void Render()
{
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.White, 1.0f, 0);
device.BeginScene();
float x = (float)Math.Cos(0);
float z = (float)Math.Sin(0);
device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1f, 50f);
device.Transform.View = Matrix.LookAtLH(new Vector3(x, 6, z), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
device.RenderState.Lighting = true;
device.Lights[0].Type = LightType.Directional;
device.Lights[0].Diffuse = Color.White;
device.Lights[0].Direction = new Vector3(-x, -6, -z);
device.Lights[0].Position = new Vector3(x, 6, z);
device.Lights[0].Enabled = true;
device.Transform.World = model.transform;
device.VertexFormat = CustomVertex.PositionNormalColored.Format;
device.SetStreamSource(0, vertexBuffer, 0);
device.Indices = indexBuffer;
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, model.getVertices().Length, 0, model.getIndices().Length / 3);
device.EndScene();
device.Present();
}
public void RenderModel(Model model)
{
this.model = model;
vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionNormalColored), model.getVertices().Length,
device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionNormalColored.Format, Pool.Default);
vertexBuffer.SetData(model.getVertices(), 0, LockFlags.None);
indexBuffer = new IndexBuffer(typeof(ushort), model.getIndices().Length, device, Usage.WriteOnly, Pool.Default);
indexBuffer.SetData(model.getIndices(), 0, LockFlags.None);
Render();
}
Run Code Online (Sandbox Code Playgroud)
TL;博士;
你可以简单地调用RenderModel一个循环.但是,为了获得更好的性能,您需要按更新频率对操作进行排序,始终处置不需要的资源,并且不要保留相同数据的多个副本.
好吧,使用您的设置渲染多个对象的天真方法如下所示:
foreach (var model in models)
{
RenderModel(model);
}
Run Code Online (Sandbox Code Playgroud)
我说天真,因为我会先解决很多事情.
实时3D应用程序都是关于良好的性能.为了实现它,你必须非常小心你执行昂贵任务的频率.例如,此刻的你正在创造一个新的顶点和索引缓冲区每次该RenderModel方法被调用.(我想每帧都会发生这种情况?)另外,每个模型都会单独设置效果状态(如视图/投影矩阵和光照),尽管它们可能在整个帧中保持相同.
识别昂贵的操作(设置/创建着色器,常量,缓冲区;大致使用GraphicsDevice的任何东西)并考虑它们需要更改的频率.为了获得最佳性能,请不要经常这样做.例子:
网格的顶点缓冲区:如果网格不是动态的,并且顶点在一段时间内(或根本不会)不会更改,则顶点缓冲区将始终包含相同的数据.加载网格然后一遍又一遍地重复使用时,创建它就足够了.(也适用于索引缓冲区.)(更新频率:每级一次)
设置光照,视图和投影矩阵:照明通常在一帧内保持不变.相机矩阵也是如此.在框架的开头设置它们一次就完成了.(更新频率:每帧一次)
绑定纹理:通常,场景中会有不同的材质,与单个模型相关联.大多数情况下,材质属于多个对象(因为您将它们的纹理组合在一个大的纹理贴图中).因此,对于使用它的所有网格,将这些纹理和常量绑定一次将节省最多的GPU容量.(更新频率:每种材料一次)
绑定顶点和索引缓冲区:顶点和索引数据通常对于网格是唯一的.因此,如果您的场景中有多个网格物体,那么一旦完成一个网格物体就会在设备上切换缓冲区是不可避免的.(更新频率:每个网格一次)
设置世界矩阵:设置效果状态,并将网格数据绑定到设备.你最终可以绘制你的对象.所以你设置了世界矩阵并调用了设备的draw方法.但是等等,你想要在场景中的其他地方另一个网格副本吗?现在是它的最佳时机.简单地绑定另一个世界矩阵并再次绘制.您刚刚在设备上绘制了两个状态变化最小的对象.完善!1 (更新频率:每个网格实例一次)
1 如果你真的需要在场景中使用相同网格的大量副本,我建议你先看看硬件实例,从Direc3D 9开始.
通常垃圾收集器会处理您的旧对象,并且它在这方面做得非常好.但在这里,您正在使用无人管理的资源.它们被称为非托管,因为它们不受CLR管理,因此不受垃圾回收的影响.
保持这些对象可能会导致内存泄漏.您的记忆将被不必要的资源混乱,导致性能下降.2
.NET为使用非托管资源的类提供了一个接口,称为IDisposable接口.它公开了一种Disposable方法,从中释放非托管资源.一旦使用完该对象,您所要做的就是调用该方法.
if (myTexture != null)
myTexture.Dispose();
Run Code Online (Sandbox Code Playgroud)
例如,在您的情况下,您每帧都会创建一个新的顶点和索引缓冲区.在用新的缓冲区覆盖它们之前,你应该清楚地处理它们,旧的缓冲区消失在必杀技中.(更不用说,你不应该经常创建它们.)只要看看一些Direct3D类,你会发现它们中的大多数都实现了IDisposable.
2据我所知,实际上并没有那么糟糕.正确实现IDisposable通常意味着类有一个Destructor,Dispose一旦对象被垃圾收集,它就会调用.尽管如此,由于您无法知道垃圾收集何时发生,因此无论如何都要手动处理Disposable对象.
目前,您可能将顶点和索引存储在数组中.创建缓冲区时,基本上就是创建数据的副本.正如我之前提到的:每个网格可以创建一次顶点和索引缓冲区.因此,当您这样做时,将顶点和索引写入缓冲区,然后仅保留这些顶点和索引.您的模型类当然会略有变化:
public class Model
{
public VertexBuffer Vertices { get; private set; }
public IndexBuffer Indices { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您不需要直接访问顶点和索引,这将是一个更好的解决方案.
我知道,这是一个小步骤,但我认为了解它是件好事.
public void RenderFrame(Model[] models)
{
// Per frame
Bind(View);
Bind(Projection);
BindLighting();
// Per effect
BindEffect();
foreach (var material in GetMaterials(models))
{
// Per material
Bind(material.Color);
Bind(material.DiffuseMap);
foreach (var model in GetModelsByMaterial(material, models))
{
// Per mesh
Bind(model.VertexBuffer);
Bind(model.IndexBuffer);
foreach (var instance in model.Instances)
{
// Per instance
Bind(instance.World);
// Draw the instance
Draw();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:我一直在使用Direct3D 9(XNA)几个月.我写的大部分内容都应该适用于D3D9和Direct3D 10/11,我对此更为熟悉.
| 归档时间: |
|
| 查看次数: |
4384 次 |
| 最近记录: |