OpenGL之多纹理(Sampler类型)绑定着色器及纹理单元详解

最近一直在写着色器,对OpenGL的API都不熟悉了,这两天刚好要处理好几张纹理,所以又来写纹理绑定这一块,之前一直默认纹理单元,简单就能加载一张纹理,就没太在意,现在要搞好几张纹理,突然有点懵了,因此摸索了下,整理出这篇文章,让自己以后还能记得。

标题限定为Sampler类型,即采样器类型,像在计算着色器里还存在image类型的,准确说是图像,绑定方法又不一样,所以作此区分。

一、纹理的创建

创建纹理是最基础的一步,网上搜一大把,我就简单贴一下吧。

​
	int TextureID[2];
    //创建纹理
	glGenTextures(1, &uTexture[0]);
	glBindTexture(GL_TEXTURE_2D, uTexture[0]);
	//    为当前绑定的纹理对象设置环绕、过滤方式
	//    将纹理包装设置为GL_REPEAT(默认包装方法)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	//    设置纹理过滤参数
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// 加载并生成纹理
	int width, height, nrChannels;
	stbi_set_flip_vertically_on_load(true); //告诉stb_image.h在y轴上翻转加载的纹理。

	unsigned char* data = stbi_load("D:\\My Document\\1213.jpg", &width, &height, &nrChannels, 0);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

​

上面的过程是加载一张图片作为纹理,有时候我们做离屏渲染或者存储处理图时可能需要创建一张空图片的纹理,那么就不用加载图片了,将data改为NULL即可。

二、纹理的绑定

有了纹理,要用的话,自然得绑定了。纹理与着色器绑定一般有两种方式:

1.纹理对象绑定纹理单元,纹理单元绑定着色器

这种方式一般解释为代码就是这样:

	glUseProgram(programObject[0]); //使用着色器,这里省略加载部分,自己摸索
	glActiveTexture(GL_TEXTURE0); //激活0号纹理单元
	glBindTexture(GL_TEXTURE_2D, uTexture[0]); //将0号纹理对象绑上
	glUniform1i(glGetUniformLocation(programObject[0], "uTexture1"), 0);//将0号纹理单元绑定到shader中的纹理变量,假设是uTexture1,根据着色器中纹理变量名字来的

	glActiveTexture(GL_TEXTURE1);//激活1号纹理单元
	glBindTexture(GL_TEXTURE_2D, uTexture[1]);//将1号纹理对象绑上
	glUniform1i(glGetUniformLocation(programObject[0], "uTexture2"), 1);//将1号纹理单元绑定到shader中的纹理变量uTexture2

这样就通过纹理单元绑定到着色器,这段代码一般写在渲染里的,因为OpenGL代码的规则是认上下文的,提前绑定容易遗留问题。

2.关于纹理,纹理单元和着色器的关系

上面代码可能没解释得很清楚,其实三者还算相互独立。每一个着色器上可以支持16个纹理单元,就相当于着色器上的Sampler采样器,一般默认是0号单元,16个Sampler采样器表示什么意思呢?意思是这个着色器内部可以传入16个纹理,正常我们一个着色器需要就几张纹理,基本够用。不同的着色器可以用相同的纹理单元号,但同一个着色器里的两个纹理要用两个纹理单元。纹理与纹理单元基本没关系,根据上面代码,我们在使用着色器时,先激活某号纹理单元,再把需要的纹理(可以随意指定)绑到纹理单元上,最后把着色器里采样器的变量名与激活的纹理单元号绑定,这样就完成了纹理的传入

三、渲染时的使用

代码详细表示:

        glUseProgram(programObject[0]); // 必须先使用着色器
		glBindVertexArray(VAOId[0]); // 使用VAO信息,绑定顶点数据
		glActiveTexture(GL_TEXTURE0); //激活纹理单元,绑的哪个就激活哪个
		glBindTexture(GL_TEXTURE_2D, uTexture[0]); //绑定纹理对象
		glActiveTexture(GL_TEXTURE1); //激活纹理单元,绑的哪个就激活哪个
		glBindTexture(GL_TEXTURE_2D, uTexture[1]); //绑定纹理对象
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

四、总结

写得可能有些粗糙,但都是我通过实践尝试出来的经验,有错误的地方麻烦指出,就算错也要错的明白不是。

结尾:希望我们一起探讨,我也是个初学者,我们一起进步!

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值