OpenGL入门(四)之纹理Texture
本系列文章为Learn OpenGL个人学习总结!
OpenGL入门(一)之认识OpenGL和创建Window
OpenGL入门(二)之渲染管线pipeline,VAO、VBO和EBO
OpenGL入门(三)之着色器Shader
OpenGL入门(四)之纹理Texture
OpenGL入门(五)之Matrix矩阵操作和坐标系统
OpenGL进阶(一)之帧缓冲FrameBuffer
OpenGL进阶(二)之像素缓冲PixelBuffer
纹理
纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节!我们可以在一张图片上插入非常多的细节,这样就可以让物体非常精细而不用指定额外的顶点,来减小开销!
为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。
纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。
一个纹理坐标:
float texCoords[] = {0.0f, 0.0f, // 左下角1.0f, 0.0f, // 右下角0.5f, 1.0f // 上中
};
纹理环绕方式
当纹理坐标超出默认范围时,可以设置环绕方式来展示不同的视觉效果输出!默认为GL_REPEAT
,还有GL_MIRRORED_REPEAT
,GL_CLAMP_TO_EDGE
和GL_CLAMP_TO_BORDER
!
前边提到过纹理坐标的分量可以通过STPQ
访问:
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
纹理过滤
纹理像素(Texture Pixel):组成一张图片的无数个像素点
纹理坐标:设置的顶点数组
OpenGL以这个顶点的纹理坐标数据去查找纹理图像上的像素,然后进行采样提取纹理像素的颜色。那么就会有一个问题,在对应查找像素的时候,用什么方式去拿像素颜色,OpenGL提供了纹理过滤来帮助我们选择,这里有两个重要的选项!
- GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。
- GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。
当进行放大(Magnify)和缩小(Minify)操作的时候可以设置纹理过滤的选项:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //缩小
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //放大
多级渐变纹理
多级渐变纹理主要是用来解决物体远近,纹理大小,分辨率不同的问题!距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个,且节省内存!
注意: 多级渐远纹理主要是使用在纹理被缩小的情况下的:纹理放大不会使用多级渐远纹理。
另外:OpenGL提供glGenerateMipmap()
函数,在创建完一个纹理后调用它OpenGL就会为纹理图像创建一系列多级渐远纹理!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);...//创建纹理
glGenerateMipmap(GL_TEXTURE_2D);
加载和创建纹理
这里使用stb_image.h
库来加载图片!
https://github.com/nothings/stb
使用非常简单,在我们的cpp文件中添加:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
创建纹理:
int width, height, nrChannels;
//这里会拿到图像的宽高和颜色通道个数
unsigned char *data = stbi_load("../dependency/stb/container.jpg", &width, &height, &nrChannels, 0);//生成纹理
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);//绑定... //设置环绕和过滤/*** @brief 生成纹理* 第1个参数:指定纹理target* 第2个参数:指定多级渐远纹理的级别 0:基本级别* 第3个参数:纹理存储格式。 这里图像只有RGB* 第4,5个参数:纹理的宽高* 第6个参数:总设置为0(历史问题)* 第7,8个参数:源图像的格式和数据类型* 第9个参数:图像数据
*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);...
stbi_image_free(data);//释放图像内存
应用纹理
这里我们绘制一个矩形,并把图片纹理贴在矩形上
//绘制矩形+纹理float vertices[] = {// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上};const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""layout (location = 1) in vec3 aColor;\n""layout (location = 2) in vec2 aTexCoord;\n""out vec3 vertexColor;\n""out vec2 texCoord;\n""void main()\n""{\n"" gl_Position = vec4(aPos, 1.0);\n"" vertexColor = aColor;\n"" texCoord = aTexCoord;\n""}\0";const char *fragmentShaderSource = "#version 330 core\n""in vec3 vertexColor;\n" //接收顶点着色器中的输入变量(名称、类型相同) "in vec2 texCoord;\n" //接收纹理(名称、类型相同)"out vec4 color;\n""uniform sampler2D texture1;\n" //声明一个纹理采样器"void main()\n""{\n"" color = texture(texture1, texCoord) * vec4(vertexColor, 1.0);\n" //将输出颜色设置为纹理 第一个参数纹理采样器,第二个参数纹理坐标"}\0";...
GLSL内建的texture()
函数,可以得到一个纹理颜色,第一个参数纹理采样器,第二个参数纹理坐标。
这样我们就能绘制出一个正确的纹理图片了!
需要注意的点:
在前边我们了解了uniform
这个变量,这里在片段着色器中声明了一个采样器,但是在代码中却没有给它赋值,目前看工作正常,能够绘制出图片!这是因为OpenGL中有默认的纹理单元0,且这个纹理单元默认激活!
纹理单元
当我们需要绘制多个纹理时,就要使用纹理单元,把纹理单元赋值给采样器,就能够和纹理一一对应起来!
glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture);
激活一个纹理单元之后,调用glBindTexture
,就会把纹理绑定到当前已激活的纹理单元!
OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这在当我们需要循环一些纹理单元的时候会很有用。
修改一下我们的片段着色器:
const char *fragmentShaderSource = "#version 330 core\n""in vec3 vertexColor;\n" //接收顶点着色器中的输入变量(名称、类型相同) "in vec2 texCoord;\n" //接收纹理(名称、类型相同)"out vec4 color;\n""uniform sampler2D texture1;\n" //声明一个纹理采样器"uniform sampler2D texture2;\n" "void main()\n""{\n"" color = mix(texture(texture1, texCoord), texture(texture2, texCoord), 0.2) * vec4(vertexColor, 1.0);\n" //将输出颜色设置为纹理 第一个参数纹理采样器,第二个参数纹理坐标"}\0";...
//有两个纹理时,就需要设置纹理单元
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 0);//指定采样器属于哪个纹理单元
glUniform1i(glGetUniformLocation(shaderProgram, "texture2"), 1);...
//渲染
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
...
GLSL内建的mix
函数需要接受两个值作为参数,并对它们根据第三个参数进行线性插值。如果第三个值是0.0,它会返回第一个输入;如果是1.0,会返回第二个输入值。0.2会返回80%的第一个输入颜色和20%的第二个输入颜色,即返回两个纹理的混合色。
另外一个需要注意的问题:纹理上下颠倒了!这是因为OpenGL要求y轴0.0坐标是在图片的底部的,但是图片的y轴0.0坐标通常在顶部。
stb_image.h能够在图像加载时帮助我们翻转y轴,在加载前调用:
stbi_set_flip_vertically_on_load(true);
这时我们将得到两个纹理叠加的效果!
OpenGL入门(四)之纹理Texture相关推荐
- 【OpenGL】OpenGL入门之纹理(Texture)
目录 纹理 纹理环绕方式 纹理过滤 多级渐远纹理(Mipmap) 加载与创建纹理 stb_image.h 生成纹理 应用纹理 纹理单元 参考 纹理 在此之前,我们已经可以为每个顶点添加颜色来增加图 ...
- OpenGL从入门到精通--纹理
纹理 github源码仓库 opengl环境准备 opengl编程从入门到精通-hello,window OpenGL从入门到精通–你好三角形 OpenGL从入门到精通–着色器的使用 我们可以为每个顶 ...
- Learn OpenGL (四):纹理
为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分.这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采 ...
- OpenGL入门之纹理的使用
参考: https://learnopenglcn.github.io/01%20Getting%20started/06%20Textures/#_7 OpenGL超级宝典 纹理 纹理是一种能够应用 ...
- OpenGL入门学习
OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性. 1.与C语言紧密结合. 2.强大的可移植性. 3.高性能的图形渲染. 总之,OpenGL是一个很NB的图形 ...
- 最全面的openGL 入门学习
自己在找openGL学习资料的时候,找到此篇openGL入门学习(虽然不是移动开发,但给我提供了非常好的思路),所以转一下让更多人知道,本文来自http://www.cppblog.com/doing ...
- OpenGL入门学习 (转)
OpenGL入门学习 (转) 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜 ...
- OpenGL入门学习[三]
OpenGL入门学习[三] http://xiaxveliang.blog.163.com/blog/static/2970803420126246501930/ OpenGL入门学习[十一] 我们在 ...
- 【待完善】OpenGL入门学习
严正声明:本文转载自网络,但具体出处未知.如果有读者了解,请联系我更正. 为了阅读方便,我对文字格式进行了修改,并填补了缺少的图片. 我尊重每位作者的权益,如果本文存在侵权行为,请联系我删除并道歉. ...
最新文章
- 端到端对话模型新突破!Facebook发布大规模个性化对话数据库
- 手机用appnium,web自动化用eclips+webdriver2
- 开启Linux下Telnet服务
- Ubuntu下使用中文语言
- java后台开发实习--第一次面试
- Linux 基础学习大考核
- python去重复元素_python 去除单个list中的重复元素
- Longest Palindrome CodeForces - 1304B(思维)
- wordpress多站点主站调用分站最新文章_企业网站SEO最新的7个优化步骤!
- [Unity] Animation Blend Tree 中混合值变化时部分骨骼错误旋转 360 度的解决办法:将 Humanoid 改成 Generic
- php中背景图怎么设置不重复,css 图像不重复怎么设置
- VS2013密钥 VS2013专业版密钥 VS2013旗舰版密钥
- 判断单链表是否中心对称
- 怎么对文件夹名称进行编号排序
- 如何将Word转PDF?来看这几个方法
- ug中模型不见了怎么办_UG双击prt文件却打不开模型是怎么回事?来看看解决方案吧...
- vuepress-theme-reco + Github Actions 构建静态博客,部署到第三方服务器
- ESP32S2(12K)-DS18B20数码管显示温度
- 配置微信公众号业务域名,解决“非微信官方网页,请确认是否继续访问”问题
- 台式计算机用什么网卡,台式机怎样安装网卡驱动,教您电脑安装网卡驱动
热门文章
- 孵化器行业拓客的10个经典方法
- 浙江浙大中控技术前端面经
- 仙剑缘_仙剑缘手游最新单机版客户端下载-仙剑缘单机版v1.3.2 安卓版-腾牛安卓网...
- 视频转音频mp3软件
- android intent打开各种文件的方法
- ‘芯’系物联网,STM32物联网方案一览
- django模型ORM笔记
- 墨西哥奢华烈酒品牌Clase Azul品牌标识换新;麦当劳中国第十二次荣膺“中国杰出雇主”认证 | 知消...
- 尚硅谷Java入门视频教程第十七章——Java9Java10Java11新特性
- Java 人工智能编程