OpenGL(三)——着色器
目录
一、前言
二、Shader 2 Shader
2.1 顶点着色器
2.2 片段着色器
三、APP 2 Shader
四、顶点颜色属性
五、着色器类C++
一、前言
着色器Shader是运行在GPU上的小程序,为图形渲染管线的某个特定部分而运行。各阶段着色器之间无法通信,只有输入和输出。着色器程序需要使用GLSL语言编写。GLSL语言转为图形计算量身定制,定义了一些向量和矩阵操作。
着色器开头需要有声明版本,结束输入、输出、uniform变量、main函数。main是着色器入口点,在函数中需要处理输入变量,然后输出到输出变量中。
二、Shader 2 Shader
2.1 顶点着色器
顶点着色器的输的顶点数据直接接收输入。使用location
这一元数据指定输入变量,定义顶点数据该如何管理,才可以在CPU上配置顶点属性,layout (location = 0)表示位置属性。
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main()
{gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色
}
2.2 片段着色器
片段着色器,它需要一个vec4
颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。
#version 330 core
out vec4 FragColor;in vec4 vertexColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)void main()
{FragColor = vertexColor;
}
三、APP 2 Shader
APP向Opengl的传参属性有三种:
Attribute:属性通道,传递可变参数,如颜色数据、顶点数据,纹理坐标、光照法线
uniform: 统一变量通道,传递不变的参数,如变换矩阵,RGBA->YUV
Texture Data:纹理数据
Uniform标识符是一种从CPU到GPU的着色器发送数据方式。Uniform是全局变量,可以被任何着色器程序访问。在片段着色器种使用变量Uniform。
#version 330 core
out vec4 FragColor;uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量void main()
{FragColor = ourColor;
}
在APP种如何使用联系着色器种的uniform全局变量?
- 找到着色器uniform 属性索引/位置值
- 调用函数更新该变量
while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render//背景颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);//激活着色器glUseProgram(shaderProgram);//更新uniform变量float timeValue = glfwGetTime();//获取秒级时间float greenValue = sin(timeValue) / 2.0f + 0.5f;int vertexUniformIndex = glGetUniformLocation(shaderProgram, "ourColor");//索引glUniform4f(vertexUniformIndex, 0.0, greenValue, 0.0, 1.0);//更新uniform变量//绘制三角形glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}glGetUniformLocation — Returns the location of a uniform variable
GLint glGetUniformLocation( GLuint program,const GLchar *name);
program:着色器程序
Specifies the program object to be queried.
name: uniform变量名字glUniform — Specify the value of a uniform variable for the current program object
void glUniform4f( GLint location,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3);
四、顶点颜色属性
直接使用顶点输入的颜色值来显示:
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 // 顶部
};
顶点着色器程序:
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n" //位置属性值0
"layout (location = 1) in vec3 aColor;\n"//颜色属性值1
"out vec3 ourColor;\n" //输出给片段着色器
"void main()\n"
"{\n"
" gl_Position = vec4(aPos, 1.0);\n"
" ourColor = aColor;\n" //从顶点数据读取并赋值给输出变量
"}\0";
片段着色器:
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"//使用顶点输出的数据
"void main()\n"
"{\n"
" FragColor = vec4(ourColor,1.0);\n"
"}\n\0";
更新VBO内存,并重新配置VAO解释器:
//位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//颜色属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));glEnableVertexAttribArray(1);
这个图片可能不是你所期望的那种,因为我们只提供了3个颜色,而不是我们现在看到的大调色板。这是在片段着色器中进行的所谓片段插值(Fragment Interpolation)的结果。当渲染一个三角形时,光栅化(Rasterization)阶段通常会造成比原指定顶点更多的片段。光栅会根据每个片段在三角形形状上所处相对位置决定这些片段的位置。
基于这些位置,它会插值(Interpolate)所有片段着色器的输入变量。比如说,我们有一个线段,上面的端点是绿色的,下面的端点是蓝色的。如果一个片段着色器在线段的70%的位置运行,它的颜色输入属性就会是一个绿色和蓝色的线性结合;更精确地说就是30%蓝 + 70%绿。
五、着色器类C++
#pragma once
#include "glad.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>class Shader
{
public:unsigned int ID;// constructor generates the shader on the fly// ------------------------------------------------------------------------Shader(const char* vertexPath, const char* fragmentPath){// 1. retrieve the vertex/fragment source code from filePathstd::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;// ensure ifstream objects can throw exceptions:vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);try{// open filesvShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// read file's buffer contents into streamsvShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();// close file handlersvShaderFile.close();fShaderFile.close();// convert stream into stringvertexCode = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure& e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;}const char* vShaderCode = vertexCode.c_str();const char* fShaderCode = fragmentCode.c_str();// 2. compile shadersunsigned int vertex, fragment;// vertex shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);checkCompileErrors(vertex, "VERTEX");// fragment Shaderfragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);checkCompileErrors(fragment, "FRAGMENT");// shader ProgramID = glCreateProgram();glAttachShader(ID, vertex);glAttachShader(ID, fragment);glLinkProgram(ID);checkCompileErrors(ID, "PROGRAM");// delete the shaders as they're linked into our program now and no longer necessaryglDeleteShader(vertex);glDeleteShader(fragment);}// activate the shader// ------------------------------------------------------------------------void use(){glUseProgram(ID);}// utility uniform functions// ------------------------------------------------------------------------void setBool(const std::string& name, bool value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);}// ------------------------------------------------------------------------void setInt(const std::string& name, int value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), value);}// ------------------------------------------------------------------------void setFloat(const std::string& name, float value) const{glUniform1f(glGetUniformLocation(ID, name.c_str()), value);}private:// utility function for checking shader compilation/linking errors.// ------------------------------------------------------------------------void checkCompileErrors(unsigned int shader, std::string type){int success;char infoLog[1024];if (type != "PROGRAM"){glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}else{glGetProgramiv(shader, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}}
};
类使用:
Shader ourShader("path/to/shaders/shader.vs", "path/to/shaders/shader.fs");
...
while(...)
{ourShader.use();ourShader.setFloat("someUniform", 1.0f);DrawStuff();
}
参考:
着色器 - LearnOpenGL CN (learnopengl-cn.github.io)
相关文章:

