纹理单元的理解

Shader中要用到纹理:

  uniform sampler2D texture1;

Main读取图片数据,创建了纹理:

  unsigned int texture1;

怎么把c++里加载的纹理传给shader程序里呢?

这就要用到纹理单元。

  1. glBindTexture(GL_TEXTURE_2D, texture1);

这条代码将纹理texture1传递给了正在使用的着色器程序里的uniform sampler2D texture1

中间隐含过程是,opengl有许多默认的纹理单元(GL_TEXTURE0,GL_TEXTURE1,GL_TEXTURE2~GL_TEXTUREn),

其中,默认激活的是纹理单元0——GL_TEXTURE0,上面的代码就把纹理传递给了这个默认激活的纹理单元0;

另一方面,在shader里声明的采样器——unigorm sampler,他会从一个特定的纹理单元里取得纹理数据,而这个特定的纹理单元是GL_TEXTURE0~n中的哪一个呢?

答案是,在shader里声明的每一个采样器,其默认对应的纹理单元是GL_TEXTURE0;

所以,使用上面的一行代码,其中的过程是这样的:

  1、没有选择激活纹理单元,所以使用默认的纹理单元0

  2、把纹理texture1传递给了纹理单元0

  3、没有设置shader里的采样器对应的纹理单元,所以采样器从默认的纹理单元0读取数据

这样会使shader里所有的采样器(如果声明多个的话)都从纹理单元0中获取纹理数据,很明显这样就会使声明的采样器都一样了。

但是我们声明多个采样器明显是想在一个着色器里使用多个不同的纹理,那么该怎么做?

着色器里有多个采样器,像是这样:

  1. #version core
  2. out vec4 FragColor;
  3.  
  4. in vec3 ourColor;
  5. in vec2 TexCoord;
  6.  
  7. uniform sampler2D texture1;
  8. uniform sampler2D texture2;
  9.  
  10. void main()
  11. {
  12. FragColor=mix(texture(texture1,TexCoord),texture(texture2,TexCoord),0.5);
  13. //FragColor=texture(texture1,TexCoord);
  14. }

回头看之前的步骤,只要完成原先省略做的事就好了

1、绑定纹理时,先选择激活相应的纹理单元

  1. glActiveTexture(GL_TEXTURE0);
  2. glBindTexture(GL_TEXTURE_2D, texture1);

2、设置shader里声明的采样器所对应的纹理单元

  1. glUniform1i(glGetUniformLocation(myShader.ID, "texture1"), );
  2. myShader.setInt("texture2", ); // 或者使用着色器类设置

两中方法,都是先找到shader中的采样器”texture1”/”texture2”的地址,然后设置其对应的纹理单元,0是指GL_TEXTURE0,1对应GL_TEXTURE1,2、3以此类推。

Texture类

