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

文章目录

  • 环境
  • 代码
    • 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);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Hadoop】Hadoop 编译源码

目录 为什么要源码编译Hadoop 编译源码1前期工作准备2jar 包安装2.1安装 Maven2.2安装 ant2.3安装 glibc-headers 和 g2.4安装 make 和 cmake2.5安装 protobuf2.6安装 openssl 库2.7安装 ncurses-devel 库 3编译源码3.1解压源码到 /opt/ 目录3.2 进入到 hadoop 源码主目录 /opt…

课时70:流程控制_for循环_嵌套循环

2.4.4 嵌套循环 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 简介 这里的嵌套实践&#xff0c;与选择语句的嵌套实践基本一致&#xff0c;只不过组合的方式发生了一些变化。常见的组合样式如下&#xff1a;for嵌套for语句for …

【Android】【Bluetooth Stack】蓝牙电话本协议分析(超详细)

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】专栏会持续更新中.....敬请期待&#xff01; 目录 1. 协议简述 1.1 PBAP…

Qt笔记 事件处理_鼠标事件

什么是事件&#xff1f; 点击鼠标左键&#xff0c;双击鼠标左键&#xff0c;鼠标来回移动&#xff0c;按下键盘按钮&#xff0c;这些都是事件。 那么事件的响应机制是什么样的呢&#xff1f; 首先main函数中有一个QApplication&#xff0c;其作用是创建一个应用程序对象&…

11种创造型设计模式(下)

观察者模式 我们可以比喻观察者模式是一种类似广播的设计模式 介绍 观察者模式&#xff1a;对象之间多对一依赖的一种设计方案&#xff0c;被依赖的对象是Subject&#xff0c;依赖的对象是Observer&#xff0c;Subject通知Observer变化。 代码 说明&#xff1a; WeatherStat…

手撕算法-判断是不是二叉搜索树

题目描述 分析 二叉搜索树的特性就是中序遍历是递增序。既然是判断是否是二叉搜索树&#xff0c;那我们可以使用中序递归遍历。只要之前的节点是二叉树搜索树&#xff0c;那么如果当前的节点大于上一个节点值那么就可以向下判断。 如果有出现当前的节点小于上一个节点值&…

Host xxx1 has more disk space than database expected (xxx2 GB > xxx3 GB)

在nova-compute.log中有时会看到日志“Host xxx1 has more disk space than database expected (xxx2 GB &#xff1e; xxx3 GB)”类似日志。 查看下源码&#xff0c;如下&#xff1a; 分析&#xff1a; 定时任务更新主机资源到内存或者对象中&#xff0c;当执行检测的定时任务…

颠覆传统:Web3如何塑造未来的数字经济

引言 近年来&#xff0c;随着数字化时代的到来&#xff0c;互联网已经成为人们生活中不可或缺的一部分。然而&#xff0c;随着技术的不断发展和社会的不断变迁&#xff0c;传统的Web2模式逐渐显露出一些弊端&#xff0c;如数据垄断、隐私泄露等问题&#xff0c;这促使人们寻求…

Linux账号管理与ACL权限设置

文章目录 Linux的账户和用户组用户标识符&#xff1a;UID与GID用户账号用户组&#xff1a;有效与初始用户组groups&#xff0c;newgrp 账号管理新增与删除用户&#xff1a;useradd、相关配置文件、passwd、usermod、userdel用户功能&#xff1a;id、finger、chfn、chsh新增与删…

【文件操作和IO】

文件操作和IO 1.文件2. 硬盘上文件的目录结构3. 文件路径4. 文件重要分类&#xff1a;5. Java中操作文件5.1 Java对于文件操作的API5.2 Java中使用File类来进行文件操作5.3 File类属性5.4 构造方法5.5 方法&#xff1a; 6. 文件内容的读写 -- 文件流&#xff08;数据流&#xf…

C++ List底层实现

文章目录 前言成员变量成员函数迭代器self& operator()前置self operator(int)后置self operator--()前置--self operator--(int)后置--bool operator!(const self & tmp)判断是否相等T* operator*() 解引用操作 list()初始化iterator begin()iterator end()const_iter…

视频无水印批量下载软件|抖音视频提取工具

视频无水印批量下载软件 在当今社交媒体充斥着大量优质视频内容的时代&#xff0c;很多用户都希望能够轻松下载自己喜爱的视频进行收藏或分享。为了满足用户的需求&#xff0c;我们特别推出了一款专业的视频无水印批量下载软件&#xff0c;让您可以方便快捷地获取喜爱的视频内容…

鸿蒙Harmony应用开发—ArkTS-转场动画(共享元素转场)

当路由进行切换时&#xff0c;可以通过设置组件的 sharedTransition 属性将该元素标记为共享元素并设置对应的共享元素转场动效。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 属性 名称参数参数描述…

springboot企业级抽奖项目业务二(用户模块)

书接上回&#xff0c;梅开二度 开发流程 该业务基于rouyi生成好了mapper和service的代码&#xff0c;现在需要在controller层写接口 实际操作流程&#xff1a; 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口…

练习 9 Web [SUCTF 2019]CheckIn (未拿到flag)

上传图片格式的木马文件&#xff1a; 返回 <? in contents!,存在PHP代码检测 上传非图片格式文件&#xff1a; 返回 不允许非image 修改木马PHP代码规避检测 <? ?> 改为 < script language“php”>< /script ><?php eval($_POST[shell]);?>…

鸿蒙实战开发:【相机和媒体库】

介绍 在ArkTS中调用相机拍照和录像&#xff0c;以及如何使用媒体库接口进行媒体文件的增、删、改、查操作。本示例用到了 权限管理能力相机模块能力接口图片处理接口音视频相关媒体业务能力接口媒体库管理接口设备信息能力接口文件存储管理能力接口弹窗能力接口 效果预览 首…

virtualBox镜像复制

镜像复制 有一个镜像后&#xff0c;图方便&#xff0c;想直接使用这个vdi文件&#xff0c;但vdi有个uuid值&#xff0c;同一个虚拟机中不能同时存在两个同样的uuid的介质的&#xff0c;普通的复制文件所得到的uuid是一样的 &#xff0c;所以需要用到自带的方法复制vdi文件&…

SpringCloud中的@EnableDiscoceryClient和@EnableFeignClients注解的作用解析、RPC远程过程调用

目录 EnableDiscoveryClient 服务发现的核心概念 服务注册中心 EnableDiscoveryClient注解的作用 服务心跳健康检查 使用示例 EnableFeignClients Feign简介 EnableFeignClients注解的作用 RPC&#xff08;Remote Procedure Call&#xff09; 参考链接 Spring Cloud…

Cache缓存:HTTP缓存策略解析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【Kotlin】扩展属性、扩展函数

1 类的扩展 Kotlin 提供了扩展类或接口的操作&#xff0c;而无需通过类继承或使用装饰器等设计模式&#xff0c;来为某个类添加一些额外的属性或函数&#xff0c;我们只需要通过一个被称为扩展的特殊声明来完成。通过这种机制&#xff0c;我们可以将那些第三方类不具备的功能强…