OpenGL入门002——顶点着色器和片段着色器

文章目录

  • 一些概念
    • 坐标转换阶段
    • 顶点着色器
    • 片段着色器
    • VBO
    • VAO
  • 实战
    • 简介
    • main.cpp
    • CMakeLists.txt
    • 最终效果

一些概念

坐标转换阶段

概述: 模型空间、世界空间、视图空间和裁剪空间是对象在3D场景中经历的不同坐标变换阶段。每个空间对应渲染管道的一个步骤,逐步将模型从其初始位置转换到最终屏幕上的位置

模型空间:

  • 定义:这是对象的本地坐标系,是模型创建时的坐标
  • 作用:模型空间定义了物体的基本形状和几何信息,不受场景中其他物体位置的影响。每个模型都有自己的模型空间坐标
  • 转换:通过模型矩阵,可以将模型空间的坐标转换为世界空间

世界空间:

  • 定义:这是整个场景的坐标系,所有模型在世界空间中都有唯一的位置和方向,可以视为“全局坐标系”
  • 作用:将所有对象放置在同一个坐标系统中,确保它们相对位置正确
  • 转换:通过应用视图矩阵,将世界空间的坐标转换为视图空间,视图矩阵通常基于摄像机的位置和方向

视图空间:

  • 定义:又称为“摄像机空间“,是以摄像机位置为原点的坐标系,此时场景中的所有对象都以摄像机为参考重新定位
  • 作用:使得所有对象相对于摄像机的位置和方向变得更直观,便于确定哪些对象可见、如何投影到屏幕
  • 转换:使用投影矩阵将视图空间转换为裁剪空间,这一步决定了图像的投影类型(如透视投影或正交投影)

裁剪空间:

  • 定义:应用投影变换后的空间,此时3D场景的坐标被转换为一个标准化的3D盒子,所有可见的坐标x,y,z值均被限制在-1到1之间
  • 作用:裁剪空间便于对视锥外部的物体进行裁剪,只保留可见部分。裁剪后的坐标将进行透视除法,映射到2D屏幕上的坐标,即归一化设备坐标
  • 转换:裁剪空间进一步转换为屏幕空间,经过视口变换,使坐标适配屏幕的分辨率和比例

顶点着色器

概述: 顶点着色器(Vertex Shader)是对输入的顶点进行处理,顶点是组成几何体的基本元素,比如三角形的每个角都是一个顶点

作用:

  • 顶点位置变换:顶点着色器通常会将顶点从模型空间(即对象的局部坐标系)转换到世界空间、视图空间,最后转换到裁剪空间,以便在屏幕上正确显示
  • 顶点属性处理:除了位置,顶点着色器还可以处理其他与顶点相关的属性,比如法线、纹理坐标、颜色等
  • 光照计算:在某些情况下,顶点着色器可以进行基础的光照计算,如使用法线来计算顶点的光照效果

输入: 顶点的坐标、法线、纹理坐标等数据

输出: 处理后的顶点坐标,如变换后的顶点位置和其他顶点属性,供后续的图形流水线使用

片段着色器

概述: 片段着色器(Framgment Shader)是屏幕上每个像素的潜在颜色值,在光栅化阶段之后,每个几何体被转换为一系列像素片段,片段着色器负责确定这些片段的最终颜色

作用:

  • 颜色计算:片段着色器通过对纹理、光照、材质等信息的处理,确定每个像素的颜色,它通常会结合插值后的顶点属性(如纹理坐标或颜色)进行复杂的颜色计算
  • 光照效果:片段着色器可以进行精确的光照计算,以便生成更逼真的阴影和高光效果
  • 纹理映射:片段着色器可以从纹理中采样,根据纹理坐标获取纹理颜色,并应用到片段上

输入: 每个片段的插值属性(如纹理坐标、颜色、发现等)

输出: 每个片段的最终颜色值,传递给屏幕或帧缓冲区

