【发布时间】:2011-06-27 13:57:19
【问题描述】:
我目前正在尝试使用不同的纹理(使用 C# 和 OpenTK)绘制简单的网格。我阅读了很多有关 TextureUnit 和绑定的信息,这就是我当前的实现(未按预期工作):
private void ApplyOpaquePass()
{
GL.UseProgram(this.shaderProgram);
GL.CullFace(CullFaceMode.Back);
while (this.opaqueNodes.Count > 0)
Draw(this.opaqueNodes.Pop());
GL.UseProgram(0);
}
还有我的绘制方法:
private void Draw(Assets.Model.Geoset geoset)
{
GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(TextureTarget.Texture2D, geoset.TextureId /*buffer id returned by GL.GenTextures*/ );
GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "Texture1"), 1 /*see note below*/ );
//Note: if I'm correct, it should be 1 when using TextureUnit.Texture1
// (2 for Texture2...), note that doesn't seem to work since no
// texture texture at all is sent to the shader, however a texture
// is shown when specifying any other number (0, 2, 3...)
// Draw vertices & indices buffers...
}
还有我的着色器代码(这应该不是问题,因为 uv 映射没问题):
uniform sampler2D Texture1;
void main(void)
{
gl_FragColor = texture2D(Texture1, gl_TexCoord[0].st);
}
有什么问题:
由于 geoset.TextureId 可以从一个 geoset 到另一个 geoset 不同,我希望将不同的纹理发送到着色器。
相反,始终将相同的纹理应用于所有对象(geoset)。
想法:
为每个纹理使用不同的 TextureUnit(效果很好),但是如果我们有 2000 个不同的纹理会发生什么?如果我的理解是正确的,只有当我们想在着色器中同时使用多个纹理时,我们才必须使用多个 TextureUnit。
-
我最初认为制服一旦定义就无法更改,但使用布尔制服的测试告诉我这实际上是可能的。
private void Draw(Assets.Model.Geoset geoset) { GL.ActiveTexture(TextureUnit.Texture1); GL.BindTexture(TextureTarget.Texture2D, geoset.TextureId); GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "Texture1"), 1 ); //added line... GL.Uniform1(GL.GetUniformLocation(this.shaderProgram, "UseBaseColor"), (geoset.Material.FilterMode == Assets.Model.Material.FilterType.Blend) ? 1: 0); // Draw vertices & indices buffers... }着色器代码:
uniform sampler2D Texture1; uniform bool UseBaseColor; void main(void) { gl_FragColor = texture2D(Texture1, gl_TexCoord[0].st); if (UseBaseColor) gl_FragColor = mix(vec4(0,1,1,1), gl_FragColor , gl_FragColor .a); }这段代码效果很好,用基色而不是透明度绘制了一些 geoset,这(应该?)证明可以在此处更改制服。为什么这不适用于我的纹理?
我应该为每个 geoset 使用不同的着色器程序吗?
提前感谢您的回答 :)
问候,
布鲁斯
编辑:这就是我在渲染器中生成纹理的方式:
override public uint GenTexture(Bitmap bmp)
{
uint texture;
GL.GenTextures(1, out texture);
//I disabled this line because I now bind the texture before drawing a geoset
//Anyway, uncommenting this line doesn't show a better result
//GL.BindTexture(TextureTarget.Texture2D, texture);
System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
bmp.UnlockBits(data);
//temp settings
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
return texture;
}
【问题讨论】:
-
您发布的代码似乎是有道理的,正如您假设可以在绘图调用之间更改制服并且可以为不同的纹理重用纹理单元,只要对于给定的绘制调用/着色器,您不需要超过一个。要么我遗漏了什么,要么问题出在其他地方,可能是你的纹理创建方式?
-
是的;您确定在 Draw() 中正确设置了 geoset.TextureID 吗?在 GenTexture 中编辑,在调用 texImage2d 之前绑定纹理非常重要,否则您将覆盖之前绑定的纹理而不是新的纹理
-
如果我中断 Draw 方法,我可以看到 geoset.TextureID 的不同值(用于生成纹理的材料数据也是正确的,即文件名......),但所有结果通过着色器渲染相同的纹理。 (请注意,使用标准 glEnable(TEXTURE_2D) 方法正确淹没了纹理)我取消注释 GenTexture 方法中的 BindTexture 调用,但没有明显变化。
-
我担心您代码中的第一个注释。你能进一步详细说明吗?如果 1 不起作用而所有其他值都起作用,那么您在代码中传递的实际值是多少?使用其他数字时您看到的纹理是什么?
-
最初,我遵循了一个教程 (opentk.com/node/2559),每个纹理使用一个纹理单元并将 Uniform 与纹理缓冲区 Id 绑定,这很方便,因为他只创建了 4 个纹理,并且可以为每个纹理映射 TextureUnit1 到 4 (以正确的顺序)。但是当纹理计数未确定时,这是不切实际的。在我的代码中,我不需要多个 TextureUnit,因为我不渲染多材质(至少目前不需要),所以我只使用 textureunit 的插槽 1(如果我保持默认 TU,则为零)。