2013-08-29 156 views
2

我是DirectX的新手,我对理解我认为的一些基础知识有点问题。假设我有10个三角形,并且我想以不同的速率旋转它们中的每一个,以便随着时间的推移它们会“旋转”。D3D11:旋转多个三角形

到目前为止,我有我的三角形出现,但我不太明白如何单独旋转它们。从我可以告诉我会做每三角这样的事情?

  1. 计算旋转矩阵,并将其设置为常量数据。
  2. 用常数数据更新常量缓冲区。
  3. 用上述数据更新顶点着色器。
  4. DrawPrimitives,使我的三角形出现在根据步骤#1中的矩阵旋转的屏幕上。 (通过顶点着色器)

是吗?它似乎来来回回。我是否应该依靠顶点着色器来进行变换,或者有什么不同的方法来在每个“对象”(三角形)的基础上应用旋转?

我很抱歉,如果我的问题没有道理,就像我说的,我认为我有一个概念/理解问题。

+0

是的,您需要将“世界”变换矩阵设置为一个常量缓冲区,并在顶点着色器中使用它来将每个顶点变换到新位置。 – jcoder

+0

我认为你的方式是正确的。那也是基于每个“对象”的。你可以做一个for循环,并为每个三角形做这些步骤。 – zdd

+0

@zdd好的,所以一个一个地做这些都没有什么大的性能影响?我的印象是,分批处理(如绘制操作)是一种行之有效的方法,并且逐步地做(一次一个)会影响性能/帧速率等等。当然,这是基于我记得的DX9天... –

回答

2

基本上,你有一些模型(在你的情况三角形)。

模型是顶点数组:

struct Vertex 
{ 
    float3 position; 
    float3 normal; 
    float2 texcoord; 
    float4 color; 
    // other vertex attributes goes here 
}; 

创建顶点(和索引)(类)缓冲剂一次,在初始化。

std::vector<Vertex> vertices = { /*vertex data goes here*/ }; 
VertexBuffer vb = renderer->CreateVertexBuffer(&vertices[0], vertices.size()); 

3D世界是对象这是情况下,你的模型(一个或多个)的的数组。

struct MyObject 
{ 
    float3 position; 
    float3 rotation; 
    float3 scale; 
    // other instance attributes goes here (it can be whatever you want) 
}; 

std::vector<MyObject> objects = { /*objects data goes here*/ }; 

基本上对象的属性是修饰顶点属性,因此所有对象都具有相同的型号,但看起来在你的世界的不同(在这个例子中,他们有不同的位置)。

通常在模型空间中定义的每个顶点的位置(以及法线,切线和双切线)。要将它移动(变换)到世界空间,可以将每个顶点的position乘以当前对象的矩阵。你不想在CPU上执行它,因为它非常慢。 顶点缓冲区保持不变(当然你可以改变它,达到变形,镶嵌等效果,但这不是我们的情况)。

所以,你在顶点(或几何)着色器中进行变换。您必须以某种方式将当前对象的变换(和其他实例属性)的信息发送给顶点着色器。

一种方法是恒定缓冲区(s)

假设你有在顶点着色器cbuffer:

cbuffer Instance 
{ 
    matrix worldMatrix; 
// other instance parameters goes here 
}; 

而且你必须用数据填充它。

绘制每个对象之前,更新缓冲区当前实例数据(每秒对象(多每帧次)):

renderer->SetVertexBuffer(vb); // Set needed geometry 
for(int i = 0; i < objects.size(); ++i) // for each object 
{ 
    matrix worldMatrix = CalculateWorldMatrix(objects[i]); // prepare data of current object 
    renderer->UpdateConstantBuffer(&worldMatrix); // Tell shaders about current object's attributes (world matrix in our case) 
    renderer->Draw(); // or DrawIndexed(); 
} 

对于n对象必须n绘制调用和n缓冲器更新。

另一种方式是实例缓冲区(s)

您再创建一个顶点缓冲区其中不包含顶点数据,但包含实例数据,准备供着色器使用。

您计算实例数据,一旦创建实例缓冲:

for(int i = 0; i < objects.size(); ++i) // for each object 
{ 
    std::vector<Instance> instances; 
    instances[i].worldMatrix = CalculateWorldMatrix(objects[i]); 
    // other instance parameters goes here 
} 

VertexBuffer instanceBuffer = renderer->CreateVertexBuffer(&instances[0], instances.size()); 

而且你还必须更改输入的布局,所以着色器将希望除了顶点数据实例数据。

绘图时,只需绑定顶点和实例缓冲区。无需更新缓冲区(如果您的三角形尚未移动)。并且不再需要矩阵计算。所以,没有for循环,只有一个(!)绘制调用。

renderer->SetVertexBuffers(2, vb, instanceBuffer); // Set needed model data and instances data 
    renderer->DrawInstanced(); // or DrawIndexedInstanced(); 

,如果你的对象改变其参数,你只更新例如缓冲:位置,颜色等

当绘制复杂的场景,你大部分时间同时使用:常量缓冲区(对于所有或许多共享的属性对象:视图矩阵,投影矩阵等)和实例化(如果有对象具有相同的模型几何体,但具有不同的属性),以利用它们的优点。

+0

你在这里介绍的两种方法的主要区别是什么,即优缺点? –

+0

进入UpdateBuffer的代码是什么?这似乎是知道的一件好事。 –