1

float を int にキャストしたときの GLSL コードの奇妙な動作について助けを得るためにここに来ましたが、GLSL を開始して以来、そのようなバグは見たことがありません

実際、GLSLを使用してCPUでメッシュスキニングを実現しようとしています

ATI Radeon HD 4850 (Gainward) を使用しており、Windows XP で OpenGL 2.1 を使用しています。

そのため、CPU 側でボーンのインデックスとウェイトを収集し、それらを頂点属性を使用してシェーダーに投げてから、ボーン マトリックスにウェイトを乗算し、その結果を使用して法線と gl_Position を計算します。

そこまではごく普通の

ボーン インデックスからボーンを取得する必要がある場合に問題が発生します。

4 つのボーンでスキニングされた単純なシリンダー メッシュを使用します。Cpu から均一な変数を介してボーンを送信しましたが、問題はこれらのボーン マトリックスに起因するものではないようです。シェーダーでハードコーディングしましたが、バグは残っています。ちなみに、Maya レンダリングと比較すると形状は正しいです。

さらに、各頂点のボーン インデックスは同じです: 0, 1, 2, 3; それらは VBO を介して GL_UNSIGNED_INT タイプで送信されます。しかし、シェーダーでは uvec4 が機能しないようです (ivec4 も)。そのため、float vec4 を使用して int() でキャストする必要があります。

ここに私の頂点シェーダーコードがあります:

uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;
uniform mat3 NormalMatrix;

uniform mat4 bones[4];

varying vec3 normal;

attribute vec3 v_pos;
attribute vec3 v_normal;

//the 4 first bones indices of the vertex;
attribute vec4 v_boneIndices0;
//the 4 first bones weights of the vertex
attribute vec4 v_boneWeights0;

void main()
{   

/* To compare with bones sent via uniform, i hardcoded the bones matrices in this array; doesn't seem to make a difference

        mat4 mattab[4];

        mattab[0] = mat4(1.0f, 0.0f, 0.0f, 0.0f,
                         0.0f, 1.0f, 0.0f, 0.0f,
                         0.0f, 0.0f, 1.0f, 0.0f,
                         0.0f, 0.0f, 0.0f, 1.0f);

        mattab[1] = mat4(1.0f, 0.0f, 0.0f, 0.0f,
                         0.0f, 0.816489f, 0.57736f, 0.0f,
                         0.0f, -0.57736f, 0.816489f, 0.0f,
                         0.0f, -0.341108f, 1.07319f, 1.0f);

        mattab[2] = mat4(0.999949f, -0.00863831f, 0.00528692f, 0.0f,
                         -0.00400147f, 0.142574f, 0.989776f, 0.0f, 
                         -0.00930377f, -0.989746f, 0.142532f, 0.0f, 
                         0.00201152f, -0.00111439f, 0.865123f, 1.0f); 

        mattab[3] = mat4(0.799844f, -0.0233416f, -0.599754f, 0.0f,
                         0.448905f, 0.686556f, 0.571949f, 0.0f,
                         0.398414f, -0.726702f, 0.559616f, 0.0f, 
                         -1.23581f, -1.4976f, 2.0412f, 1.0f );

*/

        //the average matrix of weighted bones
        mat4 mat = mat4(0.0f);

        for ( int i = 0; i < 4; i++){

               //normally, the both lines below are equivalent 
               //because v_boneIndices0 is always 0,1,3,4

               mat += v_boneWeights0[i] * bones[int(v_boneIndices0[i])];
               //mat += v_boneWeights0[i] * bones[i];  

                }

        //Here, I multiply the average matrix with v_normal and v_pos

        normal = NormalMatrix * (mat3(mat[0].xyz,mat[1].xyz,mat[2].xyz) * v_normal);

        gl_Position = ProjectionMatrix*ModelViewMatrix*(mat*vec4(v_pos, 1.0f));

}

FPS レートを見ているときにバグが表示されます。スキニングなしで、2000 FPS が得られます

ラインを使うとき

mat += v_boneWeights0[i] * bones[i];

いくつかのアーティファクトで適切な形状を取得します。FPS は 2000 のままです

しかし、私がラインを使用するとき

mat += v_boneWeights0[i] * bones[int(v_boneIndices0[i])];

(これは他のラインに似ています) 形は完璧ですが、FPS は 1500 FPS に落ちます...

ループを遅くしたのは回線自体だと思いました。ただし、この行を離れて通常の gl_Position 計算からマットを削除すると、FPS レートは 2000 に上昇します

私が計算すると、別の奇妙な動作

vec4 test = ProjectionMatrix*ModelViewMatrix*(mat*vec4(v_pos, 1.0f));

ループの直後に、マット乗算なしで Normal gl_Position を計算します

normal = NormalMatrix * v_normal;
gl_Position = ProjectionMatrix*ModelViewMatrix* vec4(v_pos, 1.0f);

FPS レートも 2000 に上昇します

合体しないとバグが出るみたい

mat += v_boneWeights0[i] * bones[int(v_boneIndices0[i])];

and

normal = NormalMatrix * (mat3(mat[0].xyz,mat[1].xyz,mat[2].xyz) * v_normal);
gl_Position = ProjectionMatrix*ModelViewMatrix*(mat*vec4(v_pos, 1.0f));

これはハードウェアのバグだと思います。または、私のやり方が間違っているのかもしれません。わかりませんが、問題は int() のキャストに関連していると思います。

Nvidiaでこの種の動作に遭遇した人はいますか? Google で何も見つかりませんでした

あなたが私を助けてくれることを願っています

ありがとう :)

4

2 に答える 2

3

あなたのエラーは、フレームあたりの時間 (timedelta)ではなく、パフォーマンスのために1 秒あたりのフレーム数を見ていることです。2000 fps と 1500 fps の差はごくわずかです。2000 fps は、1 フレームあたり 0.5 ミリ秒を意味します。1500 fps は、フレームあたり 0.6 ミリ秒を意味します。fps とフレームあたりの時間との相関関係は線形ではありません。有効な fps は 1/timedelta です。時間ウィンドウが非常に小さいため、fps が多いほど、fps の感度が高くなります。10,000 fps があり、10,000 fps から 5,000 fps の間で変動したとします。これにより、0.1 ミリ秒から 0.2 ミリ秒の時間枠が得られます。その時点で、すべての操作が timedelta に影響を与える可能性があります。

于 2010-08-02T16:16:16.653 に答える
0

ivec4 と uvec4 は OpenGL 2.1 の GLSL の一部ではなく、拡張機能 (GL_EXT_gpu_shader4) であるため、次を使用してその拡張機能を有効にする必要があります。

#extension GL_EXT_gpu_shader4 : enable

シェーダーの開始時に、シェーダーで実際の整数を使用できるようになります。この拡張機能は、DX 10 以降のカードでのみサポートされていることに注意してください (お使いのカードでサポートされています)。

この拡張機能は Core OpenGL 3.0 の一部です。

于 2010-08-03T19:59:33.473 に答える