【OpenGL学习】(七)纹理单元

【OpenGL学习】(七)纹理单元

OpenGL的纹理单元(Texture Unit)是GPU中用于管理和组织纹理资源的逻辑单元,它允许开发者在渲染过程中同时使用多个纹理,并通过采样器(Sampler)在着色器中访问这些纹理。每个纹理单元可以独立绑定不同的纹理对象(如2D纹理、立方体贴图等),并配置各自的纹理参数(如过滤模式、环绕方式等),从而在着色器中通过指定的纹理单元索引(如GL_TEXTURE0、GL_TEXTURE1等)访问对应的纹理数据。

默认情况下,第一个激活的纹理单元是 0(即 GL_TEXTURE0),因此在只使用单个纹理时,无需显式指定其他纹理单元。通过激活和配置多个纹理单元,可在着色器中实现多纹理的应用。

给定两个纹理图像:

纹理图像1纹理图像2
在这里插入图片描述在这里插入图片描述

本项目实现将两个纹理图像进行线性插值,并映射到正方形上。

项目链接:https://github.com/BinaryAI-1024/OpenGLPorjects/tree/master/textures_combined
顶点着色器texture.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);
}

片段着色器texture.fs:

#version 330 core
out vec4 FragColor;in vec3 ourColor;
in vec2 TexCoord;// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;void main()
{// 在两个纹理之间进行线性插值 (80% container, 20% awesomeface)FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}

textures_combined.cpp:

#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "stb_image.h"
#include <filesystem.h>
#include <shader_s.h>#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{// 初始化GLFWglfwInit();// 配置GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);  // OpenGL主版本号3.3glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 苹果系统兼容性设置
#endif// 创建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 初始化GLADif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 创建着色器程序Shader ourShader("texture.vs", "texture.fs");// 设置顶点数据和属性指针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 VBO, VAO, 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);// 加载和创建纹理unsigned int texture1, texture2;stbi_set_flip_vertically_on_load(true); // 垂直翻转图像// ========== 纹理1配置 ==========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); // 放大过滤// 加载图像数据int width, height, nrChannels;unsigned char* data = stbi_load(FileSystem::getPath("resources/container.jpg").c_str(),&width, &height, &nrChannels, 0);if (data){// 将图像数据上传到GPUglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data); // 释放图像内存// ========== 纹理2配置 ==========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);// 加载带有透明通道的图像data = stbi_load(FileSystem::getPath("resources/awesomeface.png").c_str(),&width, &height, &nrChannels, 0);if (data){// 注意PNG图像有透明通道,所以使用GL_RGBA格式glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);ourShader.use();// 为着色器中的uniform采样器变量texSampler1,texSampler2指定对应的纹理单元索引glUniform1i(glGetUniformLocation(ourShader.ID, "texSampler1"), 0);     // 纹理单元0:GL_TEXTURE0glUniform1i(glGetUniformLocation(ourShader.ID, "texSampler2"), 1);     // 纹理单元1:GL_TEXTURE1// 渲染循环 while (!glfwWindowShouldClose(window)){glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绑定纹理到对应的纹理单元glActiveTexture(GL_TEXTURE0);  // 激活纹理单元0glBindTexture(GL_TEXTURE_2D, texture1);glActiveTexture(GL_TEXTURE1);   // 激活纹理单元1glBindTexture(GL_TEXTURE_2D, texture2);// 绘制图形ourShader.use();glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);glfwTerminate();return 0;
}void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}

项目运行结果:

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

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

相关文章

Ubuntu 下降 Linux Kernel 的版本备忘

此处以 ubuntu 22.04 为示例系统&#xff0c;来降低其 Linux kernel 的版本。 1. 降低 Linux kernel 版本 在 Ubuntu 22.04 上降低 Linux 内核版本的步骤如下所示。 步骤 1&#xff1a;检查当前内核版本 uname -r 确认当前运行的内核版本。 步骤 2&#xff1a;查看已安装的…

Python 数据分析与机器学习入门 (八):用 Scikit-Learn 跑通第一个机器学习模型

引言&#xff1a;初识 Scikit-Learn Scikit-learn 是 Python 机器学习领域的黄金标准库。它构建在 NumPy, SciPy 和 Matplotlib 之上&#xff0c;提供了大量用于分类、回归、聚类和降维等任务的算法。Scikit-learn 广受欢迎的原因在于其三大核心优势&#xff1a; 一致的 API 设…

FPGA芯片的配置方法

FPGA芯片的配置方法 文章目录 FPGA芯片的配置方法1. FPGA配置概述2. 主动配置模式3. 被动配置模式4. JTAG配置模式5. 总结 1. FPGA配置概述 当我们在PC机上的FPGA软件集成开发环境中完成我们的设计后&#xff0c;必须通过某种形式将其映射到FPGA芯片硬件中&#xff0c;这样FPG…

通过python+openCV实现对图片中箭头方向的判断

在项目中遇到一个需求,需要对图片中的箭头方向进行判断,本来是使用YOLOv8算法来实现的,但是发现YOLO的效果对箭头的识别效果很差,不管是分类算法还是检测算法,效果都不理想,因此试一试通过openCV对箭头方向进行判断,发现效果还可以。 下面附上完整的代码和原理。 文章目…

React 第六十六节Router中 StaticRouter使用详解及注意事项

前言 StaticRouter 是 React Router 为服务器端渲染&#xff08;SSR&#xff09;提供的专用路由组件。它允许在服务器环境中处理路由逻辑&#xff0c;确保服务器和客户端渲染结果一致。下面我将详细解释其用途、原理并提供完整的代码示例。 一、StaticRouter 的核心用途 服务…

