OpenGL(4)着色器

文章目录

前言:

在OpenGL开发中,着色器(Shader)是用于控制图形渲染管线各个阶段的小程序。它们是用GLSL(OpenGL Shading Language)编写的,GLSL是一种类似于C的语言。着色器在GPU上执行,负责处理顶点、片段等数据,最终生成图像。

一、着色器

1、什么是着色器?

概念:

着色器(Shader)是运行在 GPU 上的小程序,用于处理图形渲染过程中的特定任务。传统的 OpenGL 渲染流程中,CPU 需要承担大量的图形计算任务,而引入着色器后,将这些计算任务转移到 GPU 上,利用 GPU 的并行计算能力,大大提高了渲染效率。

工作原理:

当 OpenGL 进行图形渲染时,会将顶点数据(如顶点坐标、颜色、纹理坐标等)传递给着色器进行处理。着色器根据预设的算法对这些数据进行计算和转换,最终生成像素的颜色值,用于显示在屏幕上。整个渲染过程可以分为多个阶段,每个阶段由不同类型的着色器负责处理。

2、着色器类型

2.1、顶点着色器(Vertex Shader)

  • 功能:顶点着色器是处理顶点数据的第一个阶段。它接收顶点的原始数据(如顶点坐标、法线、颜色等),并对这些数据进行变换和处理,例如将顶点坐标从模型空间转换到裁剪空间。

  • 示例代码

    cpp 复制代码
    #version 330 core
    layout (location = 0) in vec3 aPos;  // 输入的顶点位置
    layout (location = 1) in vec3 aColor; // 输入的顶点颜色
    out vec3 ourColor;  // 输出的颜色,传递给片段着色器
    void main()
    {
        gl_Position = vec4(aPos, 1.0); // 将顶点位置转换为齐次坐标
        ourColor = aColor; // 传递颜色数据
    }

2.2、片段着色器(Fragment Shader)

  • 功能:片段着色器负责计算每个像素的最终颜色。它接收顶点着色器传递过来的数据(如颜色、纹理坐标等),并根据这些数据计算出每个像素的颜色值。

  • 示例代码

    cpp 复制代码
    #version 330 core
    in vec3 ourColor; // 从顶点着色器接收的颜色数据
    out vec4 FragColor; // 输出的最终像素颜色
    void main()
    {
        FragColor = vec4(ourColor, 1.0); // 将颜色数据转换为 RGBA 格式
    }

3、着色器属性

在基于 Qt 进行 OpenGL 开发时,理解 OpenGL 着色器语言(GLSL)中的 layoutinout 等属性是非常重要的,这些属性用于定义着色器之间的数据传递和属性的存储位置。下面详细介绍这些属性。

3.1、layout 属性

  • 功能:

    layout 属性主要用于指定着色器输入输出变量的存储布局,比如在顶点着色器中指定顶点属性的位置,或者在片段着色器中指定颜色输出的位置等。通过 layout 属性,我们可以精确地控制数据在内存中的存储和访问方式,方便 OpenGL 正确地读取和处理数据。

  • 示例及解释:

    glsl 复制代码
    #version 330 core
    // 顶点着色器中,使用 layout 指定顶点位置属性的位置为 0
    layout (location = 0) in vec3 aPos;
    // 使用 layout 指定顶点颜色属性的位置为 1
    layout (location = 1) in vec3 aColor;
    out vec3 ourColor;
    
    void main()
    {
        gl_Position = vec4(aPos, 1.0);
        ourColor = aColor;
    }

    在上述顶点着色器代码中,layout (location = 0) 表明 aPos 这个顶点位置属性在顶点数据中的索引为 0,layout (location = 1) 则表示 aColor 顶点颜色属性的索引为 1。在 C++ 代码中,我们可以根据这些索引来设置顶点属性指针,示例如下:

    cpp 复制代码
    // 设置顶点位置属性指针
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    // 设置顶点颜色属性指针
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));

3.2、in 属性

  • 功能:

    in 属性用于声明着色器的输入变量。在不同类型的着色器中,in 变量的来源不同。例如,在顶点着色器中,in 变量通常是从 CPU 传递过来的顶点属性数据;在片段着色器中,in 变量一般是从顶点着色器经过光栅化插值后传递过来的数据。

  • 示例及解释:

    glsl 复制代码
    #version 330 core
    // 顶点着色器
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aColor;
    out vec3 ourColor;
    
    void main()
    {
        gl_Position = vec4(aPos, 1.0);
        ourColor = aColor;
    }
    
    // 片段着色器
    in vec3 ourColor;
    out vec4 FragColor;
    
    void main()
    {
        FragColor = vec4(ourColor, 1.0);
    }

在顶点着色器中,aPosaColor 是从 CPU 传递过来的顶点属性,使用 in 关键字声明。而 ourColor是输出变量,会传递给片段着色器。在片段着色器中,ourColor 作为输入变量接收来自顶点着色器的数据,然后将其用于计算最终的像素颜色。

