• OpenGL原理与实践——核心模式(三):Texture-纹理系统理论与应用


    目录

    初识——纹理系统是什么?怎么用?

    Texture —— UV坐标系统

    Texture Wrapping:UV超过了[0,1]怎么办?

    Texture Filter:UV经过计算得到的是浮点数怎么办?

    在OpenGL中该怎么做呢?

    Texture Unit——OpenGL提供了多个Texture锚定点,显示多个纹理图

    整理代码、建立ffImage类

    Texture纹理的应用


    初识——纹理系统是什么?怎么用?

    Texture —— UV坐标系统

    • UV坐标定义到每一个顶点上
    • 通过插值,到纹理图片上采样
    • 得到像素点颜色 

    Texture Wrapping:UV超过了[0,1]怎么办?

    OpenGL提供了几种方式,如图

    Texture Filter:UV经过计算得到的是浮点数怎么办?

    Texture Filter的结果以及相关情况下的设置

    也就是说在纹理变小的时候,采用Nearest进行采样;纹理变大的时候,采用Linear方式采样。

    在OpenGL中该怎么做呢?

    ①在C++当中创建Texture,并且绑定到系统中进行渲染和数据传递

    ②在shader中进行处理 

    Texture Unit——OpenGL提供了多个Texture锚定点,显示多个纹理图

    整理代码、建立ffImage类

    新建ffImage.h及ffImage.cpp

    1. //ffImage.h
    2. #pragma once
    3. #include "Base.h"
    4. class ffImage
    5. {
    6. private:
    7. int m_width;
    8. int m_height;
    9. int m_picType;
    10. ffRGBA* m_data;
    11. public:
    12. int getWidth()const { return m_width; }
    13. int getHeight()const { return m_height; }
    14. int getPicType()const { return m_picType; }
    15. ffRGBA* getData()const { return m_data; }
    16. ffRGBA getColor(int x, int y)const {
    17. if (x<0 || x>m_width - 1 || y<0 || y>m_height - 1) {
    18. return ffRGBA(0, 0, 0, 0);
    19. }
    20. return m_data[y * m_width + x];
    21. }
    22. ffImage(int _width = 0, int _height = 0, int _picType = 0, ffRGBA* _data = nullptr) {
    23. m_width = _width;
    24. m_height = _height;
    25. m_picType = _picType;
    26. int _sumSize = m_width * m_height;
    27. if (_data && _sumSize) {
    28. m_data = new ffRGBA[_sumSize];
    29. memcpy(m_data, _data, sizeof(ffRGBA) * _sumSize);
    30. }
    31. else {
    32. m_data = nullptr;
    33. }
    34. }
    35. ~ffImage() {
    36. if (m_data) {
    37. delete[]m_data;
    38. }
    39. }
    40. public:
    41. static ffImage* readFromFile(const char* _fileName);
    42. };
    1. //ffImage.cpp
    2. #include "ffImage.h"
    3. #define STB_IMAGE_IMPLEMENTATION
    4. #include "stb_image.h"
    5. ffImage* ffImage::readFromFile(const char* _fileName)
    6. {
    7. int _picType = 0;
    8. int _width = 0;
    9. int _height = 0;
    10. //stbimage读入图片是反过来的
    11. stbi_set_flip_vertically_on_load(true);
    12. unsigned char* bits = stbi_load(_fileName, &_width, &_height, &_picType, STBI_rgb_alpha);
    13. ffImage* _image = new ffImage(_width, _height, _picType, (ffRGBA*)bits);
    14. stbi_image_free(bits);
    15. return _image;
    16. }

    Texture纹理的应用

    同样的,建立一个句柄:

    unsigned int _texture = 0;

    纹理的相关处理:

    1. void initTexture() {
    2. _pImage = ffImage::readFromFile("res/wall.jpg");
    3. //纹理绑定
    4. glGenTextures(1, &_texture);
    5. glBindTexture(GL_TEXTURE_2D, _texture);
    6. //纹理属性设置
    7. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    8. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    9. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    10. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    11. //读入图片数据
    12. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,_pImage->getData());
    13. }

    同样的,需要在顶点数组中添加UV信息:

    1. float vertices[] = {
    2. //顶点信息 颜色信息 纹理信息
    3. 0.5f, 0.5f, 0.0f, 1.0f,0.0f,0.0f, 1.0f,1.0f,
    4. 0.5f, -0.5f, 0.0f, 0.0f,1.0f,0.0f, 1.0f,0.0f,
    5. -0.5f, -0.5f, 0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,
    6. -0.5f, 0.5f, 0.0f, 0.0f,1.0f,0.0f, 0.0f,1.0f
    7. };

    同样的,新建一个锚点(layout):

    1. //对哪个锚点进行操作:layout=0的锚点,读3个顶点,类型为float,不需要归一化,每次步长为3个float大小,从0处开始读
    2. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    3. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float)*3));
    4. glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float)*6));

    同样的,激活这个锚点2

    1. //打开锚点:激活
    2. glEnableVertexAttribArray(0);
    3. glEnableVertexAttribArray(1);
    4. glEnableVertexAttribArray(2);

    同样的,更新一下shader

    1. //vertexShader.glsl
    2. #version 330 core
    3. layout (location = 0) in vec3 aPos;
    4. layout (location = 1) in vec3 aColor;
    5. layout (location = 2) in vec2 aUV;
    6. out vec4 outColor;
    7. out vec2 outUV;
    8. void main()
    9. {
    10. gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    11. outColor = vec4(aColor, 1.0f);
    12. outUV = aUV;
    13. };
    1. //fragmentShader.glsl
    2. #version 330 core
    3. out vec4 FragColor;
    4. in vec4 outColor;
    5. in vec2 outUV;
    6. uniform sampler2D outTexture;
    7. void main()
    8. {
    9. FragColor = texture(outTexture, outUV);
    10. };

    这里值得注意一点,在fragmentShader中的sampler2D,这里并没有通过C++的代码传入数据,因为我们只用了一张纹理贴图,默认texture unit为0,而这个sampler2D也是默认取为0的texture unit

    渲染结果:

    混合结果:

    1. //fragmentShader.glsl
    2. #version 330 core
    3. out vec4 FragColor;
    4. in vec4 outColor;
    5. in vec2 outUV;
    6. uniform sampler2D outTexture;
    7. void main()
    8. {
    9. FragColor = texture(outTexture, outUV) * outColor;
    10. };

  • 相关阅读:
    【TypeScript】什么是字面量类型、类型推断、类型拓宽和类型缩小?
    断点检测学习
    Python基础复习-面向对象的编程
    mysql 客户端SSL错误2026 (HY000)
    从谷歌CRE谈起,运维如何培养服务意识?
    【工作技术栈】【源码解读】一次springboot注入bean失败问题的排查过程
    安装thinkphp6并使用多应用模式,解决提示路由不存在解决办法
    jxTMS设计思想之web界面
    Python---break关键字对for...else结构的影响
    MyBatis教程
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/128026551