模仿Shader类写了自己的Texture类(重复操作实在太多了

  1. class lxlTexture {
  2. public:
  3. unsigned int Id;
  4. lxlTexture(){}
  5. lxlTexture(const GLchar* texPath,GLint format) {
  6. glGenTextures(, &Id);
  7. glBindTexture(GL_TEXTURE_2D, Id);
  8.  
  9. // 为当前绑定的纹理对象设置环绕、过滤方式
  10. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  11. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  12. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  13. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  14. //读取图片文件
  15. int width, height, nrChannels;//颜色通道个数
  16. stbi_set_flip_vertically_on_load(false);
  17. unsigned char* data = stbi_load(texPath, &width, &height, &nrChannels, );
  18. //导入读取的图片文件数据,处理生成纹理
  19. glTexImage2D(GL_TEXTURE_2D, , format, width, height, , format, GL_UNSIGNED_BYTE, data);
  20. ////-解释-
  21. //上面把纹理绑定到了GL_TEXTURE_2D,现在这个参数选择了GL_TEXTURE_2D为目标,处理绑定在上面的纹理
  22. //参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
  23. //第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们也把纹理储存为RGB值。
  24. //第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
  25. //下个参数应该总是被设为0(历史遗留的问题)。
  26. //第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为char(byte)数组
  27. //最后一个参数是真正的图像数据。
  28.  
  29. //自动生成多级纹理
  30. glGenerateMipmap(GL_TEXTURE_2D);
  31. //释放
  32. stbi_image_free(data);
  33. std::cout << Id << std::endl;
  34. }
  35. void bindTexture(int num) {
  36. switch (num) {
  37. case :
  38. glActiveTexture(GL_TEXTURE0);
  39. break;
  40. case :
  41. glActiveTexture(GL_TEXTURE1);
  42. break;
  43. case :
  44. glActiveTexture(GL_TEXTURE2);
  45. break;
  46. case :
  47. glActiveTexture(GL_TEXTURE3);
  48. break;
  49. case :
  50. glActiveTexture(GL_TEXTURE4);
  51. break;
  52. case :
  53. glActiveTexture(GL_TEXTURE5);
  54. break;
  55. case :
  56. glActiveTexture(GL_TEXTURE6);
  57. break;
  58. case :
  59. glActiveTexture(GL_TEXTURE7);
  60. break;
  61. default:
  62. std::cout << "纹理绑定支持0~7"<<std::endl;
  63. }
  64. glBindTexture(GL_TEXTURE_2D, Id);
  65. }
  66. void SetWrap(GLint pname) {
  67. if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname==GL_CLAMP_TO_BORDER) {
  68. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, pname);
  69. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, pname);
  70. }
  71. else {
  72. std::cout << "输入不是设置环绕方式" << std::endl;
  73. }
  74. }
  75. void SetWrapS(GLint pname) {
  76. if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname == GL_CLAMP_TO_BORDER) {
  77. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, pname);
  78. }
  79. else {
  80. std::cout << "输入不是设置环绕方式" << std::endl;
  81. }
  82. }
  83. void SetWrapT(GLint pname) {
  84. if (pname == GL_REPEAT || pname == GL_MIRRORED_REPEAT || pname == GL_CLAMP_TO_EDGE || pname == GL_CLAMP_TO_BORDER) {
  85. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, pname);
  86. }
  87. else {
  88. std::cout << "输入不是设置环绕方式" << std::endl;
  89. }
  90. }
  91.  
  92. void SetFilterMag(GLint pname) {
  93. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, pname);
  94. }
  95. void SetFilterMin(GLint pname) {
  96. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  97. }
  98. };

使用

  1. //初始化
  2. mytexture1 = Texture("Resource/Texture/container.jpg",GL_RGB);
  3. mytexture2 = Texture("Resource/Texture/awesomeface.png",GL_RGBA);
  4. //传递
  5. mytexture1.bindTexture();
  6. mytexture2.bindTexture();

