OpenGL(三)——着色器

news2024/11/25 2:53:17

目录

一、前言

二、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; // 位置变量的属性位置值为0

out 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全局变量?

  1. 找到着色器uniform 属性索引/位置值
  2. 调用函数更新该变量
    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 filePath
        std::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 files
            vShaderFile.open(vertexPath);
            fShaderFile.open(fragmentPath);
            std::stringstream vShaderStream, fShaderStream;
            // read file's buffer contents into streams
            vShaderStream << vShaderFile.rdbuf();
            fShaderStream << fShaderFile.rdbuf();
            // close file handlers
            vShaderFile.close();
            fShaderFile.close();
            // convert stream into string
            vertexCode = 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 shaders
        unsigned int vertex, fragment;
        // vertex shader
        vertex = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertex, 1, &vShaderCode, NULL);
        glCompileShader(vertex);
        checkCompileErrors(vertex, "VERTEX");
        // fragment Shader
        fragment = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragment, 1, &fShaderCode, NULL);
        glCompileShader(fragment);
        checkCompileErrors(fragment, "FRAGMENT");
        // shader Program
        ID = 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 necessary
        glDeleteShader(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)

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

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

相关文章

uniapp 截图或者生成海报

需求&#xff1a;uniapp移动端需要生成一张当前界面的海报 方案一&#xff1a;类似于手机按钮截图效果。实现代码如下&#xff1a; doSaveScreen() { let $this this; uni.showLoading({ //加载框 title: 保存中..., …

Sqlmap手册—史上最全

Sqlmap手册—史上最全 一.介绍 开源的SQL注入漏洞检测的工具&#xff0c;能够检测动态页面中的get/post参数&#xff0c;cookie&#xff0c;http头&#xff0c;还能够查看数据&#xff0c;文件系统访问&#xff0c;甚至能够操作系统命令执行。 检测方式&#xff1a;布尔盲注、…

css中的background属性

文章目录 一&#xff1a;background-repeat二&#xff1a;background-position三&#xff1a;background缩写方式三&#xff1a;background-size四&#xff1a;background-origin五&#xff1a;background-clip 在日常前端开发中&#xff0c;经常需要进行背景或背景图的处理。但…

国民技术N32G430开发笔记(10)- IAP升级 Application 的制作

IAP升级 Application 的制作 1、App程序跟Bootloader程序最大的区别就是&#xff0c; 程序的执行地址变成了之前flash设定的0x08006000处&#xff0c; 大小限制为20KB 所以修改Application工程的ld文件 origin 改成 0x08006000 length 改成0x5000 烧录是起始地址也要改为x0x…

