opengl日记10-opengl使用多个纹理示例

news2024/12/23 12:52:12

文章目录

  • 环境
  • 代码
    • CMakeLists.txt文件内容不变。
    • fragmentShaderSource.fs
    • vertexShaderSource.vs
    • main.cpp
  • 总结

在这里插入图片描述

环境

  • 系统:ubuntu20.04
  • opengl版本:4.6
  • glfw版本:3.3
  • glad版本:4.6
  • cmake版本:3.16.3
  • gcc版本:10.3.0

在<opengl学习日记9-opengl使用纹理示例>的基础上,拓展使用多个纹理。

代码

CMakeLists.txt文件内容不变。

fragmentShaderSource.fs

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

uniform sampler2D texture1;
uniform sampler2D texture2;

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

vertexShaderSource.vs

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
        gl_Position = vec4(aPos, 1.0);
        ourColor = aColor;
        TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include "stbimage.h"

//#include <glm/glm.hpp>
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtc/type_ptr.hpp>

#include <iostream>
#include <fstream>
#include <iosfwd>
#include <sstream>
#include <string>

//定义窗口大小
int SCR_WIDTH = 800;
int SCR_HEIGHT = 600;

std::string readFile(const std::string filename)
{
    std::string data;
    data = readFile(filename.c_str());
    return data;
}

std::string readFile(const char* filename)
{
    std::string data;
    std::ifstream infile;
    infile.open(filename);
    std::stringstream neirong;
    neirong << infile.rdbuf();
    infile.close();
    data = neirong.str();
    return data;
}

int main()
{
    std::cout << "Hello World!" << std::endl;

    std::cout << "初始化" << std::endl;
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "transformtions", NULL, NULL);
    if (window == NULL) {
        std::cout << "创建窗口失败" << std::endl;
        return -1;
    }

    glfwMakeContextCurrent(window);
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        std::cout << "初始化glad失败" << std::endl;
        return -1;
    }

    std::cout << "顶点定义,VAO,VBO,EBO" << std::endl;
    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};

    //索引缓冲区
    unsigned int indices[] = {0, 1, 3,
                              1, 2, 3};

    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //定位点关系
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) (3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *) (6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    std::cout << "着色器定义" << std::endl;
    std::cout << "着色器定义:顶点着色器" << std::endl;
    std::string vertexShaderSource = readFile("vertexShaderSource.vs");
    const char *vertexShaderSourceCtr = vertexShaderSource.c_str();
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSourceCtr, NULL);
    glCompileShader(vertexShader);

    int success;
    char infolog[512] = {0};
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infolog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infolog << std::endl;
    }

    std::cout << "着色器定义:片段着色器" << std::endl;
    std::string fragmentShaderSource = readFile("fragmentShaderSource.fs");
    const char *fragmentShaderSourceCtr = fragmentShaderSource.c_str();
    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSourceCtr, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infolog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infolog << std::endl;
    }

    std::cout << "着色器定义:启用着色器程序" << std::endl;
    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infolog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infolog << std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    std::cout << "纹理定义" << std::endl;
    unsigned int texture1;
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1);

    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);

    stbi_set_flip_vertically_on_load(true);
    std::cout << "读取纹理图片" << std::endl;
    int width, height, nrChannels;
    unsigned char* texturesData = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
    if (texturesData) {
        //绑定和纹理图片数据结合
        glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGB,
            width,
            height,
            0,
            GL_RGB,
            GL_UNSIGNED_BYTE,
            texturesData);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cout << "读取图片数据错误" << std::endl;
    }
    stbi_image_free(texturesData);

    std::cout << "纹理定义2" << std::endl;
    unsigned int texture2;
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);

    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);

    std::cout << "读取纹理图片" << std::endl;
    //        int width, height, nrChannels;
    texturesData = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
    if (texturesData) {
        //绑定和纹理图片数据结合
        glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGBA,
            width,
            height,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            texturesData);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cout << "读取图片数据错误" << std::endl;
    }
    stbi_image_free(texturesData);

    glUseProgram(shaderProgram);
    glUniform1i(glGetUniformLocation((GLuint)shaderProgram,"texture1"),0);
    glUniform1i(glGetUniformLocation((GLuint)shaderProgram,"texture2"),1);

    std::cout << "绘制" << std::endl;
    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);

        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (const GLvoid *) 0);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    std::cout << "内存释放" << std::endl;
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);
    glfwTerminate();

    return 0;
}

总结

  1. 使用多个纹理,则需要定义多个纹理,读取多个图片数据