VBO

概述: VBO(Vertex Buffer Object)是一个存储在GPU内存中的缓冲区,用于存放顶点数据。通常,顶点数据包含顶点的坐标、颜色、法线、纹理坐标等信息。通过使用VBO,程序可以将这些顶点数据传输到GPU,这样GPU可以在渲染时快速访问它们,而不需要每帧都从CPU传输数据

关键步骤:

  • 创建VBO:使用glGenBuffers()创建一个VBO
  • 绑定VBO:使用glBindBuffer()绑定VBO,指定将要存储的缓冲数据类型(如顶点数据GL_ARRY_BUFFER)
  • 填充VBO:使用glBufferData()将顶点数据传输到VBO中

VAO

概述: VAO(Vertex Array Object)是一个用于保存VBO配置的对象,它记录了与绘制顶点相关的所有状态信息。VAO不仅仅是VBO的一个包装器,它还保存了顶点属性指针和启用状态。例如:每个顶点的布局、数据的解释方式(如步幅、偏移量),以及使用的VBO。使用VAO可以简化渲染过程,因为当VAO被绑定时,所有与其关联的VBO和顶点属性信息都会自动生效。

关键步骤:

  • 创建VAO:使用glGenVertexArrays()创建一个VAO
  • 绑定VAO:使用glBindVertexArray()绑定VAO
  • 设置顶点属性指针:使用glVertexAttribPointer()设置顶点属性指针(告诉OpenGL如何解释顶点数据)
  • 启用顶点属性:使用glEnableVertexAttribArray()启用顶点属性

实战

简介

怎么在vscode上使用cmake构建项目,具体可以看这篇Windows上如何使用CMake构建项目 - 凌云行者的博客

目的: 绘制一个三角形

环境:

  • 编译工具链:使用msys2安装的mingw-gcc
  • 依赖项:glfw3:x64-mingw-static,glad:x64-mingw-static(通过vcpkg安装)

