首页 / 汽车 / 正文

windowed mode(【LearnOpenGL】06.着色器基础)

放大字体  缩小字体 来源:鱼肉馅饺子 2026-04-15 13:33  浏览次数:11

开发环境

  • Windows 10
  • Visual Studio Community 2022

准备项目

1.新建一个空的C++项目:06_Shader,并设置为启动项目。

新建项目

2.配置GLEW和GLFW。根据ntent="mp" data-source="innerlink" href="https://www.toutiao.com/i7294560261539725843/?group_id=7294560261539725843" rel="noopener noreferrer noopener noreferrer" target="_blank">【LearnOpenGL】01.创建窗口ntent="mp" data-source="innerlink" href="https://www.toutiao.com/i7299268967548486155/?group_id=7299268967548486155" rel="noopener noreferrer noopener noreferrer" target="_blank">【LearnOpenGL】03.配置GLEW,对这2项进行配置,保证编译通过。

简介

OpenGL 着色语言(OpenGL Shading Language,简称为GLSL)是 OpenGL 中使用了一种高级的图形编程语言。其中可以在 OpenGL 可编程处理器上执行的 OpenGL 着色语言代码被称为“着色器(Shader)”。

可编程着色器主要是对顶点和片元进行处理。顶点处理涉及在各个顶点发生的操作,尤其是变换和光照。片元处理是在各个片元(各个像素的数据结构)基础上进行的操作,尤其是从纹理内存读取和在各个片元上应用纹理值的操作组成的。

语法

OpenGL 着色语言是基于 ANSI C 编程语言的语法。使用 OpenGL 着色语言编写的程序的基本结构与使用 C 编写的程序的基本结构相同:

  • 一组着色器的入口点是函数 void main(),而这个函数的主体被界定在括号中。
  • OpenGL 着色语言中的常量、标识符、运算符、表达式和语句与 C 是基本相同的。
  • 用于循环的控制流、if-then-else 以及函数调用与 C 几乎完全相同。

OpenGL 着色语言也具有其专用性。添加了一些与 ANSI C 不同的语言特性:

  • 支持用于浮点数、整数和布尔值的矢量类型。
  • 运算符可以像处理标量一样处理矢量类型。
  • 使用数组语法或者作为一个结构的字段可以访问矢量的单个组分。
  • 增加了浮点矩阵,使用数组语法可以选定矩阵的列,得到一个矢量。
  • 增加了取样器(sampler)的基本类型,可以用来访问纹理内存。
  • 增加了attribute、uniform 和 varying 限定符。

数据类型:标量

类型

描述

float

声明一个单独的浮点数

int

声明一个单独的整数

bool

声明一个单独的布尔数

数据类型:矢量

类型

描述

vec2

包含2个浮点数的矢量

vec3

包含3个浮点数的矢量

vec4

sampler1D

sampler2D

访问一个二维纹理

sampler3D

访问一个三维纹理

samplerCube

访问一个立方贴图纹理

sampler1DShadow

访问一个带对比的一维深度纹理


2.将着色器对象关联到着色器程序

void glAttachShader(GLuint program, GLuint shader);

参数:

  • program

关联到的着色器程序。

  • shader

着色器对象。

着色器对象可以在任何时候关联到着色器程序,但是只有经过程序的成功链接之后,着色器对象的功能才能可用。

着色器对象可以同时关联到多个不同的着色器程序上。


3.链接着色器程序

void gllinkProgram(GLuint program);

参数:

  • program

指定链接的着色器程序。


5.使用着色器来处理顶点和片元

void glUseProgram(GLuint program);

参数:

  • program

指定要运行的着色器程序。

如果 program 为0,那么所有当前使用的着色器都会被清除。


Shader类

着色器源代码编写、编译、加载、管理都是比较麻烦的事,所以构建一个类专门处理这些事情很有必要。

Shader.h

#pragma once#include <string>class Shader{public:	/// <summary>	/// 加载源代码文件,构造着色器	/// </summary>	/// <param name="vertexPath">顶点着色器源代码文件路径</param>	/// <param name="fragmentPath">片元着色器源代码文件路径</param>	Shader(const std::string& vertexPath, const std::string &fragmentPath);	/// <summary>	/// 析构函数	/// </summary>	~Shader();	/// <summary>	/// 启用着色器程序	/// </summary>	void Bind() const;	/// <summary>	/// 取消使用着色器程序	/// </summary>	void Unbind() const;private:	/// <summary>	/// 着色器程序ID	/// </summary>	unsigned int m_ID;	/// <summary>	/// 根据着色器源代码字符串,构建着色器对象	/// </summary>	/// <param name="vertexSource">顶点着色器源代码字符串</param>	/// <param name="fragmentSource">片元着色器源代码字符串</param>	void CreateShader(const std::string& vertexSource, const std::string& fragmentSource);	/// <summary>	/// 把着色器源代码字符串,根据指定的着色器类型,编译成着色器对象。	/// </summary>	/// <param name="type">着色器类型</param>	/// <param name="source">着色器源代码字符串</param>	/// <returns>返回着色器对象</returns>	unsigned int CompileShader(unsigned int type, const std::string& source);};

Shader.cpp

