7

バックグラウンド

ゲーム エンジンの開発では、メモリと計算のパフォーマンスを最適化するために、通常はデータ指向の設計を使用します。

パーティクルシステムを例に取りましょう。

粒子システムには多数の粒子があり、各粒子は位置、速度などのいくつかの属性を持つ場合があります。

C++ での典型的な実装は次のようになります。

struct Particle {
    float positionX, positionY, positionZ;
    float velocityX, velocityY, velocityZ;
    float mass;
    // ...
};

struct ParticleSystem {
    vector<Particle> particles;
    // ...
};

この実装の問題の 1 つは、パーティクルの属性が相互にインターリーブされることです。このメモリ レイアウトはキャッシュに適していないため、SIMD 計算には適していない可能性があります。

データ指向の設計ではなく、次のコードを記述します。

struct ParticleAttribute {
    size_t size;
    size_t alignment;
    const char* semantic;
};

struct ParticleSystem {
    ParticleSystem(
        size_t numParticles,
        const ParticleAttribute* attributes,
        size_t bufferSize) {
        for (size_t i = 0; i < numAttributes; ++i) {
            bufferSize += attributes[i].size * numParticles;
            // Also add paddings to satisfy the alignment requirements.
        }
        particleBuffer = malloc(bufferSize); 
    }

    uint8* getAttribute(const char* semantic) {
        // Locate the semantic in attributes array.
        // Compute the offset to the starting address of that attribute.
    }

    uint8* particleBuffer;      
};

これで、割り当ては 1 つだけになり、各属性はメモリ内に継続的に存在します。粒子をシミュレートするには、次のコードを記述します。

symplecticEuler(ps.getAttribute("positionX"), ps.getAttribute("velocityX"), dt);

このgetAttribute関数は、特定の属性の開始アドレスを取得します。

質問

これをRustに実装する方法を知りたいです。

私の考えは、最初に というクラスを作成することです。これは、合計バッファーサイズを計算するのにParticleSystem数秒かかり、次にバッファーにメモリを割り当てます。ParticleAttributeこれはRustセーフなコードでできると思います。

次のステップはgetAttribute、特定の属性の開始アドレスへの参照を返す関数を実装することです。ここであなたの助けが必要です。オフセットを使用して生のアドレスを取得し、それを目的の型 (float* など) にキャストし、その生のポインターを Rust の可変参照にラップするにはどうすればよいですか?

さらに、SIMD ライブラリを使用してその参照を介して 4 つの要素をロードする必要があるため、配列への変更可能な参照への生のポインターをラップする必要があると思います。Rustを使用してこれを達成するにはどうすればよいですか?


更新: 属性に関する詳細情報を提供します。属性の数と詳細情報は実行時に決定されます。属性のタイプはさまざまですが、プリミティブなもの (f32、f64、ints など) のみをサポートする必要があると思います。

4

1 に答える 1