OpenGL笔记(4)纹理的更多相关文章

  1. Opengl ES之纹理贴图

    纹理可以理解为一个二维数组,它可以存储大量的数据,这些数据可以发送到着色器上.一般情况下我们所说的纹理是表示一副2D图,此时纹理存储的数据就是这个图的像素数据. 所谓的纹理贴图,就是使用Opengl将 ...

  2. opengl笔记——旋转,一段代码的理解

    重看:opengl笔记——OpenGL好资料备忘 在找到这段代码,对理解opengl旋转很有帮助 ... glPushMatrix(); // initialze ModelView matrix g ...

  3. Android OpenGL ES(八)----纹理编程框架

    1.把纹理载入进OpenGL中 我们的第一个任务就是把一个图像文件的数据载入到一个OpenGL的纹理中. 作为開始.让我们又一次舍弃第二篇的框架.又一次创建一个程序,新建一个util工具包,在该包下创 ...

  4. Linux OpenGL 实践篇-5 纹理

    纹理 在之前的实践中,我们所渲染的物体的表面颜色都是纯色或者根据顶点位置计算出的一个颜色,这种方式在表现物体细节方面是比较吃资源的,因为我们每增加一个细节,我们就需要定义更多的顶点及其属性.所以美术人 ...

  5. OpenGL 多线程共享纹理

    1:opengl 多线程共享纹理纹理: //解码时候使用opengl进行绘制,需要构建队列和两个线程,分别用于解码数据并且填充纹理和渲染. 主线程常见两个共享上下文: main() { ⋯⋯⋯⋯ gH ...

  6. OpenGL笔记(一) 绘制三角形

    GLTools: 一些有用且可复用的函数 GLEW: OpenGL API的一些扩展机制 GLUT: OpenGL Utility toolkit, OpenGL跨平台相关,隐藏平台相关细节 RC代表 ...

  7. OpenGL学习笔记(3) 纹理

    关于纹理 一般游戏里的物体不一定都是纯色的物体,物体上面会有一些图片贴在上面,比如墙壁,箱子,地板,可以看到砖头.木板和大理石组成的图片,要把图片贴到计算机里的几何图形的话,就要把图片的颜色采样贴到几 ...

  8. OpenGL超级宝典笔记——深度纹理和阴影 【转】

    目录[-] 光源视角 新型的纹理 深度纹理的大小 首先绘制阴影 然后是光照 投影阴影贴图 阴影比较 之前我们介绍过简单的把物体压平到投影平面来制造阴影.但这种阴影方式有其局限性(如投影平面须是平面). ...

  9. OpenGL的glTexCoord2f纹理坐标配置

    纹理坐标配置函数,先看定义: void glTexCoord2f (GLfloat s, GLfloat t); 1.glTexCoord2f()函数 有两个参数:GLfloat s, GLfloat ...

随机推荐

  1. Spring(002)-创建rest服务

    1.创建基于get参数的rest服务 @RestController @RequestMapping("/action") public class GetController { ...

  2. Linux安装docker(ubuntu16.04和centos7.4)

    ubuntu16.04版本 1.安装依赖 sudo apt-get install apt-transport-https ca-certificates software-properties-co ...

  3. pom文件详解(自己没看过)

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  4. Python进阶-Ⅸ 递归 二分法

    1.算法 英文名:algorithm,就是计算的方法.# 是截止到目前,人类发现的针对特定场景的,最优的计算方法.是人类智慧的结晶.# 人脑是复杂的,电脑其实很简单.比如: 999 * 123 人类会 ...

  5. Task异常捕获的几种方式

    在调用Task的Wait()方法或Result属性处会抛出Task中的异常. 但是如果没有返回结果,或者不想调用Wait()方法,该怎么获取异常呢? 可以使用ContinueWith()方法 var ...

  6. Flask-Login中装饰器@login_manager.user_loader的作用及原理

    Flask-Login通过装饰器@login_required来检查访问视图函数的用户是否已登录,没有登录时会跳转到login_manager.login_view = 'auth.login'所注册 ...

  7. 11/7 <Dynamic Programming>

    62. Unique Paths 方法一: 二位数组 而这道题是每次可以向下走或者向右走,求到达最右下角的所有不同走法的个数.那么跟爬梯子问题一样,需要用动态规划 Dynamic Programmin ...

  8. Vs code背景图

    写前端代码时,用过webstorm,sublime,vscode,最终还是选择了vscode,主要原因是(好看)简洁的编程环境,丰富的插件功能.不过无论是哪一个编辑器,长时间看着黑色/白色的背景难免单 ...

  9. 牛客CSP-S提高组赛前集训营1———2019.10.29 18:30 至 22:00

    期望得分:100+0+10 实际得分:40+0+0 考炸了... T1:题目链接 究竟为什么会这样,,, 仔细研读我的丑代码 发现... 枯辽.... #include<cstdio> # ...

  10. mac 浏览器(chrome, safari)信任自签名证书

    mac 浏览器(chrome, safari)信任自签名证书 自签名证书创建了一个 https 服务器,但是浏览器访问的时候总是不信任证书,感觉很烦,就想如果信任这个证书就不会有问题了. 方法1: 直 ...