OpenGL(三)——着色器
目录 一、前言 二、Shader 2 Shader 2.1 顶点着色器 2.2 片段着色器 三、APP 2 Shader 四、顶点颜色属性 五、着色器类C 一、前言 着色器Shader是运行在GPU上的小程序,为图形渲染管线的某个特定部分而运行。各阶段着色器之间无法通信,只有输入和输…...

【MySQL】单表查询
一、表的准备 查询操作的SQL演示将基于下面这四张表进行,我们先创建好这四张数据表,并为其添加数据。 1、第一张表为部门表,名称为包含三个字段:部门编号(deptno),部门名称(dname&…...

第一章 安装Unity
使用Unity开发游戏的话,首先要安装Unity Hub和Unity Editor两个软件。大家可以去官方地址下载:https://unity.cn/releases/full/2020 (这里我们选择的是2020版本) Unity Hub 是安装 Unity Editor、创建项目、管理帐户和许可证的主…...

20230425----重返学习-vue项目-vue自定义指令-vue-cli的配置
day-057-fifty-seven-20230425-vue项目-vue自定义指令-vue-cli的配置 vue项目 vuex版 普通版纯axios:切换页面,就会重新发送一次ajax请求普通版升级:vuex版vuex的常用功能 vuex 数据通信vuex 缓存数据 前进后退,切换页面&#…...

el-input 只能输入整数(包括正数、负数、0)或者只能输入整数(包括正数、负数、0)和小数
使用el-input-number标签 也可以使用typenumbe和v-model.number属性,两者结合使用,能满足大多数需求,如果还不满足,可以再结合正则表达式过滤 <el-input v-model.number"value" type"number" /> el-i…...

Docker Compose的常用命令与docker-compose.yml脚本属性配置
Docker Compose的常用命令与配置 常见命令ps:列出所有运行容器logs:查看服务日志输出port:打印绑定的公共端口build:构建或者重新构建服务start:启动指定服务已存在的容器stop:停止已运行的服务的容器&…...

with语句和上下文管理器(py编程)
1. with语句的使用 基础班向文件中写入数据的示例代码: # 1、以写的方式打开文件f open("1.txt", "w")# 2、写入文件内容f.write("hello world")# 3、关闭文件f.close()代码说明: 文件使用完后必须关闭,因为文件对象会占用操作系统…...

《JavaEE初阶》HTTP协议和HTTPS
《JavaEE初阶》HTTP协议和HTTPS 文章目录 《JavaEE初阶》HTTP协议和HTTPSHTTP协议是应用层协议:使用Fiddler抓取HTTP请求和响应:Fiddler的下载和基本使用:Fiddler的中间代理人身份:其他抓包工具: 先简单认识HTTP请求与HTTP响应:HTTP请求:HTTP响应: HTTP请求详解:首行࿱…...

微信小程序 | 基于高德地图+ChatGPT实现旅游规划小程序
🎈🎈效果预览🎈🎈 ❤ 路劲规划 ❤ 功能总览 ❤ ChatGPT交互 一、需求背景 五一假期即即将到来,在大家都阳过之后,截止到目前这应该是最安全的一个假期。所以出去旅游想必是大多数人的选择。 然后&#x…...

Excel技能之实用技巧,高手私藏
今天来讲一下Excel技巧,工作常用,高手私藏。能帮到你是我最大的荣幸。 与其加班熬夜赶进度,不如下班学习提效率。能力有成长,效率提上去,自然不用加班。 消化吸收,工作中立马使用,感觉真不错。…...

黑马程序员Java零基础视频教程笔记-运算符
文章目录 一、算数运算符详解和综合练习二、隐式转换和强制转换三、字符串和字符的加操作四、自增自减运算符五、赋值运算符和关系运算符六、四种逻辑运算符七、短路逻辑运算符八、三元运算符 一、算数运算符详解和综合练习 1. 运算符和表达式 ① 运算符:对字面量…...

Microsoft Data Loss Prevention(DLP)部署方案
目录 一、前言 二、部署流程 步骤一:确定数据需求 步骤二:规划信息保护策略...

win系统使用frp端口映射实现内网穿透,配置“任务计划程序”提高稳定性
Github下载最新版frp: https://github.com/fatedier/frp/releases/download/v0.48.0/frp_0.48.0_windows_amd64.zip 解压把frpc.exe和frpc.ini放到D:\program\frp目录下,修改frpc.ini内容如下: [common] server_addr 服务器域名或IP,假设…...

python工具方法 39 大图裁剪为小图|小图还原成大图(含生成大图伪标签)
在进行遥感影像的处理中,通常都是几万x几万的大型影像,这给数据标注(图像尺寸过大使标注软件不能正常打开或过大给标注带来困难)、训练模型(只能使用小图)、测试图片(在小图上预测需要还原成大图)、生成伪标签(需要大图的伪标签,而不是小图的)都带来了困难。针对此进…...

MUSIC算法仿真
MUSIC算法原理及仿真 DOA波达方向估计MUSIC算法概述MUSIC算法原理MUSIC算法MATLB仿真 DOA波达方向估计 DOA(Direction Of Arrival)波达方向是指通过阵列信号处理来估计来波的方向,这里的信源可能是多个,角度也有多个。DOA技术主要…...

redis 数据类型详解 以及 redis适用场景场合
1. MySqlMemcached架构的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇…...

python基于轻量级YOLOv5的生猪检测+状态识别分析系统
在我之前的一篇文章中有过生猪检测盒状态识别相关的项目实践,如下: 《Python基于yolov4实现生猪检测及状态识》 感兴趣的话可以自行移步阅读,这里主要是基于同样的技术思想,将原始体积较大的yolov4模型做无缝替换,使…...

阅读笔记 First Order Motion Model for Image Animation
文章解决的是图片动画的问题。假设有源图片和驱动视频,并且其中的物体是同一类的,文章的方法让源图片中的物体按照驱动视频中物体的动作而动。 文章的方法只需要一个同类物体的视频集,不需要而外的标注。 方法 该方法基于self-supervised策…...

【计算机图形学】课堂习题汇总
在直线的光栅化算法中,如果不考虑最大位移方向则可能得到怎样的直线? A:斜率为1的线 B:总是垂直的 C:离散的点,无法构成直线 D:总是水平的 在直线的改进的Bresenham算法中,每当误…...

国外导师对博士后申请简历的几点建议
正所谓“工欲善其事,必先利其器”,想要申请国外的博士后职位,就要准备好相应的申请文书材料。如果说Cover Letter是职位的窍门砖,那么申请者的简历就是争取职位的决定性筹码。 相信大家已经看过许多简历的模版了,但是…...

【五一创作】Scratch资料袋
Scratch软件是免费的、免费的、免费的。任何需要花钱才能下载Scratch软件的全是骗子。 1、什么是Scratch Scratch是麻省理工学院的“终身幼儿园团队”开发的一种图形化编程工具。是面向青少年的一款模块化,积木化、可视化的编程语言。 什么是模块化、积木化&…...

数据库基础篇 《17.触发器》
数据库基础篇 《17.触发器》 在实际开发中,我们经常会遇到这样的情况:有 2 个或者多个相互关联的表,如商品信息和库存信息分别存放在 2 个不同的数据表中,我们在添加一条新商品记录的时候,为了保证数据的完整性&#…...

03 - 大学生如何使用GPT
大学生如何使用GPT提高学习效率 一、引言 在当今的高速发展的信息时代,大学生面临着越来越多的学习挑战。作为一种先进的人工智能技术,GPT为大学生提供了一种强大的学习工具。本文将介绍大学生在不同场景中如何使用GPT来提高学习效率,并给出…...

【P1】Jmeter 准备工作
文章目录 一、Jmeter 介绍1.1、Jmeter 有什么样功能1.2、Jmeter 与 LoadRunner 比较1.3、常用性能测试工具1.4、性能测试工具如何选型1.5、学习 Jmeter 对 Java 编程的要求 二、Jmeter 软件安装2.1、官网介绍2.2、JDK 安装及环境配置2.3、Jmeter 三种模式2.4、主要配置介绍2.4.…...

字节的面试,你能扛住几道?
C , Python 哪一个更快? 读者答:这个我不知道从哪方面说,就是 C 的话,它其实能够提供开发者非常多的权限,就是说它能涉及到一些操作系统级别的一些操作,速度应该挺快。然后 Python 实现功能还…...

NOPI用法之自定义单元格背景色(3)
NPOI针对office2003使用HSSFWorkbook,对于offce2007及以上使用XSSFWorkbook;今天我以HSSFWorkbook自定义颜色为例说明,Office2007的未研究呢 在NPOI中默认的颜色类是HSSFColor,它内置的颜色有几十种供我们选择,如果不…...

数据分析中常见标准的参考文献
做数据分析过程中,有些分析法方法的标准随便一搜就能找到,不管是口口相传还是默认,大家都按那样的标准做了。日常分析不细究出处还可以,但是正式的学术论文你需要为你写下的每一句话负责,每一个判断标准都应该有参考文…...

辨析 变更请求、批准的变更请求、实施批准的变更请求
变更请求、批准的变更请求、实施批准的变更请求辨析 辨析各种变更请求,不服来辨。 变更请求 定义:对正规受控的文件或计划(范围、进度、成本、政策、过程、计划或程序)等的变更,以反映修改或增加的意见或内容 根据变更请求的工作内容可将变…...

leetcode 561. 数组拆分
题目描述解题思路执行结果 leetcode 561. 数组拆分 题目描述 数组拆分 给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。 返回该 最大总和 。 示例 1&am…...

AviatorScript
AviatorScript 是一门高性能、轻量级寄宿于 JVM (包括 Android 平台)之上的脚本语言 特性介绍 支持数字、字符串、正则表达式、布尔值、正则表达式等基本类型,完整支持所有 Java 运算符及优先级等。函数是一等公民,支持闭包和函…...