5

2 つのベクトルを含むライト パラメータの構造体を定義しました。構造体は、C++ と GLSL の両方で同様の方法で定義されます (注: s ではなくQVector3D3 つの s をカプセル化します)。floatdouble

C++ ホスト プログラム:

struct LightParameters {
    QVector3D pos;
    QVector3D intensity;
};

フラグメント シェーダー:

struct LightParameters {
    vec3 pos;
    vec3 intensity;
};

フラグメント シェーダーでは、次のユニフォームも定義します。ライトの数は 8 に制限されているため、uniform 配列のサイズは一定です (ただし、numLights実際に使用されるのは 1 つだけです)。

const int maxLights = 8;
uniform int numLights;
uniform LightParameters lights[maxLights];

ホスト プログラムでは、ライトを定義してシェーダーに渡します ( QGLShaderProgram)。

static const int maxLights = 8;
LightParameters lights[maxLights];

int numLights = 1;
lights[0].pos = {0, 1, 0};
lights[0].intensity = {1, 1, 1};

shaderProgram->bind();
shaderProgram->setUniformValue("numLights", numLights);
shaderProgram->setUniformValueArray("lights", reinterpret_cast<GLfloat*>(lights), maxLights, 6);
shaderProgram->release();

最後のパラメーターの6は、各配列要素がGLfloat生の float 配列 (別名「タプル サイズ」) から 6 を使用することを示す必要があります。

Qt のドキュメントによると、6 のタプル サイズを使用することはできないはずです (1、2、3、4 のみが許可されています)。一方、QGLShaderProgram では、最大 4x4 のエントリを持つマトリックスを渡すことができます。GLSL では、4 つ以上の float を持つユニフォームの構造体も使用できます (この例によると)。

これは、次の質問につながります。

Qtを使用してフロート/ベクトルの構造体を均一な配列として渡すにはどうすればよいですか? Qt でできない場合は GL 関数を呼び出してこれを行いますが、Qt がこれを便利に実行できるかどうかに興味があります。

もちろん、とにかく上記のコードを試しました。構造体のすべてのベクトルが 0 に設定されます。

構造体の 2 番目のパラメーターを削除して 3 のタプル サイズを使用しても、コードは機能しません。ただし、vec3シェーダーで使用するだけの場合 (ホスト プログラムで 1 つの QVector3D を持つ構造体、タプル サイズ = 3) は機能します。

したがって、OpenGL ホスト プログラム API ではカスタム タイプの処理が異なることが問題のようですが、Qt はそれをサポートしていないようです。現在、回避策として 2 つの一様な配列 (1 つは位置用、もう 1 つは強度用) を使用しています。

4

2 に答える 2

12

Qtはこれとは何の関係もありません。

の配列であるかのように構造体の配列を渡すことはできません型が基本型ではない均一な配列がある場合、すべての配列インデックスとその構造体のすべてのメンバーには、別々の均一な名前を持つ別々の均一な場所があります。したがって、各メンバーを個別に渡す必要があります。

これを行う必要があります:

shaderProgram->setUniformValue("lights[0].pos", lights[0].pos);
shaderProgram->setUniformValue("lights[0].intensity", lights[0].intensity);
shaderProgram->setUniformValue("lights[1].pos", lights[1].pos);
shaderProgram->setUniformValue("lights[1].intensity", lights[1].intensity);
shaderProgram->setUniformValue("lights[2].pos", lights[2].pos);
shaderProgram->setUniformValue("lights[2].intensity", lights[2].intensity);

などなど。

または、適切な均一ブロックを使用して、そのすべてを省くこともできます。

于 2013-05-24T17:48:20.203 に答える
0

テンプレート関数を使用します:

template<class T> void setUniformArrayValue(QOpenGLShaderProgram *program,
                                       const QString& arrayName,
                                       const QString& varName,
                                       int index,
                                       const T& value)
{
    const char* name = QString("%1[%2].%3")
            .arg(arrayName)
            .arg(index)
            .arg(varName)
            .toStdString().c_str();
    program->setUniformValue(name, value);
}

そしてプログラムで:

for (int i = 0; i < m_lights.size(); i++) {
    setUniformArrayValue<QColor>(program, "lights", "ambient", i, m_lights[i].ambient());
    ...
}
于 2015-06-09T14:49:03.457 に答える