OpenGL 1D纹理:填充任意浮点数值

3

所以,我正在努力理解一维纹理。我尝试将三个浮点值作为 uniform 传递到片段着色器中。它们代表了光的颜色,旨在通过在纹理中存储所有信息(颜色和位置)来重用相同的着色器以处理 n 个灯光。目前,我正在尝试仅传递单个光源的颜色以测试事物。因此,在片段着色器中,我有以下内容:

uniform sampler1D lightColor;
...
vec3 lc = vec3(texelFetch(lightColor, 0, 0)); // all zeroes
vec3 lc = vec3(texture(lightColor, 0, 0));    // same

我曾尝试在着色器中使用texelFetchtexture调用(二者之一或两者皆有),但无济于事。请注意,如果我像这样在着色器中硬编码值:

vec3 lc = vec3(0.0f, 0.0f, 0.8f);

然后我得到了期望的结果(即 lc 中的非零值),因此我确信,至少在着色器中,问题可能出现在 texelFetchtexture 调用中。

回到 C++ 领域,代码(在我的 lightManager 初始化时执行一次)如下:

GLfloat lightValues[] = { 0.8f, 0.8f, 0.8f };
GLuint lightID; // member, not a local variable.
glGenTextures(1, &lightID);
glBindTexture(GL_TEXTURE_1D, lightID);
glActiveTexture(GL_TEXTURE0 + lightID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage1D(GL_TEXTURE_1D, 1, GL_RGB32F, 1);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 3 * sizeof(GLfloat), GL_RGB, GL_FLOAT, lightValues);
glUniform1i(glGetUniformLocation(shader->program, "light"), lightID);

这里没有什么非常花哨的东西(虽然肯定是错误的)。在阅读OpenGL文档的6.2表后,对于glTexStorage1D,我选择了1作为levels(没有MipMaps),并选择了GL_RGB32F作为internalFormat(因为我正在尝试传递3个浮点数)。由于只有一个值,所以width为1。这应该处理好了分配。
现在,填充缓冲区需要使用glTexSubImage1D,我选择level 0(同样没有MipMaps),0作为xoffset,宽度为GLfloat大小的三倍,GL_RGB作为格式,GLfloat作为type。最后,是实际数据。
关于c++代码的一些事情:我正确地将过滤器设置为GL_NEAREST(所以不是它的问题),我会说uniform位置/连接到sader是正确的(通过glUniform1iglGetUniformLocation)。
现在来谈我的问题:
  • 首先,显而易见,通过纹理传递灯光信息是否合理?着色器明显无法执行像lights[n]这样的操作,因为需要在编译时知道n,所以纹理自然而然地成为一种欺骗的方式。
  • 其次,我的假设是否正确,数据大小可能是罪魁祸首?我读到过关于纹理完整性的内容,但说实话,它非常简略。一个像素的大小肯定有问题。
  • 第三,您是否发现其他任何问题?特别是与internalFormatformattype有关的问题?
  • 第四,有什么想法可以解释为什么lc不断被填充为零吗?
谢谢!
编辑:我不想使用多次传递或定义传递到着色器的灯光数量的硬限制(使n恒定)。我读到了一些关于OpenGL 4.2中的某些功能的内容,但我对此不感兴趣。我只是想用手头的工具学习(但可以保证,在弄清楚这个问题后,将来我会回来问这些主题的问题(: )
1个回答

1

好的,我和https://stackoverflow.com/users/1774414/raistmaj一起弄清楚了

原来在glTexStorageglTexSubImagewidth是数组中元素的数量,因此为1,无论组件的数量如何。

另外,在调用glBindTexture之前必须先调用glActiveTexture(显然!!)


你还在错误地使用纹理ID的glActiveTexture。OpenGL会生成一个错误并忽略该调用。 - datenwolf
1
你在那里做错的是将纹理名称添加到GL_TEXTURE_0中。这不是正确的方法!有一定数量的纹理单元(从0到N,其中N是您可以使用glGetInteger(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)查询的数字),并且可以调用glActiveTexture(GL_TEXTURE_0 + i),其中i在范围0到N内。您使用glGenTextures生成并使用glBindTexture绑定的是所谓的纹理名称,在1到2^32-1的范围内可以使用任何名称作为纹理名称。 - datenwolf
1
关于你的问题“如何知道激活哪个纹理单元”:这取决于你的判断。把纹理单元看作是喷漆枪,它们由OpenGL实现给出了一定数量的喷漆枪,你必须使用它们。但是你可以在商店里放置(几乎)无限数量的染料罐,可以自由地与有限数量的喷漆枪连接。glActiveTexture(GL_TEXTURE_0 + 喷漆枪编号) 选择喷漆枪,glBindTexture(…, 染料名称) 连接喷嘴,glUniform(sampler_location, 喷漆枪编号) 分配喷漆枪到着色器。 - datenwolf
假设我连接了M支喷漆枪,对于我的照明计算来说需要加1。这个值m会因为不同的表面而改变,并且最大值应该是N-1,对吗?换句话说,对于绘制完整的模型(由许多表面组成),可用纹理数量的限制是分别应用于每个表面,而不是整个模型。更进一步地说,渲染我的场景可能需要超过N支喷漆枪,只要每个单独的表面所需的喷漆枪数不超过N即可。我说的有什么不对吗?还是我理解得没问题? - Carlos Romero
1
将“surface”替换为“drawing batches”,你就对了。在旧的遗留API中,glBegin/glEnd块表示“drawing batch”。现在,你可以通过调用名为glDraw…的函数来识别一个连贯的绘图批次。在这些调用之间,你可以为每个纹理单元更改纹理绑定。- 还有一个扩展(这还不是标准功能,所以不要依赖它),允许在绘图批次中使用任意数量的纹理,而无需绑定它们;该扩展称为“bindless textures”。我只是想引起你的兴趣... - datenwolf
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接