我有一个像素着色器:
varying vec2 f_texcoord;
uniform vec4 mycolor_mult;
uniform sampler2D mytexture;
void main(void) {
gl_FragColor = (texture2D(mytexture, f_texcoord) * mycolor_mult);
};
和相应的C ++代码:
GLint m_attr = glGetUniformLocation(m_program, "mycolor_mult");
// ...
unsigned int myColor = ...; // 0xAARRGGBB format
float a = (myColor >> 24) / 255.f;
float r = ((myColor >> 16) & 0xFF) / 255.f;
float g = ((myColor >> 8) & 0xFF) / 255.f;
float b = (myColor & 0xFF) / 255.f;
glUniform4f(m_attr, r, g, b, a);
我将精灵的颜色保持为unsigned int
,并且必须将其转换为4个浮点数才能将其传递给着色器。
可以优化吗?我的意思是我可以传递不浮点数,但是无符号字符作为着色器的组件并避免“除以255”操作吗?我应该在着色器和C ++代码中进行哪些更改?
答案 0 :(得分:5)
这个问题有几个方面。
我同意@ Nick的评论。你很有可能试图优化那些对性能不重要的东西。例如,如果此代码每帧仅执行一次,则此代码的执行时间绝对无关紧要。如果每帧执行多次次,事情可能会有所不同。使用分析器可以告诉您在此代码中花费了多少时间。
确保glGetUniformLocation()
调用仅在链接着色器后进行一次,而不是每次都设置制服。否则,该调用很可能比其余代码昂贵得多。如果您已经这样做,那么从代码中就不完全清楚了。
实际上,如果您需要在着色器中将值设置为浮点数。制服没有自动格式转换,因此您不能简单地使用glUniform*()
系列中的其他来电。来自规范:
对于所有其他统一类型,使用的Uniform *命令必须与着色器中声明的制服的大小和类型相匹配。没有进行类型转换。
如果您真的想进行微优化,可以通过乘法替换除法。在大多数CPU上,划分比乘法更昂贵。然后代码如下所示:
const float COLOR_SCALE = 1.0f / 255.f;
float a = (myColor >> 24) * COLOR_SCALE;
float r = ((myColor >> 16) & 0xFF) * COLOR_SCALE;
float g = ((myColor >> 8) & 0xFF) * COLOR_SCALE;
float b = (myColor & 0xFF) * COLOR_SCALE;
您不能指望编译器为您执行此转换,因为更改操作可能会影响操作的精度/舍入。一些编译器具有标志以实现这些类型的优化。请参阅示例Optimizing a floating point division and conversion operation。
答案 1 :(得分:2)
使用现代OpenGL(GLSL> = 4.1),有unpackUnorm4x8
GLSL函数可以完全按照您的要求执行:它需要一个32位uint并从中创建一个标准化的浮点向量。你只需要调整结果以匹配你的字节顺序,该函数会将最低有效字节解释为第一个通道。
uniform uint mycolor_packed;
//...
vec4 mycolor_mult=unpackUnorm4x8(mycolor_packed).bgra;
这可能是在着色器本身中进行转换的最有效方法。但是,如果在GPU上每个片段执行一次这样的操作更有效率,而且每次在CPU上进行一次调用只执行一次,那么仍然值得怀疑。