嵌入模型与大语言模型的区别:从结构到应用的深度解析

嵌入模型与大语言模型的区别&#xff1a;从结构到应用的深度解析 在当今自然语言处理&#xff08;NLP&#xff09;技术蓬勃发展的背景下&#xff0c;嵌入模型&#xff08;Embedding Model&#xff09; 和 大语言模型&#xff08;Large Language Model, LLM&#xff09; 成为了…

el-date-picker赋值不成功

vue使用element 的时间组件el-date-picker赋值不成功&#xff0c;点击后才回显数据 解决: 组件未渲染完成之前赋值了&#xff0c;在onMounted函数内赋值&#xff0c;或者在确保组件已经渲染后赋值

深入浅出JavaScript中的私有变量与特权方法

深入浅出JavaScript中的私有变量与特权方法&#xff1a;封装的艺术 在JavaScript的开发实践中&#xff0c;私有变量和特权方法是实现数据封装和代码安全性的核心工具。它们不仅帮助我们隐藏敏感数据&#xff0c;还能通过闭包和作用域机制构建更健壮的代码结构。本文将从基础概…

ReactNative【实战系列教程】我的小红书 2 -- 快捷登录、手机号密码登录

最终效果 技术要点 用户协议 – 打开本地浏览器 点击后&#xff0c;直接打开本地浏览器浏览网页 // 最终需修改为 《用户协议》 的网址Linking.openURL("https://www.baidu.com");手机号输入框的 344 展示 onChangeText{(text: string) > {setPhone(formatPhone(…

【赵渝强老师】OceanBase数据库从零开始:Oracle模式

这里我们来介绍一下新上线的课程《OceanBase数据库从零开始&#xff1a;Oracle模式》&#xff0c;本门课程共11章。 视频讲解如下 【赵渝强老师】OceanBase从零开始&#xff08;Oracle模式&#xff09; 下面详细介绍一下每一章的主要内容&#xff1a; 第01章-OceanBase的体系…

Flink核心功能与运行流程详解

目录 一、背景 二、图构建 三、任务执行流程&#xff08;yarn per-job模式&#xff09; 3.1 Flink组件 3.2 执行流程 四、分布式调度 4.1 TM的slot 4.2 TM的slot的CPU与内存 4.3 节点的部署 4.4 节点的状态 4.5 节点部署流程 五、数据传输 5.1 内存分配 5.2 传输…

linux 操作docker的基本命令docker仓库

基本操作命令 docker run --nametest-host -itd centos7.6 /bin/bash 通过镜像创建容器 登录容器 [rootdocker101 ~]# docker exec -it test-host /bin/bash &#xff08;exec是执行&#xff0c;i是交互式。t叫tty&#xff09; 或者container id [rootdocker101 ~]# doc…

Netty学习路线图 - 第四阶段:Netty基础应用

Netty学习路线图 - 第四阶段&#xff1a;Netty基础应用 &#x1f4da; Netty学习系列之四 本文是Netty学习路线的第四篇&#xff0c;我们将用大白话讲解Netty的基础应用&#xff0c;带你从理论走向实践。 写在前面 大家好&#xff01;在前面三篇文章中&#xff0c;我们学习了J…

开源项目推荐:MCP Registry——管理MCP服务器的利器

探索MCP Registry:未来模型上下文协议的核心注册服务 随着人工智能技术的迅速发展,机器学习模型的管理和配置变得愈发重要。今天,我们将探索一个颇具潜力的开源项目——MCP Registry。这是一个由社区驱动的注册服务,专为模型上下文协议(Model Context Protocol,简称MCP)…

Spring Boot 统一功能处理:拦截器详解

一、拦截器核心概念 作用&#xff1a;拦截器是 Spring 框架提供的核心功能&#xff0c;用于在请求处理前后执行预定义逻辑&#xff0c;实现统一处理&#xff08;如登录校验、日志记录等&#xff09;。 核心方法&#xff1a; public class LoginInterceptor implements Handl…

在docker容器中安装docker服务,基于fuse-overlayfs进行overlay挂载,而不是vfs

1、docker 安装 正常安装docker软件&#xff0c;运行docker时&#xff0c;会提示&#xff1a;No docker socket 服务 2、启动docker服务&#xff08;包含守护进程&#xff09; systemctl start docker #dockerd &if ! ps aux | grep -v grep | grep -q "dockerd&qu…

虚拟机配置注意事项

一.VM大部分产品免费&#xff0c;遇到付费的要斟酌一下 在小编之前的文章中有简单下载VM的教程VMwareWorkstPro安装-CSDN博客 二.配置过程中的设置大部分都可以在配置完成后更改 例如下图设备所涉及到的&#xff0c;都是可以更改设置的 三.电脑关机时&#xff0c;要注意先把…

openGL+QT快速学习和入门案列

openGLQT快速学习和入门案列

深度学习03 人工神经网络ANN

什么是神经网络 人工神经网络&#xff08; Artificial Neural Network&#xff0c; 简写为ANN&#xff09;也简称为神经网络&#xff08;NN&#xff09;,是一种模仿生物神经网络结构和功能的计算模型,人脑可以看做是一个生物神经网络,由众多的神经元连接而成.各个神经元传递复…

Linux中部署Jenkins保姆间教程

本文将以docker的方式&#xff0c;讲述如何部署Jenkins 一、拉取Jenkins镜像 1.1 最新版Jenkins介绍 最新版Jenkins地址&#xff1a;Download and deploy 当前最新版的如下图所示&#xff1a; 1.2 各版本支持的JDK版本 地址如下&#xff1a;Java Support Policy 如果你安装…