openGL学习(Shader)

认识Shader

在计算机图形学中,Shader(着色器)是一种运行在 GPU(图形处理单元)上的程序,用于控制图形渲染过程中顶点和像素的处理。着色器是 OpenGL、Direct3D、Vulkan 等图形 API 的核心组成部分,它们允许开发者自定义渲染管线的各个阶段,从而实现高度自定义的视觉效果。

着色器类型

  1. 顶点着色器(Vertex Shader)

    • 处理每个顶点的数据。

    • 可以进行顶点位置的变换、纹理坐标的生成、光照计算等。

    • 通常用于实现 3D 变换、动画效果等。

  2. 片段着色器(Fragment Shader)

    • 处理每个像素(或片段)的数据。

    • 决定每个像素的颜色和透明度。

    • 用于实现光照、阴影、纹理映射、后处理效果等。

  3. 几何着色器(Geometry Shader)

    • 在顶点着色器和片段着色器之间处理整个图元(如点、线、三角形)。

    • 可以生成新的顶点或图元。

    • 用于实现高级的几何变换和效果。

  4. 张量着色器(Tessellation Shader)

    • 包括两个阶段:域着色器(Domain Shader)和原语生成着色器(Hull Shader)。

    • 控制细分曲面的生成和处理。

    • 用于实现复杂的曲面细分和建模。

  5. 计算着色器(Compute Shader)

    • 执行通用计算任务,不直接参与渲染管线。

    • 可以并行处理大量数据。

    • 用于实现物理模拟、图像处理、AI 计算等。

着色器编写

着色器通常使用 GLSL(OpenGL Shading Language)或 HLSL(High-Level Shader Language)等语言编写。以下是一个简单的 GLSL 顶点着色器示例:

#version 330 core// in代表输入 
//vec3代表是一个三维向量(xyz)
// aPos 是我们自己取的名字
// layout(location = n) 代表告诉vertexShaser去vao的第n个属性描述中去取数据。
// gl_Position 是glsl的内置变量,负责向后续阶段输出顶点位置处理的结果。 一般为NDC坐标。
//vec4代表 四维向量。layout(location = 0) in vec3 aPos;  // 顶点位置void main() {gl_Position = vec4(aPos, 1.0);  // 将顶点位置传递给片段着色器
}

以及一个简单的 GLSL 片段着色器示例:

#version 330 core//out代表输出变量
//vec4代表四维向量,rgba,红绿蓝,透明度
//FragColor 是最终输出的变量
out vec4 FragColor;  // 输出颜色void main() {FragColor = vec4(1.0, 0.5, 0.2, 1.0);  // 设置像素颜色为橙色
}

着色器编译和链接

在 OpenGL 中,着色器需要经过编译和链接才能使用。以下是一个简化的流程:

  1. 编写着色器代码:使用 GLSL 编写顶点着色器和片段着色器代码。

  2. 创建着色器对象:使用 glCreateShader 创建着色器对象。

  3. 编译着色器:使用 glShaderSourceglCompileShader 编译着色器代码。

  4. 创建程序对象:使用 glCreateProgram 创建程序对象。

  5. 附加着色器:使用 glAttachShader 将编译好的着色器附加到程序对象。

  6. 链接程序:使用 glLinkProgram 链接程序对象。

  7. 使用程序:使用 glUseProgram 使用链接好的程序对象。

着色器的优势

  1. 高度自定义:开发者可以自定义渲染管线的各个阶段,实现复杂的图形效果。

  2. 性能优化:着色器在 GPU 上运行,可以利用 GPU 的并行处理能力,提高渲染性能。

  3. 跨平台兼容性:着色器语言(如 GLSL)在不同的图形 API 和硬件平台上具有较好的兼容性。

总之,着色器是现代图形渲染中不可或缺的一部分,它们为开发者提供了强大的工具来实现高度自定义的视觉效果。