main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>using std::cout;
using std::endl;// 屏幕宽度
const unsigned int SCR_WIDTH = 800;
// 屏幕高度
const unsigned int SCR_HEIGHT = 600;// 窗口大小改变的回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// 确保视口与新窗口尺寸匹配,注意在视网膜显示器上,宽度和高度会显著大于指定值glViewport(0, 0, width, height);
}// 处理输入
void process_input(GLFWwindow* window) {// 按下ESC键时进入if块if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)// 关闭窗口glfwSetWindowShouldClose(window, true);
}// 顶点着色器源码
const char *vertexShaderSource = "#version 330 core\n" // 指定了GLSL(OpenGL着色器语言)的版本"layout (location = 0) in vec3 aPos;\n" // 定义了一个输入变量aPos,它是一个vec3类型的变量, 并且指定了它的位置值为0, 这意味着顶点属性数组的第一个属性将被绑定到这个变量"void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" // 将输入的顶点位置aPos转换为一个四维向量,gl_Postion是OpengGL固定功能管线中用于存储顶点位置的变量"}\0";// 片段着色器源码
const char *fragmentShaderSource = "#version 330 core\n" // 指定了GLSL(OpenGL着色器语言)的版本"out vec4 FragColor;\n" // 定义了一个输出变量FragColor,它是一个vec4类型的变量,表示片段颜色,out关键字表示这个变量将输出到渲染管线的下一个阶段"void main()\n""{\n""   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" // 将输出颜色设置为橙色"}\n\0";int main() {// 初始化glfwglfwInit();// 设置opengl版本glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);// 使用核心模式:确保不使用任何被弃用的功能glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建glfw窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "I am window title", NULL, NULL);if (window == NULL) {cout << "Failed to create glfw window" << endl;// 终止GLFWglfwTerminate();return -1;}// 设置当前窗口的上下文glfwMakeContextCurrent(window);// 设置窗口大小改变的回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 加载opengl函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {cout << "Failed to initialize GLAD" << endl;return -1;}// 构建并编译顶点着色程序// 创建一个着色器对象,GL_VERTEX_SHADER表示顶点着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);// 将着色器源码附加到着色器对象上glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);// 编译着色器glCompileShader(vertexShader);// 检查着色器是否编译成功int success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n"<< infoLog << endl;}// 构建并编译片段着色器// 创建一个着色器对象,GL_FRAGMENT_SHADER表示片段着色器unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);// 将着色器源码附加到着色器对象上glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);// 编译着色器glCompileShader(fragmentShader);// 检查着色器是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"<< infoLog << endl;}// 创建着色器程序对象unsigned int shaderProgram = glCreateProgram();// 将着色器对象附加到着色器程序上glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);// 链接程序对象glLinkProgram(shaderProgram);// 检查链接是否成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n"<< infoLog << endl; }// 删除着色器对象glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 设置三角形的顶点数据float vertices[] = {-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f,  // 右下角0.0f, 0.5f, 0.0f    // 顶部};// 生成一个VAOunsigned int VAO;glGenVertexArrays(1, &VAO);// 绑定VAO,使其成为当前操作的VAOglBindVertexArray(VAO);// 生成一个VBOunsigned int VBO;glGenBuffers(1, &VBO);// 绑定VBO, 使其成为当前操作的VBO,GL_ARRAY_BUFFER表示顶点缓冲区glBindBuffer(GL_ARRAY_BUFFER, VBO);// 为当前绑定的VBO创建并初始化数据存储,GL_STATIC_DRAW表示数据将一次性提供给缓冲区,并且在之后的绘制过程中不会频繁更改glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 定义顶点属性的布局// - index:顶点属性的索引// - size:每个顶点属性的数量,每个顶点有三个分享// - type:数据类型// - normalized:是否将非浮点数值归一化// - stride:连续顶点属性之间的间隔// - pointer:数据在缓冲区中的偏移量glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);// 启用顶点属性数组glEnableVertexAttribArray(0);// 解绑VBOglBindBuffer(GL_ARRAY_BUFFER, 0);// 解绑VAOglBindVertexArray(0);// 循环渲染while (!glfwWindowShouldClose(window)) { // 检查是否应该关闭窗口// 处理输入process_input(window);// 清空屏幕所用的颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 清空颜色缓冲,主要目的是为每一帧的渲染准备一个干净的画布glClear(GL_COLOR_BUFFER_BIT);// 使用着色器程序glUseProgram(shaderProgram);// 绑定VAOglBindVertexArray(VAO);// 绘制三角形glDrawArrays(GL_TRIANGLES, 0 ,3);// 交换缓冲区glfwSwapBuffers(window);// 处理所有待处理事件,去poll所有事件,看看哪个没处理的glfwPollEvents();}// 删除VAOglDeleteVertexArrays(1, &VAO);// 删除VBOglDeleteBuffers(1, &VBO);// 删除着色器程序glDeleteProgram(shaderProgram);// 终止GLFW,清理GLFW分配的资源glfwTerminate();return 0;
}

CMakeLists.txt

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 设置项目名称
project(HelloTriangle)# vcpkg集成, 这里要换成你自己的vcpkg工具链文件和共享库路径
set(VCPKG_ROOT D:/software6/vcpkg/)
set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
set(CMAKE_PREFIX_PATH ${VCPKG_ROOT}/installed/x64-mingw-static/share)# 查找所需的包
find_package(glad CONFIG REQUIRED)
find_package(glfw3 CONFIG REQUIRED)# 添加可执行文件
add_executable(HelloTriangle main.cpp)# 链接所需的库
target_link_libraries(HelloTriangle PRIVATE glad::glad glfw)

最终效果

在这里插入图片描述

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

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

相关文章

