3

私は DirectX を初めて使用し、基本的なことのいくつかを理解するのに少し問題があります。10 個の三角形があり、時間の経過とともに「スピン」するように、それぞれを異なる速度で回転させたいとしましょう。

これまでのところ、三角形が表示されていますが、それらを個別に回転させる方法がわかりません。私が言えることから、三角形ごとにこのようなことをしますか?

  1. 回転行列を計算し、定数データに設定します。
  2. 定数バッファを定数データで更新します。
  3. 上記のデータで頂点シェーダーを更新します。
  4. DrawPrimitives を使用して、手順 1 のマトリックスに従って回転した画面に三角形が表示されるようにします。(頂点シェーダー経由)

そうですか?往復が多いようです。変換を行うために頂点シェーダーに依存することになっていますか、それとも「オブジェクト」(三角形) ごとに回転を適用する別の方法がありますか?

私が言ったように、私の質問が意味をなさない場合は申し訳ありませんが、私は概念/理解の問題を抱えていると思います.

4

1 に答える 1

3

基本的に、いくつかのモデル(あなたの場合は三角形)があります。

モデルは頂点の配列です。

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

初期化時に、頂点 (およびインデックス) バッファーを 1 回作成します。

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 で実行したくありません。頂点バッファーは変更されません(もちろん、変形、テッセレーションなどの効果を得るために変更できますが、これは私たちの場合ではありません)。

したがって、頂点(またはジオメトリ)シェーダーで変換を行います。そして、どういうわけか、現在のオブジェクトの変換 (およびその他のインスタンス属性) の情報を頂点シェーダーに送信する必要があります。

1 つの方法は定数 buffer(s)です。

頂点シェーダーに cbuffer があるとします。

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

そして、データを入力する必要があります。

各オブジェクトを描画する前に、現在のインスタンス データでバッファを更新します (オブジェクトごとに 1 回 (フレームごとに複数回))。

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バッファ更新があります。

もう 1 つの方法は、インスタンス バッファーです。

頂点データではなくインスタンス データを保持するもう 1 つの頂点バッファーを作成し、シェーダーによって消費されるように準備します。

インスタンス データを計算し、インスタンス バッファを 1 回作成します。

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ループはなく、描画呼び出しは 1 つ (!) だけです。

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

オブジェクトのパラメータ (位置、色など) を変更する場合にのみ、インスタンス バッファを更新します。

複雑なシーンを描画するときは、ほとんどの場合、定数バッファー (ビュー マトリックス、射影マトリックスなどのすべてまたは多くのオブジェクトで共有される属性用) とインスタンス化 (モデル ジオメトリが同じで属性が異なるオブジェクトがある場合) の両方を使用して、彼らの利点を取ります。

于 2013-08-30T04:27:54.053 に答える