#include "Shader.h"#include <GL/glew.h>#include <fstream>#include <sstream>#include <iostream>Shader::Shader(const std::string& vertexPath, const std::string &fragmentPath) :m_ID(0){	// 着色器源代码字符串	std::string vertexCode;	std::string fragmentCode;	std::ifstream vertexFile;	std::ifstream fragmentFile;	// 保证ifstream对象可以抛出异常:	vertexFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);	fragmentFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);	try	{		// 打开文件		vertexFile.open(vertexPath);		fragmentFile.open(fragmentPath);		std::stringstream vertexStream, fragmentStream;		// 读取文件的缓冲内容到数据流中		vertexStream << vertexFile.rdbuf();		fragmentStream << fragmentFile.rdbuf();		// 关闭文件处理器		vertexFile.close();		fragmentFile.close();		// 转换数据流到string		vertexCode = vertexStream.str();		fragmentCode = fragmentStream.str();	}	catch (const std::exception&)	{		std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;	}	CreateShader(vertexCode, fragmentCode);}Shader::~Shader(){	glDeleteProgram(m_ID);}void Shader::CreateShader(const std::string& vertexSource, const std::string& fragmentSource){	unsigned int vertexShader, fragmentShader;	// 顶点着色器对象	vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSource);	// 片元着色器对象	fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);	if (vertexShader > 0 || fragmentShader > 0)	{		// 创建着色器程序		m_ID = glCreateProgram();		// 关联着色器对象		if (vertexShader > 0) glAttachShader(m_ID, vertexShader);		if (fragmentShader > 0) glAttachShader(m_ID, fragmentShader);		// 链接着色器程序		gllinkProgram(m_ID);	}	// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了	if (vertexShader > 0) glDeleteShader(vertexShader);	if (fragmentShader > 0) glDeleteShader(fragmentShader);}unsigned int Shader::CompileShader(unsigned int type, const std::string& source){	unsigned int shader;	// 创建着色器对象	shader = glCreateShader(type);	const char* src = source.c_str();	// 附加着色器源码	glShaderSource(shader, 1, &src, NULL);	// 编译着色器对象	glCompileShader(shader);	return shader;}void Shader::Bind() const{	glUseProgram(m_ID);}void Shader::Unbind() const{	glUseProgram(0);}


顶点数据

有了着色器,我们就可以把每个顶点上的颜色属性展示出来了。

// 顶点数据float vertices[] = { // --- position ---     --- color ---    -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下角   -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 左上角    0.5f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // 右上角    0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f  // 右下角};

因为我们添加了另一个顶点属性,并且更新了VBO的内存,我们就必须重新配置顶点属性指针。更新后的VBO内存中的数据现在看起来像这样:

// --- 位置属性 ---glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), 0);glEnableVertexAttribArray(0);// --- 颜色属性 ---glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));glEnableVertexAttribArray(1);

由于我们现在有了两个顶点属性,我们不得不重新计算步长值:6*sizeof(GL_FLOAT)。对于每个顶点,位置属性的偏移值不变,还是0;而颜色属性的偏移值是位置属性的字节长度,即:3*sizeof(GL_FLOAT)。

完整项目

#include <GL/glew.h>#include <GLFW/glfw3.h>#include <iostream>#include "src/Shader.h"unsigned int VBO;unsigned int IBO;void init() {    // 顶点数据    float vertices[] = {     // --- position ---     --- color ---        -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下角       -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 左上角        0.5f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // 右上角        0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f  // 右下角    };    // 绘制顶点的顺序    unsigned int indices[] = {        0, 1, 2,    // 第一个三角形的顶点数组下标        2, 0, 3     // 第二个三角形的顶点数组下标    };    // 创建一个缓存对象名,并存储到VBO    glGenBuffers(1, &VBO);    // 将缓存对象绑定到GL_ARRAY_BUFFER    glBindBuffer(GL_ARRAY_BUFFER, VBO);    // 把顶点数据复制到当前绑定的缓存对象    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);    // 创建一个缓存对象名,并存储到IBO    glGenBuffers(1, &IBO);    // 将缓存对象绑定到GL_ELEMENT_ARRAY_BUFFER    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);    // 把顶点索引数据复制到当前绑定的缓存对象    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);    // --- 位置属性 ---    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), 0);    glEnableVertexAttribArray(0);    // --- 颜色属性 ---    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));    glEnableVertexAttribArray(1);    // 着色器    Shader shader("res/Basic.vert", "res/Basic.frag");    shader.Bind();}void display() {    // 绘制    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);}void clear() {    // 删除缓存对象    glDeleteBuffers(1, &VBO);    glDeleteBuffers(1, &IBO);}// mainint main(void){    GLFWwindow* window;        if (!glfwInit())        return -1;        window = glfwCreateWindow(640, 480, "Shader", NULL, NULL);    if (!window)    {        glfwTerminate();        return -1;    }        glfwMakeContextCurrent(window);    // glew init    if (glewInit() != GLEW_OK) {        std::cout << "glew init error!" << std::endl;    }    // print opengl version    std::cout << "OpenGL version :" << glGetString(GL_VERSION) << std::endl;        init();        while (!glfwWindowShouldClose(window))    {                glClear(GL_COLOR_BUFFER_BIT);                display();                glfwSwapBuffers(window);                glfwPollEvents();    }    glfwTerminate();        clear();    return 0;}

运行结果:

运行结果


GitHub[作揖]

https://github.com/zGameDeveloper/LearnOpenGL/tree/main/Project/06_Shader

打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心