void  prepareShader()
{cout << "prepareShader()" << endl;//1.完成vs和fs,并且装字符串const char* vertexShaderSource ="#version 460 core\n""layout(location = 0) in vec3 aPos;\n""void main()\n""{\n""gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);\n""}\n\0";const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n""FragColor = vec4(1.0f,0.5f,0.2f,1.0);\n""}\n\0";//2创建Shader程序(vs和fs)GLuint vertex, fragment;vertex = glCreateShader(GL_VERTEX_SHADER);fragment = glCreateShader(GL_FRAGMENT_SHADER);//3为shader程序输入Shader代码glShaderSource(vertex, 1, &vertexShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。glShaderSource(fragment, 1, &fragmentShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。int success = 0;char infoLog[1024];//4 执行Shader编译glCompileShader(vertex);//5 检查是否正确编译glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Vertex Shaser Complie: " << infoLog << endl;}//4 执行fragment编译glCompileShader(fragment);//5 检查是否正确编译glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Fragment Shader Complie: " << infoLog << endl;}// 创建Program壳子GLuint program = 0;program =	glCreateProgram();//将编译后的结果放进ProgramglAttachShader(program, vertex);glAttachShader(program, fragment);// 执行program链接操作,形成最终的shader程序。glLinkProgram(program);//检查链接错误glGetProgramiv(program, GL_LINK_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetProgramInfoLog(program, 1024, NULL, infoLog); //获取日志信息cout << "Error Program Link: " << infoLog << endl;}//清理glDeleteShader(vertex);glDeleteShader(fragment);}
#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h" 
#include "glad/glad.h"   //需要先引用glad的头文件。 用于加载 OpenGL 函数指针
#include "GLFW/glfw3.h" // 用于创建窗口和处理输入。	
#include <assert.h>
#include "wrapper/checkerror.h"
#include "application/application.h"
using namespace std;/*
* 目标:学习DrawArray进行绘制
* 1.采用GL_TRANGLES进行绘制三角形
* 这里可以缩放窗体,实验NDC坐标的作用。
* prepareVAOForGLTriangles:构建四个顶点的VAO
*  
*/GLuint vao, program;void prepareSingleBuffer()
{//1.准备顶点位置数据与颜色数据float positions[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f,};float colors[] = {1.0f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,1.0f,};//2.为位置&颜色数据各自生成一个VBOGLuint posVbo = 0, colorVbo = 0;GL_CALL(glGenBuffers(1, &posVbo));GL_CALL(glGenBuffers(1, &colorVbo));//3.给两个分开的VBO各自填充数据//positions填充数据GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, posVbo));GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW));//colors填充数据GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, colorVbo));GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW));//生成VAO并且绑定GLuint vao = 0;glGenVertexArrays(1, &vao);glBindVertexArray(vao);// 分别将数据放入VAO//描述位置属性glBindBuffer(GL_ARRAY_BUFFER, posVbo);//只有绑定了vbo,下面的属性描述才于此有关系glEnableVertexAttribArray(0);glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),0);glBindBuffer(GL_ARRAY_BUFFER, colorVbo);//只有绑定了vbo,下面的属性描述才于此有关系glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);glBindVertexArray(0); //将VAO进行解绑}void prepareInterLeavedBuffer()
{cout << "prepareInterLeavedBuffer()" << endl;float vertices[] = {-0.5f,-0.5f,0.0f,1.0f,0.0f,0.0f,0.5f,-0.5f,0.0f,0.0f,1.0f,0.0f,0.0f,0.5f,0.0f,0.0f,0.0f,1.0f};//2.为位置&颜色数据各自生成一个VBOGLuint vbo = 0;GL_CALL(glGenBuffers(1, &vbo));GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));//生成VAO并且绑定//GLuint vao = 0;glGenVertexArrays(1, &vao);glBindVertexArray(vao);// 分别将数据放入VAO//描述位置属性glBindBuffer(GL_ARRAY_BUFFER, vbo);//只有绑定了vbo,下面的属性描述才于此有关系glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);//颜色属性//glBindBuffer(GL_ARRAY_BUFFER, vbo);//只有绑定了vbo,下面的属性描述才于此有关系glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),(void*)(3*sizeof(float)));glBindVertexArray(0); //将VAO进行解绑
}void prepareVAOForTriangles()
{cout << "prepareVAOForTriangles()" << endl;//目前暂时不用颜色float vertices[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f,0.5f,0.5f,0.0f,0.8f,0.8f,0.0f,0.8f,0.0f,0.0f};//2.生成一个VBOGLuint vbo = 0;GL_CALL(glGenBuffers(1, &vbo));GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo));GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));//生成VAO并且绑定glGenVertexArrays(1, &vao);glBindVertexArray(vao);// 分别将数据放入VAO//描述位置属性glBindBuffer(GL_ARRAY_BUFFER, vbo);//只有绑定了vbo,下面的属性描述才于此有关系glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glBindVertexArray(0); //将VAO进行解绑
}void  prepareShader()
{cout << "prepareShader()" << endl;//1.完成vs和fs,并且装字符串const char* vertexShaderSource ="#version 460 core\n""layout(location = 0) in vec3 aPos;\n""void main()\n""{\n""gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);\n""}\n\0";const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n""FragColor = vec4(1.0f,0.5f,0.2f,1.0);\n""}\n\0";//2创建Shader程序(vs和fs)GLuint vertex, fragment;vertex = glCreateShader(GL_VERTEX_SHADER);fragment = glCreateShader(GL_FRAGMENT_SHADER);//3为shader程序输入Shader代码glShaderSource(vertex, 1, &vertexShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。glShaderSource(fragment, 1, &fragmentShaderSource, NULL); //字符串用\0进行结尾,不需要告诉他长度。int success = 0;char infoLog[1024];//4 执行Shader编译glCompileShader(vertex);//5 检查是否正确编译glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Vertex Shaser Complie: " << infoLog << endl;}//4 执行fragment编译glCompileShader(fragment);//5 检查是否正确编译glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetShaderInfoLog(vertex, 1024, NULL, infoLog); //获取日志信息cout << "Error Fragment Shader Complie: " << infoLog << endl;}// 创建Program壳子//GLuint program = 0;program =	glCreateProgram();//将编译后的结果放进ProgramglAttachShader(program, vertex);glAttachShader(program, fragment);// 执行program链接操作,形成最终的shader程序。glLinkProgram(program);//检查链接错误glGetProgramiv(program, GL_LINK_STATUS, &success);if (!success) // 0有问题,非0没有问题{glGetProgramInfoLog(program, 1024, NULL, infoLog); //获取日志信息cout << "Error Program Link: " << infoLog << endl;}//清理glDeleteShader(vertex);glDeleteShader(fragment);}void render()
{//GL_CALL( glClear(1) );//加上gl_call如果产生错误可以打印出来,虽然vs智能提示有问题GL_CALL(glClear(GL_COLOR_BUFFER_BIT));//渲染操作//1. 使用当前的programglUseProgram(program);//绑定当前的vaoglBindVertexArray(vao);//发出绘制指令//绘制三角形// 如果点数不够,就会连到0,0点  (123 和456)绘制两组三角形glDrawArrays(GL_TRIANGLES, 0, 6);//绘制的模式// GL_TRIANGLES 绘制三角形//		默认以三个点绘制一组三角形,不够三个点就不显示//	GL_TRIANGLE_STRIP://		末尾点数为偶数【n-2 n-1 n】,基数【n-1 n-2 n】 n从0开始//		并且会复用之前的点//	GL_TRIANGLE_FAN:以扇形序列v0为起点,连接三角形。// GL_LINES:绘制直线// GL_LINE_STRIP//	 }void onResize(int width,int height)
{GL_CALL(glViewport(0, 0, width, height));cout << "onResize " << endl;
}void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;//更新窗体的大小glViewport(0, 0, width, height);}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码		 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;if (app->init(800,600) == -1){return -1;}//设置监听帧缓冲窗口大小回调函数。//glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);//glfwSetKeyCallback(win, keyCallback);app->setResizeCallBack(onResize);app->setkeyCallBack(keyCallback);//设置OpenGL视口以及清理颜色glViewport(0,0,800,600);glClearColor(0.2f,0.3f,0.3f,1.0f);prepareShader();prepareVAOForTriangles();// 3. 执行窗体循环// while (app->update() == 0 ){render();}// 4. 退出程序前做相关清理app->destroy();cout << "===================================" << endl;//const double M_PI = 3.14159265358979323846;//double radians = M_PI / 2; // 90度,转换为弧度//double sineValue = sin(radians);//std::cout << "sin(" << radians << ") = " << sineValue << std::endl;//system("pause");return 0;
}

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

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

相关文章

webpack高级配置

一、了解webpack高级配置&#xff1a; 1、什么是webpack高级配置&#xff1a; 进行 Webpack 优化&#xff0c;让代码在编译或者运行时性能更好 2、webpack优化从哪些方面入手&#xff1a; ① 提升开发体验&#xff0c;增强开发和生产环境的代码调试&#xff1a; 如果代码编写…

LLM表征工程还有哪些值得做的地方

LLM表征工程还有哪些值得做的地方 在大型语言模型(LLM)的表征工程领域,近年来涌现出多个具有突破性的创新方向,这些方法通过动态调整、多模态融合、结构化记忆增强等技术,显著提升了模型的适应性、可解释性和效率。 一、动态自适应表征:从静态到动态的范式革新 传统LL…

LabVIEW智能避障小车

​LabVIEW结合 NI、德州仪器&#xff08;TI&#xff09;、欧姆龙&#xff08;Omron&#xff09;等硬件&#xff0c;设计实现了一款具备智能避障、循迹功能的轮式机器人。系统支持手动操控与自主运行两种模式&#xff0c;通过无线通信实时传输传感器数据与图像信息&#xff0c;在…

逻辑代数中的基本规则,代入规则和反演规则,对偶规则

本文探讨了代入规则在逻辑等式中的应用&#xff0c;解释了如何通过替换变量来保持等式的正确性&#xff0c;同时介绍了反演规则和对偶规则的概念。代入规则定义:在任何一个包含变量A的逻辑等式中&#xff0c;如果用另一个逻辑式代入式中的所有A位置&#xff0c;则等式依然成立反…

Javaweb使用websocket,请先连上demo好吧!很简单的!

Javaweb使用websocket先看结构及效果MyWebSocketHandler用于处理消息WebSocketConfig用于配置建联地址等SchedulerConfig必须配置这个MyWebSocketInterceptor建联的拦截器SpringBootWebsocketApplication启动类POM依赖展示效果源码先看结构及效果 MyWebSocketHandler用于处理消…

文心大模型4.5开源测评:保姆级部署教程+多维度测试验证

前言&#xff1a;国产大模型开源的破局时刻 2025年6月百度文心大模型4.5系列的开源&#xff0c;标志着国产AI从"技术跟跑"向"生态共建"的关键跨越。 文心大模型4.5是百度自主研发的新一代原生多模态基础大模型&#xff0c;通过多个模态联合建模实现协同优…

前端学习5:Float学习(仅简单了解,引出flex)

一、Float基础概念1. 设计初衷&#xff1a; float最初是为实现文字环绕图片的效果&#xff08;类似杂志排版&#xff09;&#xff0c;后来被开发者用来做页面布局。2. 核心特性&#xff1a;使元素脱离普通文档流&#xff08;但仍在DOM中&#xff09;元素会向左/右浮动&#xff…

08-自然壁纸实战教程-视频列表-云

08-自然壁纸实战教程-视频列表 前言 视频列表页面本质上也是一个数据展示的列表&#xff0c;不同之处在于之前是是展示壁纸&#xff0c;Image组件负责渲染&#xff0c;这里展示的是视频&#xff0c;使用Video组件&#xff0c;另外视频页面也实现了下载的基本功能&#xff0c;…

SCI特刊征稿

我们团队联合北京工业大学研究团队在SCI源刊CMC组织了特刊SI: Advanced Edge Computing and Artificial Intelligence in Smart Environment,主要收录边缘计算和人工智能方向的文章&#xff0c;欢迎领域专家和学者投稿&#xff0c;网址https://www.techscience.com/cmc/special…

DO,VO,DTO.....

在 Java 项目里&#xff08;尤其是 Spring、MyBatis 这类框架&#xff09;&#xff0c;经常会看到一堆以 O 结尾的类&#xff1a;VO、DO、DTO、BO、POJO……它们本质上都是普通的 Java Bean&#xff08;即 POJO&#xff09;&#xff0c;但职责和出现的位置不同。下面用“用户下…

数据结构之并查集和LRUCache

系列文章目录 数据结构之ArrayList_arraylist o(1) o(n)-CSDN博客 数据结构之LinkedList-CSDN博客 数据结构之栈_栈有什么方法-CSDN博客 数据结构之队列-CSDN博客 数据结构之二叉树-CSDN博客 数据结构之优先级队列-CSDN博客 常见的排序方法-CSDN博客 数据结构之Map和Se…

UE5多人MOBA+GAS 21、给升龙添加连段攻击,从角色的按下事件中传递事件给GA

文章目录给升龙制作可连段缓存下一连段用普攻键来触发升龙后续的连段在角色中发送按下普攻标签事件在升龙中接收按下事件&#xff0c;触发连段以及伤害和力量的传递最后在蓝图中设置一下升龙技能的完整代码给升龙制作可连段 给升龙技能添加一些连段 缓存下一连段 缓存下一连…

基于光栅传感器+FPGA+ARM的测量控制解决方案

基于光栅传感器结合FPGA与ARM的测量控制解决方案&#xff0c;通过硬件协同分工实现高精度、实时性及多场景适应性&#xff1a;⚙️ ‌一、系统架构分工‌‌传感层&#xff08;光栅传感器&#xff09;‌采用光栅尺输出正交脉冲信号&#xff0c;分辨率达0.5μm&#xff0c;精度1μ…

NW831NW910美光固态闪存NW887NW888

美光固态闪存深度解析&#xff1a;NW831、NW910、NW887、NW888系列全方位评测一、技术根基与架构创新美光NW系列固态闪存的技术突破源于其先进的G9 NAND架构&#xff0c;该架构采用5纳米制程工艺和多层3D堆叠技术&#xff0c;在单位面积内实现了高达256层的存储单元堆叠&#x…

reasense api 文档

API 架构 英特尔实感&#xff08;Intel RealSense™&#xff09;API 提供对深度摄像头流数据的配置、控制和访问功能。该 API 支持通过高层级 API 快速启用摄像头基础功能&#xff0c;或通过底层级 API 全面控制所有摄像头设置。请根据需求选择合适的 API&#xff1a; 高层级 P…

ArkTs实现骰子布局

Entry Component struct workA {// 定义6种颜色数组&#xff0c;使用ResourceColor类型确保颜色值合法性State color: ResourceColor[] [#ef2816, #f0a200, #6ab002, #005868, #41192e, #141411]// 定义公共样式装饰器&#xff0c;避免重复样式代码Stylesys() {// 白色圆形基础…

c语言内存函数以及数据在内存中的存储

代码见&#xff1a;登录 - Gitee.com 1. memcpy使用和模拟实现 strcpy&#xff0c;strncpy是拷贝字符串的&#xff0c;有局限性 函数原型&#xff1a; void * memcpy ( void * destination, const void * source, size_t num ); 功能&#xff1a; memcpy 是完成内存块拷⻉的…

Codeforces Round 787 (Div. 3)(A,B,C,D,E,F,G)

Codeforces Round 787 (Div. 3) - Codeforces A. Food for Animals 题意 有a袋狗粮,b袋猫粮,c袋通用粮食&#xff0c;问现在有x只狗y只猫,每一个动物都要吃一袋粮食,问粮食够不够吃 思路 首先肯定考虑猫吃猫粮&#xff0c;狗吃狗粮。然后再考虑如果不够吃的话才会去吃通用…

LLaMA-Factory的webui快速入门

一、webui的启动方式 LLaMA-Factory 支持通过 WebUI 零代码微调大语言模型。 在完成安装 后&#xff0c;您可以通过以下指令进入 WebUI: llamafactory-cli webui 使用上面命令启动服务后&#xff0c;即可使用默认7860端口进行访问。访问地址&#xff1a;http://ip:7860,截止…

【第四节】ubuntu server安装docker

首先更新软件源 sudo apt update sudo apt upgrade安装docker 下载 Docker 官方 GPG 密钥 # 1. 下载 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg再次更新软件源…