5

これはやっかいです。適切な説明のために、私がやろうとしていることを説明させてください。コードリストをフォローアップしてから、コードを後で説明します。

目標

私が持っているすべてのGLSLシェーダーファイルの変数の名前を取得しようとしています。現在、私は単一の頂点シェーダーと、それを補完するフラグメントシェーダーしか持っていません。これの目的は、すべての変数名を入力しなくても、値をシェーダーに動的にバインドできるようにすることです。

コード

std::vector< const char* > GetShaderVariableNames( const Shader& shader )
    {
        Config::Log::info( "Getting shader variable names." );

        static const char* keyLookupTable[] =
        {
            "vec2", "vec3", "vec4",
            "mat2", "mat3", "mat4",
            "float", "int", "double"
        };

        std::vector< const char* >  keys;
        std::vector< std::string > lines;

        SplitIntoLines( &lines, std::string( shader.shaderSrc ) );

        for( int32_t iLines = 0; iLines < lines.size(); ++iLines )
        {
            const char* line = lines[ iLines ].c_str();

            int32_t index = 0;
            bool foundMatch = false;

            for( int32_t iKey = 0; iKey < sizeof( keyLookupTable ) / sizeof( char ); ++iKey )
            {
                if( strContains( lines[ iLines ], keyLookupTable[ iKey ] ) )
                {
                    index = iKey;
                    foundMatch = true;
                    break;
                }
            }

            if( foundMatch )
            {
                const int32_t pos = lines[ iLines ].find( keyLookupTable[ index ] );

                Config::Log::info( "Position found is %i", pos );

                const int32_t lineLen = strlen( line );

                char* var = new char[ lineLen - pos ];

                int32_t iLine = pos + strlen( keyLookupTable[ index ] );

                for( ; iLine < lineLen; ++iLine )
                {
                    var[ iLine ] = line[ iLine ];
                }

                Config::Log::info( "Shader Variable Found is: %s", var );

                keys.push_back( var );
            }
        }

        return keys;
    }

赤いピルを飲む

したがって、最も一般的に使用される変数タイプを含むキールックアップテーブルがあるという考え方です。まず、受け取ったシェーダーは、ハンドル、タイプ(フラグメント、頂点、テクスチャなど)、そしてもちろんソースなど、データに関する情報を保持するクラスです。これらはすべて、文字列ではなく、シェーダーファイルから解析しています。

何が起こるかというと、シェーダーファイルで解析された各行を繰り返すおじいちゃんのループがあります。すべての行で、キールックアップテーブルに一致がある場合、反復する2番目のループは、の値(つまり、一致が見つかった配列内のインデックス)keyLookupTable[]をとるインデックス値で中断されます。iKeyその後、ループが中断します。

一致が見つかった場合は、一致が見つかった行の位置(vec4またはmat3)が取得されます。そこから、に格納されている位置posを使用posして、変数名の長さの基準として機能します。これは、char配列に必要な文字数を指定することによって行われます。必要な量は、線の長さから位置を引いたものです。

そこから、3番目の最後のループが行を繰り返し、aを使用しchar*てそれを参照し、値を取り込んでline、割り当てられたvar文字配列にコピーします。

最後に、std::vectorキーが挿入varされてループに進み、プロセスが繰り返されます。

注目すべき懸念

  • シェーダー自体はJavaを介して解析され、JNIを介してC ++に送信されるため、JNIを使​​用してシェーダー文字列を取得しています。
  • 私は次のような出力を取得しているので、Unicodeが問題になる可能性があります。 Shader Variable Found is: |uԯ|uԯ/
  • シェーダーsrcは、JNIからconstchar*に渡されます。env->GetStringUTFChars()

結論

これを行うには、おそらく何かを使用するなど、より良い方法があると確信していますstd::stringstreamが、私はそれについてあまり詳しくないので、このアルゴリズムを何らかの形で機能させたいと考えています。ただし、これが「素朴な」方法である場合は、提案を受け付けています。

質問

解析を機能させるためにこれを達成するための最良の方法は何ですか?

4

1 に答える 1

9

これを自分で行う必要がありますか?GLSLはすでにこの解析を行っており、すべての入力変数のリストが必要な場合は、glGetActiveAttrib/を介してそれらを取得できますglGetActiveUniform

リンクされたシェーダーのアクティブな属性/ユニフォームの数をクエリし、入力変数の名前をクエリする各インデックスを反復処理するだけです。

http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttrib.xml

http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml

于 2012-05-02T19:20:28.377 に答える