OpenGL排坑指南—贴图纹理绑定和使用

一、前言

OpenGL学习 的纹理这一章中讲述了纹理贴图的使用方式,主要步骤是先创建一个纹理的对象,和创建顶点VAO类似,然后就开始绑定这个纹理,最后在循环中使用,有时候可能还要用到激活纹理单元的函数。然而,对于何时应该激活如何和shader里的纹理编号进行绑定没有详细的说明,导致在使用的时候产生了不少困惑。比如何时应该绑定,绑定后的索引如何匹配。

在这一章的第一个效果案例:显示一个带贴图纹理的箱子时只用到了绑定而没有用到激活,部分主要代码如下:即使这样,在shader中也能让贴图获取到这里写进去的数据。

cpp 复制代码
   while (!glfwWindowShouldClose(window))
    {
        -----
        glBindVertexArray(VAO);
        -----
    }

其shader的片段着色器代码如下,这个片段的"texture1"数据在上述循环中并未明确指定传过来的

cpp 复制代码
// texture sampler
uniform sampler2D texture1;

void main()
{
	FragColor = texture(texture1, TexCoord);
}

这是我第一个猜想:如果C++代码中只创建了一个纹理数据,不用激活和指定传输到片段着色器中,使用" glBindTexture(GL_TEXTURE_2D, texture);"函数可以默认将片段着色器中的贴图都填充同样的数据。带着这个猜想我开始验证我的想法。

二、实现

2.1、如果只有一个贴图数据,默认传输到片段着色器的每一个"uniform sampler2D"

其他都不变,我只修改片段着色器代码,首先我创建了两个uniform sampler2D变量,分别为texture1和texture2,然后稍微修改其片段着色器代码如下:如果这两个片段都获取到同样的数据则显示两倍的贴图效果,如果不相等则屏幕显示一个绿色的片。

cpp 复制代码
// texture sampler
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{

	vec4 tempColor1=texture(texture1, TexCoord);
	vec4 tempColor2=texture(texture2,TexCoord);
	if(tempColor1==tempColor2)
	{
		FragColor =tempColor1+tempColor2;
	}
	else
		FragColor=vec4(0,1,0,1);
}

试验的结果得到如下,明显比之前要亮一点,很显然两个贴图都获取到循环里传输过来的贴图数据,而且是一样的。
图2.1.1

2.2、如果C++代码只有一个贴图,但我就想传给片段着色器中指定的纹理

**1)只激活第一个并不管用:**这个时候我尝试使用激活,我只激活第一个试试,结果和图2.1.1是一样的,两个纹理还是被传输一样的纹理数据。

cpp 复制代码
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture);

**2)两个都激活,但只赋值给第二个贴图,结果两个都没有得到数据:**再尝试不同的激活方式,保持只传输一个纹理数据的逻辑,将第一个激活然后不赋值,激活第二个并且赋值贴图纹理,理论上这样应该是可以的啊,结果变成了黑的,如图2.2.1所示

cpp 复制代码
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, 0);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture);

图2.2.1

是不是两个贴图都没有获取到数据呢,我还不确定,再修改片段着色器判断一下:如果确实没有获取到数据则让屏幕显示"黄色"的箱子,结果如图2.2.2所示,确实显示了黄色的箱子,这说明我们

cpp 复制代码
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{

	vec4 tempColor1=texture(texture1, TexCoord);
	vec4 tempColor2=texture(texture2,TexCoord);
	if(tempColor1==tempColor2)
	{
		if(tempColor1==vec4(0,0,0,1))
		{
			FragColor=vec4(1,1,0,1);
		}
		else
			FragColor =tempColor1+tempColor2;
	}
	else
		FragColor=vec4(0,1,0,1);
}

图2.2.2

贴图数据始终还是以默认的方式进行传输,第二个激活并传输并没有奏效,始终还是第一个激活才奏效。

3)再增加一个贴图的索引,结果可以精准的将数据传输到第二个贴图:代码如下,在激活之前给

cpp 复制代码
		ourShader.setInt("texture2", 1);
		// bind Texture
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, 0);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture);

当前的shader指定一个索引1,并且这个索引数值"1"一定要和后续绑定的"GL_TEXTURE1"对应,最后得到的结果是绿色的一个箱子,说明在片段着色器中贴图的数据不一样了。

三、总结

3.1、如果只有一个贴图数据,在C++中只用默认的绑定操作,默认传输到片段着色器的每一个"uniform sampler2D"变量中。

3.2、如果要指定传输给片段着色器中一定要使用激活贴图 glActiveTexture(GL_TEXTURE1);和 设置索引号ourShader.setInt("texture2", 1);同时使用,并且激活的序列号和设置索引值要相等,只使用索引也不行。

3.3、激活和设置索引以及绑定都要在循环里每帧都使用,尝试将索引设置不放在循环里也不行。

3.4、激活和绑定都是默认的情况下,设置索引没有任何作用,可以不用。 比如在文章后续做一个2D游戏中的一篇文章里渲染精灵 其最后的游戏类代码中初始化时设置了纹理"image"的数据索引为0,但是其着色器代码中并没有"image"这个变量,而且此处

cpp 复制代码
void Game::Init()
{
   ......
    ResourceManager::GetShader("sprite").Use().SetInteger("image", 0);
    .......
}

无论你修改"image"为任何变量,比如"imageeeeeeeeeeeeeeee",它依然能显示正确的结果,因为这一篇文章中就是一个默认的贴图,而且激活和绑定都是执行默认的0,这里的索引就不会发生任何作用。

相关推荐
mxwin1 天前
Unity Shader 逐像素光照 vs 逐顶点光照性能与画质的权衡策略
unity·游戏引擎·shader·着色器
mxwin1 天前
Unity URP 全局光照 (GI) 完全指南 Lightmap 采样与实时 GI(光照探针、反射探针)的 Shader 集成
unity·游戏引擎·shader·着色器
mxwin1 天前
Unity URP 溶解效果基于噪声纹理与 clip 函数实现物体渐隐渐显
unity·游戏引擎·shader
mxwin2 天前
Unity Shader 顶点色:利用模型顶点颜色传递渲染数据
unity·游戏引擎·shader
摄影图2 天前
隐私保护数字盾牌设计图片素材 满足各类网络安全创作需求
网络·安全·aigc·贴图·插画
mxwin2 天前
Unity URP 下的 GPU Instancing减少 DrawCall 的关键技术
unity·游戏引擎·shader
mxwin2 天前
Unity URP SRP Batcher 完全指南 URP/HDRP 下的核心批处理机制,大幅降低 CPU 开销
unity·游戏引擎·shader·单一职责原则
新缸中之脑2 天前
HDRI-Generator: 环境贴图生成AI
人工智能·贴图
mxwin2 天前
Unity Mask 贴图:用一张纹理的 RGBA 通道分别控制 PBR 材质参数
unity·材质·贴图
mxwin3 天前
Unity Shader UV 坐标与纹理平铺Tiling & Offset 深度解析
unity·游戏引擎·shader·uv