3.3、out 属性

  • 功能:

    out 属性用于声明着色器的输出变量。这些变量会传递给下一个阶段的着色器进行处理。例如,顶点着色器的输出变量会经过光栅化插值后传递给片段着色器。

  • 示例及解释:

    glsl 复制代码
    #version 330 core
    // 顶点着色器
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aColor;
    // 声明输出变量,传递给片段着色器
    out vec3 ourColor;
    
    void main()
    {
        gl_Position = vec4(aPos, 1.0);
        ourColor = aColor;
    }
    
    // 片段着色器
    // 接收来自顶点着色器的输出变量
    in vec3 ourColor;
    // 声明片段着色器的输出变量,即最终的像素颜色
    out vec4 FragColor;
    
    void main()
    {
        FragColor = vec4(ourColor, 1.0);
    }

在顶点着色器中,ourColor 使用 out 关键字声明,它会将顶点的颜色信息传递给片段着色器。在片段着色器中,FragColor 使用 out 关键字声明,它表示最终的像素颜色,会被写入帧缓冲区。

3.4、总结

  • layout 属性用于指定变量的存储位置,方便 OpenGL 正确解析数据。
  • in 属性用于声明着色器的输入变量,接收来自上一个阶段的数据。
  • out 属性用于声明着色器的输出变量,将数据传递给下一个阶段的着色器。

通过合理使用这些属性,我们可以实现不同着色器之间的数据传递和交互,从而完成复杂的图形渲染任务。

4、示例

创建一个顶点着色器与片段着色器,并使用QOpenGLShaderProgram类对象应用着色器,如下:

  • 顶点着色器
cpp 复制代码
// vertex_shader.glsl
#version 330 core
layout (location = 0) in vec3 aPos;      // 顶点位置
layout (location = 1) in vec3 aColor;    // 顶点颜色

out vec3 ourColor; // 传递给片段着色器的颜色

void main()
{
    gl_Position = vec4(aPos, 1.0); // 设置顶点位置
    ourColor = aColor;             // 传递颜色
}
  • 片段着色器
cpp 复制代码
#version 330 core
in vec3 ourColor;      // 从顶点着色器传入的颜色
out vec4 FragColor;    // 输出颜色

void main()
{
    FragColor = vec4(ourColor, 1.0); // 使用传入的颜色
}
  • 示例代码
cpp 复制代码
#include <QOpenGLFunctions_3_3_Core>
#include "OpenGLWidget.h"

// 顶点数据结构
struct Vertex {
    float position[3];       // 位置
    float color[3];          // 颜色
};

// 顶点数据
Vertex vertices[] = {
    { { -0.5f, -0.5f, 0.0f },{ 1.0, 0.0, 0.0 } },
    { { 0.5f, -0.5f, 0.0f },{ 0.0, 1.0, 0.0 } },
    { { 0.0f,  0.5f, 0.0f },{ 0.0, 0.0, 1.0 } }
};

// 构造函数
OpenGLWidget::OpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
}

// 析构函数
OpenGLWidget::~OpenGLWidget()
{
}

void OpenGLWidget::initializeGL()
{
    // 初始化OpenGL相关的接口
    initializeOpenGLFunctions();

    // 顶点数据:坐标 + 颜色
    GLfloat 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  // 顶部 (蓝色)
    };

    // 创建并绑定VAO
    glGenVertexArrays(1, &m_vao);
    glBindVertexArray(m_vao);

    // 创建并绑定m_vbo
    glGenBuffers(1, &m_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    // 位置属性 (location = 0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    // 颜色属性 (location = 1)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // 解绑VAO
    glBindVertexArray(0);

    // 编译着色器
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/OpenGL_Demo_Shader/vertex_shader.glsl");
    m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/OpenGL_Demo_Shader/fragment_shader.glsl");
    m_shaderProgram.link();
}

void OpenGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h); // 设置视口大小
}

void OpenGLWidget::paintGL()
{
    // 清除颜色缓冲
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置背景颜色
    glClear(GL_COLOR_BUFFER_BIT);

    // 使用着色器程序
    m_shaderProgram.bind();

    // 绑定VAO
    glBindVertexArray(m_vao);

    // 绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 解绑VAO
    glBindVertexArray(0);
}
  • 运行结果
相关推荐
不收藏找不到我3 小时前
7、基于osg引擎实现读取vtk数据通过着色器实现简单体渲染(1)
着色器
太妃糖耶13 小时前
Shader中着色器的编译目标级别
unity·shader·着色器
竹竿袅袅17 小时前
Tomcat 安装
java·tomcat·apache·web
2301_801067092 天前
Web服务器配置、虚拟主机配置、访问权限控制
运维·服务器·php·apache
csdn_aspnet2 天前
Windows 上安装配置 Apache Tomcat 及Tomcat 与 JDK 版本对应
windows·tomcat·apache
四肢发达的猿2 天前
【2步解决】phpstudy开机自启(自动启动phpstudy、mysql、nignx或apache、自动打开网址)
数据库·mysql·apache·phpstudy·phpstudy_pro
Gobysec2 天前
Goby 漏洞安全通告| Apache Tomcat 远程命令执行(CVE-2025-24813)
tomcat·apache·poc·exp·漏洞扫描工具·漏洞验证·cve-2025-24813
HELLOMILI2 天前
[Unity3D] 动态立方体贴图系统
游戏·unity·游戏引擎·图形渲染·着色器
ronshi3 天前
通过Apache HTTP Server部署SVN
svn·apache