使用 Elastic、OpenLLMetry 和 OpenTelemetry 跟踪 LangChain 应用程序

作者&#xff1a;来自 Elastic Bahubali Shetti Langchain 应用程序的使用正在增长。构建基于 RAG 的应用程序、简单的 AI 助手等的能力正在成为常态。观察这些应用程序更加困难。考虑到现有的各种选项&#xff0c;本博客展示了如何将 OpenTelemetry 检测与 OpenLLMetry 结合使…

【Linux】从零开始使用多路转接IO --- select

碌碌无为&#xff0c;则余生太长&#xff1b; 欲有所为&#xff0c;则人生苦短。 --- 中岛敦 《山月记》--- 从零开始认识五种IO模型 1 前言2 认识多路转接select3 多路转接select等待连接4 完善代码5 总结 1 前言 上一篇文章我们讲解了五种IO模型的基本概念&#xff0c;并…

客户端与微服务之间的桥梁---网关

当我们创建好了N多个微服务或者微服务的实例之后&#xff0c;每个服务暴露出不同的端口地址&#xff0c;一般对于客户端请求&#xff0c;只需要请求一个端口&#xff0c;要隔离客户端和微服务的直接关系&#xff0c;保证微服务的安全性和灵活性&#xff0c;避免敏感信息的泄露。…

docker部署nginx+nacos+redis+java镜像和容器

nginx镜像制作 Dockerfile内容&#xff1a; # 基础镜像 FROM nginx # author MAINTAINER ruoyi# 挂载目录 VOLUME /home/ruoyi/projects/ruoyi-ui # 创建目录 RUN mkdir -p /home/ruoyi/projects/ruoyi-ui # 指定路径 WORKDIR /home/ruoyi/projects/ruoyi-ui # 复制conf文件到路…

MiniWord

