解析GLSL着色器字符串以在Android NDK中查找变量名称

时间:2012-05-02 19:15:09

标签: c++ parsing variables android-ndk glsl

这个是一个很好的。为了正确解释,让我解释一下我正在尝试做什么。我将跟进代码清单,然后向后解释代码。

目标

我正在尝试在每个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;
    }

服用红色药片

因此,我们的想法是有一个包含最常用变量 types 的关键查找表。首先,Shader收到的是一个包含数据信息的类,例如它的句柄,类型(片段,顶点,纹理等),当然还有它的来源。我正在从着色器文件解析所有这些,而不是字符串。

会发生一个爷爷循环,它遍历着色器文件中解析的每一行。在每一行中,如果密钥查找表中存在匹配,则迭代keyLookupTable[]的第二个循环将断开,索引值取值iKey(即,数组,找到匹配项)。然后循环中断。

如果找到匹配项,则会获取找到匹配项的行中的位置(例如vec4mat3)。从那里开始,使用pos中存储的位置,我们使用pos作为变量名长度的基础,这是通过在char数组中指定所需的字符数来完成的。所需的金额是线的长度减去位置。

然后从第三个也是最后一个循环遍历该行,使用char*引用它,获取line中的值并将它们复制到分配的var字符数组。

最后,std::vector键插入var并继续循环,重复该过程。

值得关注

  • 我正在使用JNI来获取着色器字符串,因为着色器本身是通过Java解析的,然后通过JNI发送到C ++。
  • Unicode可能是一个问题,因为我一直在获得如下输出: Shader Variable Found is: |uԯ|uԯ/
  • 着色器src从JNI通过env->GetStringUTFChars()
  • 传递给const char *

结论

我确信有更好的方法可以做到这一点,可能使用std::stringstream或其他东西,但我不是很熟悉它,并希望这种算法以某种方式或某种方式工作。但是,如果这是“天真”的做法,我愿意接受建议。

问题

实现此目的的最佳方法是使解析工作吗?

1 个答案:

答案 0 :(得分:9)

你确定自己需要这样做吗? GLSL已经为您进行了解析,如果您想要所有输入变量的列表,可以通过glGetActiveAttrib / glGetActiveUniform获取它们。

只查询链接着色器的活动attribs / uniforms的数量,然后遍历查询输入变量名称的每个索引。

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

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