D3D11:旋转多个三角形

时间:2013-08-29 22:48:17

标签: c++ directx directx-11

我是DirectX的新手,在理解我认为的一些基础知识时遇到了一些问题。假设我有10个三角形,我想以不同的速率旋转每个三角形,以便随着时间的推移它们“旋转”。

到目前为止,我的三角形出现了,但我不知道如何单独旋转它们。据我所知,我会按照每个三角形做这样的事情吗?

  1. 计算旋转矩阵,并将其设置为常量数据。
  2. 使用常量数据更新常量缓冲区。
  3. 使用所述数据更新顶点着色器。
  4. DrawPrimitives,以便我的三角形出现在屏幕上,根据步骤#1中的矩阵旋转。 (通过顶点着色器)
  5. 是吗?这似乎很多来回。我应该依靠顶点着色器来进行变换,还是有不同的方法在每个'对象'(三角形)的基础上应用旋转?

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

1 个答案:

答案 0 :(得分:3)

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

模型是顶点数组:

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上执行此操作,因为它非常慢。 顶点缓冲区保持不变(当然,您可以更改它,以实现变形,曲面细分等效果,但这不是我们的情况)。

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

一种方法是恒定缓冲区

假设您在顶点着色器中有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缓冲区更新。

另一种方式是实例缓冲区

你创建了一个顶点缓冲区,它不包含顶点数据,而是准备由着色器使用的实例数据。

您计算实例数据并创建一次实例缓冲区:

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();

如果对象更改其参数,则只更新实例缓冲区:位置,颜色等。

绘制复杂场景时,大多数情况下都使用:常量缓冲区(对于所有或多个对象共享的属性:视图矩阵,投影矩阵等)和实例化(如果对象具有相同的模型几何,但属性不同) ),发挥他们的优势。