1.nuget 下载配置 2.引用 3. var value = new Dictionary<string, object>() { ["nianfen"] = nianfen, ["yuefen"] = yuefen, ["yuefenjian1"] = (int.Par…

SpringBoot篇(简化操作的原理)

目录 一、代码位置 二、统一版本管理&#xff08;parent&#xff09; 三、提供 starter简化 Maven 配置 四、自动配置 Spring&#xff08;引导类&#xff09; 五、嵌入式 servlet 容器 一、代码位置 二、统一版本管理&#xff08;parent&#xff09; SpringBoot项目都会继…

Jetson OrinNX平台CSI相机导致cpu load average升高问题调试

1. 前言 硬件: Orin NX JP: 5.1.2, R35.4.1 用v4l2-ctl --stream-mmap -d0 命令去获取相机数据时, 用top查看cpu使用情况, CPU占用率很低,但load average在1左右, 无任何程序运行时,load average 为0 用ps -aux 查看当前进程情况,发现有两个系统进程vi-output, …

Iceoryx2:高性能进程间通信框架(中间件)

文章目录 0. 引言1. 主要改进2. Iceoryx2 的架构3. C示例代码3.1 发布者示例&#xff08;publisher.cpp&#xff09;3.2 订阅者示例&#xff08;subscriber.cpp&#xff09; 4. 机制比较5. 架构比较6. Iceoryx vs Iceoryx2参考资料 0. 引言 Iceoryx2 是一个基于 Rust 实现的开…

获取Hive表备注

DESCRIBE EXTENDED 表名;先获取Detailed Table Information这行的data_type字段数据&#xff0c;进行正则匹配&#xff0c;拿到表备注&#xff0c;如下&#xff1a; String str ReUtil.get("parameters:\\{(?!.*?\\().*transient_lastDdlTime.*?comment(.*?)\\}&quo…

OTFS的基本原理(通俗易懂)

一、OTFS调制解调原理 Orthogonal Time Frequency Space Modulation | IEEE Conference Publication | IEEE Xplore OTFS原论文提出的方法可以概括为 可以概括为 Xdd (延迟多普勒域数据) ----> ISFFT(辛有限傅里叶变换) ---->海森堡变换 延迟多普勒域数据 …

数据结构与算法——Java实现 53.力扣938题——二叉搜索树的范围和

生命的意义 在于活出自我 而不是成为别人眼中的你 —— 24.11.3 938. 二叉搜索树的范围和 给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1&#xff1a; 输入&#xff1a;root [10,5,15,3,7,null,18], low 7, high 15 …

顺德自闭症全托管学校:专业照顾,细心呵护

在顺德及周边地区&#xff0c;寻找一所能够为自闭症儿童提供专业照顾与细心呵护的全托管学校&#xff0c;是许多家庭的迫切需求。自闭症儿童在社交、语言和行为上所面临的挑战&#xff0c;需要更为专业的教育环境和细致入微的关怀。而位于广州的星贝育园自闭症儿童寄宿制学校&a…

【react】基础知识点学习

1. 创建项目 npm install -g create-react-app npx create-react-app my-app cd my-app npm startindex.js为入口文件&#xff0c;App.js为根组件。 如何将react应用挂载在页面上&#xff1f; 将App组件渲染到id为root的DOM元素中 2. JSX JSX是|avaScript和XML(HTML)的缩写…

基于 JAVASSM 框架沙县小吃点餐系统

基于 JAVASSM 框架&#xff08;即 Java Spring Spring MVC MyBatis&#xff09;开发一个沙县小吃点餐系统。 步骤一&#xff1a;需求分析 明确系统需要实现的功能&#xff0c;比如&#xff1a; 用户注册和登录浏览菜单添加菜品到购物车下单并支付订单管理后台管理&#…

apt的编译安装(古老通讯)

Ubuntu系统的防火墙关闭&#xff1a; ufw disable 第一步&#xff1a;Ubuntu 安装依赖环境 apt -y install libpcre3-dev zlib1g-dev libssl-dev build-essential 如果出现无法下载则在末尾处假如 --fix missing如下图所示 出现下图则为安装成功 第二步&#xff1a; useradd…

基于微信小程序的校园失物招领系统的研究与实现(V4.0)

博主介绍&#xff1a;✌stormjun、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

有向无环图的拓扑排序——CSP-J1真题讲解

【题目】 考虑一个有向无环图&#xff0c;该图包括4条有向边&#xff1a;(1,2)&#xff0c;(1,3)&#xff0c;(2,4)&#xff0c;和(3,4)。以下哪个选项是这个有向无环图的一个有效的拓扑排序&#xff1f;&#xff08; &#xff09; A. 4, 2, 3, 1 B. 1, 2, 3, 4 C. 1, 2, 4…

selenium操作已开启的浏览器,方便调试

一、谷歌浏览器配置&#xff1a; 在所安装的谷歌下面&#xff0c;执行下面命令&#xff0c;打开谷歌浏览器&#xff0c;用来selenium的操作&#xff1a; 注意事项&#xff1a;端口需要不被占用&#xff0c;--user-data-dir"D:\workspace\chrome-data"这个路径需要有…

DAY75WEB 攻防-验证码安全篇接口滥用识别插件复用绕过宏命令填入滑块类

知识点&#xff1a; 1、验证码简单机制-验证码过于简单可爆破 2、验证码重复使用-验证码验证机制可绕过 3、验证码智能识别-验证码图形码被可识别 4、验证码接口调用-验证码触发接口可枚举 图片验证码-识别插件-登录爆破&接口枚举 验证码识别绕过等技术适用于&#x…

微信小程序生成二维码

目前是在开发小程序端 --> 微信小程序。然后接到需求&#xff1a;根据 form 表单填写内容生成二维码&#xff08;第一版&#xff1a;表单目前需要客户进行自己输入&#xff0c;然后点击生成按钮实时生成二维码&#xff0c;不需要向后端请求&#xff0c;不存如数据库&#xf…