【chapter30】【PyTorch】[动量与学习率衰减】

前言&#xff1a; SGD的不足&#xff1a; ①呈“之”字型&#xff0c;迂回前进&#xff0c;损失函数值在一些维度的改变得快&#xff08;更新速度快&#xff09;&#xff0c;在一些维度改变得慢&#xff08;速度慢&#xff09;- 在高维空间更加普遍 ②容易陷入局部极小值和鞍点…

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat

JDK本身提供了很多方便的JVM性能调优监控工具&#xff0c;除了集成式的VisualVM和jConsole外&#xff0c;还有jps、jstack、jmap、jhat、jstat等小巧的工具&#xff0c;本博客希望能起抛砖引玉之用&#xff0c;让大家能开始对JVM性能调优的常用工具有所了解。 现实企业级Java开…

【数据架构系列-06】一文搞懂数据模型的3中类型——概念模型、逻辑模型、物理模型

数据模型就是模拟现实世界的方法论&#xff0c;是通向智慧世界的基石&#xff01; 从现实世界发展到智慧世界&#xff0c;要数经历现实世界、信息世界、计算机世界、数据世界、智慧世界五个不同的世界&#xff0c;我们天生具有从混沌的世界抽象信息变为信息世界的能力&#xff…

《统计学习方法》——EM算法及其推广(上)

引言 EM算法是一种迭代算法&#xff0c;用于含有隐变量的概率模型参数的极大似然估计。 理解EM算法需要很多概率论的知识&#xff0c;所以下面先贴出所需要的知识。便于对后文的理解。 补充知识 期望 对于离散型随机变量 X X X的概率分布为 p i p { X x i } p_ip\{Xx_i\}…

第八章 集合函数

文章目录 前言一、聚合函数介绍1 、AVG (平均值) 和SUM &#xff08;求和&#xff09;函数2 、MIN&#xff08;最小值&#xff09;和MAX&#xff08;最大值&#xff09;函数3 、COUNT函数问题&#xff1a;用count(*)&#xff0c;count(1)&#xff0c;count(列名)谁好呢? 二、G…

语义分割学习笔记(一)语义分割前言

1.什么是语义分割&#xff1f; 语义分割(semantic segmentation) FCN要对分割对象进行一个大的划分&#xff0c;即分类。如下图&#xff0c;语义分割有树、人、草地大类别的划分。 实例分割(Instance segmentation) Mask R-CNN要对每一个分割类别中的每一个对象也要进行一个细…

第五章——动态规划2

线性DP 数字三角形 像二维数组一样&#xff0c;设置行和列&#xff0c;只不过这里的列是斜着的&#xff0c;如圈出来的7&#xff0c;坐标可以表示为(4,2) 集合划分&#xff0c;所有路径可以分成俩类&#xff0c;某点左上方一类&#xff0c;右下方一类。 我们先把7去掉&#xff…

利用层级式一致性加强进行半监督病理图像分割

文章目录 Semi-supervised Histological Image Segmentation via Hierarchical Consistency Enforcement摘要方法对学生模型进行有监督学习层级式一致性强化模块Hierarchical Consistency Loss (HC-Loss)以自我为导向的分层一致性损失 实验结果 Semi-supervised Histological I…

MySQL基础概念和SQL

目录 1.概念 1.1.什么是MySQL 1.2.关系型数据库、非关系型数据库 1.3.库、表、字段 2.数据类型 2.1.数值 2.2.字符串 2.3.日期/时间 3.结构化查询语言 3.1.DDL 3.2.DML 3.3.DCL 3.4.DQL 3.4.1.结果集 3.4.2.取别名 3.4.3.查列 3.4.4.条件查询 3.4.5.模糊查询…

做BI财务数据分析,国产BI软件经验更足

不管是为了提高销售额&#xff0c;还是为了提高库存周转、疏通现金流&#xff0c;都离不开数据分析&#xff0c;特别是BI大数据分析可视化。因此这几年来BI软件在各行各业的接受度迅速提升&#xff0c;特别是在财务数据分析方面&#xff0c;国产BI软件更是经验、技术到位。要说…

【大数据之Hadoop】二十二、Yarn调度器和调度算法

Hadoop作业调度器主要有三种&#xff1a;FIFO、容量&#xff08;Capacity Scheduler&#xff09;和公平&#xff08;Fair Scheduler&#xff09;。 Apache Hadoop默认的资源调度器&#xff1a;容量调度器Capacity Scheduler。 CDH框架默认调度器是Fair Scheduler。 1 FIFO 单…

智能电动自行车充电远程管理系统

目前市场上现有的户外普通充电桩只是一个用电计量工具&#xff0c;无法形成一个有效的停放充电管理环境。在受到雨、雪、风、暴晒等天气影响下根本无法使用,并且存在极大的安全隐患。同时公共无限的停放也导致充电位置被闲置车辆及杂物堆放占用&#xff0c;经常出现真正需要充电…

前端面试题 —— CSS (二)

目录 一、transition 和 animation 的区别 二、什么是物理像素&#xff0c;逻辑像素和像素密度&#xff0c;为什么在移动端开发时需要用到3x, 2x 这种图片&#xff1f; 三、margin 和 padding 的使用场景 四、CSS 优化和提高性能的方法有哪些&#xff1f; 五、display:in…

大数据编程实验3 熟悉常用的HBase操作

实验:熟悉常用的HBase操作 1实验目的 理解HBase在Hadoop体系结构中的角色&#xff1b;熟练使用HBase操作常用的Shell命令&#xff1b; 2 实验平台 操作系统&#xff1a;Linux Hadoop版本&#xff1a;3.1.3 HBase版本&#xff1a;2.2.2 JDK版本&#xff1a;1.8 3 实验内容和…

KDJB-702继保综合检测试验仪

一、产品参数 交流电流输出 输出精度&#xff1a;≤0.5A 2mA &#xff1e;0.5A 0.2% 相电流输出&#xff08;有效值&#xff09;&#xff1a;0&#xff5e;30A 三并电流输出&#xff08;有效值&#xff09;&#xff1a;0&#xff5e;900A 相电流长时间允许工作值&#xff…

java开发的chatGPT机器人系统

ChatGPT机器人发展趋势&#xff1a; 更加个性化&#xff1a;随着数据和技术的不断进步&#xff0c;ChatGPT机器人将能够更加准确地理解用户的需求和偏好&#xff0c;并提供更加个性化的回复和服务。 多语言支持&#xff1a;随着ChatGPT在各个国家和地区的普及&#xff…