std::cout << "纹理定义" << std::endl;
    unsigned int texture1;
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1);

    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);

    stbi_set_flip_vertically_on_load(true);
    std::cout << "读取纹理图片" << std::endl;
    int width, height, nrChannels;
    unsigned char* texturesData = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
    if (texturesData) {
        //绑定和纹理图片数据结合
        glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGB,
            width,
            height,
            0,
            GL_RGB,
            GL_UNSIGNED_BYTE,
            texturesData);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cout << "读取图片数据错误" << std::endl;
    }
    stbi_image_free(texturesData);

    std::cout << "纹理定义2" << std::endl;
    unsigned int texture2;
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);

    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);

    std::cout << "读取纹理图片" << std::endl;
    //        int width, height, nrChannels;
    texturesData = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
    if (texturesData) {
        //绑定和纹理图片数据结合
        glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGBA,
            width,
            height,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            texturesData);
        glGenerateMipmap(GL_TEXTURE_2D);
    } else {
        std::cout << "读取图片数据错误" << std::endl;
    }
    stbi_image_free(texturesData);
  1. 一张图片纹理叠加在另一张图片纹理上,需要有透明通道,图片格式是png,所以在绑定png纹理图片是需要注意参数变化
glTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGBA,
            width,
            height,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            texturesData);

注意第三个参数和第七个参数,由GL_RGB变为GL_RGBA
3. 在绘制之前需要手动设置一次纹理对应的采样器

glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation((GLuint)shaderProgram,"texture1"),0);
glUniform1i(glGetUniformLocation((GLuint)shaderProgram,"texture2"),1);

这里需要注意,glUniform1i函数的书写是数字1,不是字母l
4. 在读取纹理之前,设置一下,可保持加载图像不上下颠倒

stbi_set_flip_vertically_on_load(true);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1532506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常见分布式ID解决方案

简介&#xff1a; 分布式ID解决方案是用于在分布式系统中生成唯一标识符的方案。常见的分布式ID解决方案可总结为3点&#xff1a;数据库方案、算法方案、开源组件方案。 分布式ID 分布式 ID&#xff08;Distributed ID&#xff09;是指在分布式系统中生成全局唯一的标识符&…

10000字!一文学会SQL数据分析

文章来源于山有木兮 原文链接&#xff1a;https://edu.cda.cn/goods/show/3412?targetId5695&preview0 第1节 SQL简介与基础知识 做数据分析的&#xff0c;为什么要写SQL&#xff1f; 没有数据的情况下&#xff0c;我们分析数据就像是巧妇难为无米之炊。因此&#xff0c…

【prometheus-operator】k8s监控redis

1、准备exporter https://github.com/oliver006/redis_exporter oliver006-redis_exporter-amd64.tar # 安装镜像 docker load -i oliver006-redis_exporter-amd64.tar # 上传镜像 docker tag oliver006/redis_exporter ip/monitor/redis_exporter:latest docker push ip/mo…

零基础入门数据挖掘系列之「建模调参」

摘要&#xff1a;对于数据挖掘项目&#xff0c;本文将学习如何建模调参&#xff1f;从简单的模型开始&#xff0c;如何去建立一个模型&#xff1b;如何进行交叉验证&#xff1b;如何调节参数优化等。 建模调参&#xff1a;特征工程也好&#xff0c;数据清洗也罢&#xff0c;都是…

强大的文本编辑器:Sublime Text for Mac注册激活版

Sublime Text for Mac是一款功能强大的文本编辑器&#xff0c;特别适合程序员和开发者使用。它提供了丰富的功能&#xff0c;如智能代码补全、语法高亮、自定义快捷键、项目管理、多行选择、自动保存等&#xff0c;以提高代码编写效率和舒适度。此外&#xff0c;Sublime Text还…

【鸿蒙HarmonyOS开发笔记】通知模块之发布基础类型通知,内含如何将图片变成PixelMap对象

通知简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知常见的使用场景&#xff1a; 显示接收到的短消息、即时消息等。 显示应用的推送消息&#xff0c;如广告、版本更新等。 显示当前正…

数字功放VS模拟功放,选择适合你的音频解决方案

数字功放和模拟功放是音频系统中常用的两种功放技术&#xff0c;适用于不同的音频应用&#xff0c;都具有各自的优势和特点。本文将为您详细介绍数字功放和模拟功放的差异&#xff0c;并帮助您找到适合自己的音频解决方案。 1、数字功放是一种利用数字信号处理技术的功放。它将…

Qt 坐标位置转换

Qt 坐标位置转换 文章目录 Qt 坐标位置转换常见的位置坐标转换Qt窗体中常用坐标的区别与获取途径当前光标相对于屏幕的绝对位置当前光标相对于当前窗口的位置鼠标事件发生的位置窗体的位置判断鼠标光标是否悬浮在某个子控件上 从事Qt快一年了 &#xff0c;在做坐标转换的时候容…

钡铼技术R40工业4G路由器加速推进农田水利设施智能化

钡铼技术R40工业4G路由器作为一种先进的通信设备&#xff0c;正在被广泛应用于各行各业&#xff0c;其中包括农田水利设施的智能化改造。通过结合钡铼技术R40工业4G路由器&#xff0c;农田水利设施可以实现更高效的管理和运营&#xff0c;提升农田灌溉、排水等工作效率&#xf…

OpenAI的GPT已达极限,更看好AI Agent

日前&#xff0c;比尔盖茨发表文章表示&#xff1a;AI Agent不仅会改变人与电脑的互动方式&#xff0c;或许还将颠覆软件行业&#xff0c;引领自输入命令到点击图标以来的最大计算机革命。 在数字化和技术创新的浪潮中&#xff0c;AI Agent作为一种前沿技术&#xff0c;正开启…

基于 HBase Phoenix 构建实时数仓(5)—— 用 Kafka Connect 做实时数据同步

目录 一、总体架构 二、安装配置 MySQL 1. 创建 mysql 用户 2. 建立 MySQL 使用的目录 3. 解压安装包 4. 配置环境变量 5. 创建 MySQL 配置文件 6. MySQL 系统初始化 7. 启动 mysql 服务器 8. 创建 dba 用户 三、配置 MySQL 主从复制 四、安装部署 Kafka Connector…

Docker常用命令!!!

一、docker基础命令 1、启动docker systemctl start docker 2、关闭docker systemctl stop docker 3、重启docker systemctl restart docker 4、docker设置随服务启动而自启动 systemctl enable docker 5、查看docker 运行状态 systemctl status docker 6、查看docker 版本号信…

ChatGPT在大气科学领域建模、数据分析、可视化与资源评估中的高效应用及论文写作

深度探讨人工智能在大气科学中的应用&#xff0c;特别是如何结合最新AI模型与Python技术处理和分析气候数据。课程介绍包括GPT-4等先进AI工具&#xff0c;旨在帮助学员掌握这些工具的功能及应用范围。课程内容覆盖使用GPT处理数据、生成论文摘要、文献综述、技术方法分析等实战…

Learn OpenGL 19 几何着色器

几何着色器 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader)&#xff0c;几何着色器的输入是一个图元&#xff08;如点或三角形&#xff09;的一组顶点。几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换。然而&#xff0c;几何着色器最有趣的地方…

IOS/Android App备案(uniapp)

IOS/App备案 IOS备案Android备案 IOS备案 准备好p12证书即可 链接: https://aitoolnav.caichuangkeji.com/#/AppMd5 Android备案 上DCLOUD开发者中心&#xff0c;找到相关应用后&#xff0c;直接查看证书即可获取到MD5 公钥&#xff1a;先根据上述页面下载证书&#xff0c;…

应急响应-Web2

应急响应-Web2 1.攻击者的IP地址&#xff08;两个&#xff09;&#xff1f; 192.168.126.135 192.168.126.129 通过phpstudy查看日志&#xff0c;发现192.168.126.135这个IP一直在404访问 &#xff0c; 并且在日志的最后几条一直在访问system.php &#xff0c;从这可以推断 …

Git原理与使用(一)

目录 前言 版本控制器 Linux下的Git的安装 Git的基本操作 创建Git本地仓库 配置Git 工作区、暂存区、版本库 添加与提交 查看.git文件 前言 我们可能要写多个文档对一个产品进行描述&#xff0c;但是一般情况下我们可能要写多个文档&#xff0c;比如&#xff1a; 初…

Rust Rocket简单入门

简介 Rust中最知名的两个web框架要数Rocket和Actix了&#xff0c;Rocket更注重易用性&#xff0c;Actix则更注重性能。这里只是了解一下Rust下的WebAPI开发流程&#xff0c;就学一下最简单的 Rocket。 Rocket 是一个用于 Rust 的异步 Web 框架&#xff0c;专注于可用性、安全性…

NCV4266ST50T3G线性稳压器芯片中文资料规格书PDF数据手册引脚图参数图片价格

产品概述&#xff1a; NCV4266 是一款集成了 150 mA 输出电流的低漏稳压器系列&#xff0c;可用于严酷汽车环境。它包括了较宽的运行温度范围和输出电压范围。该器件提供 3.3 V、5.0 V 固定电压版本&#xff0c;以及可调电压版本&#xff0c;输出电压准确度为 2%。它具有较高的…

web攻防——csrf,ssrf

csrf 当我们在访问自己的管理员系统的时候&#xff0c;打开别人发的钓鱼连接就会自动增加管理员&#xff08;前提&#xff0c;后台在登录状态&#xff09;当我们打开别人发的网站&#xff0c;就会触发增加管理员的数据包 假设我们要测试这个网站 看到这个&#xff0c;就得下载一…