简单着色器编写(上)

这篇具有很好参考价值的文章主要介绍了简单着色器编写(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在我的第一篇OpenGL文章中,我已经成功的画出了一个三角形,默认是白色的,那么该怎么把它换一个颜色呢?

先给出完整的代码。

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include<iostream>

static unsigned int CompileShader(unsigned int type,const std::string& source)
{
    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(id);

    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    if (result==GL_FALSE)
    {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        char* message = (char*)alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << "Failed to compile"<<
            (type==GL_VERTEX_SHADER?"vertex":"fragment")
            << "shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        return 0;
    }

    return id;
}

static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(GL_VERTEX_SHADER,vertexShader);
    unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);

    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glValidateProgram(program);

    glDeleteShader(vs);
    glDeleteShader(fs);

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glewInit();

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK)
        std::cout << "error";

    std::cout << glGetString(GL_VERSION) << std::endl;

    float positions[6] =
    {
        -0.5f, -0.5f,
        0.0f, 0.5f,
        0.5f, -0.5f
    };

    unsigned int buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float),positions,GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    std::string vertexShader =
        "#version 330 core\n"
        "\n"
        "layout(location=0)in vec4 position;"
        "\n"
        "void main()\n"
        "{\n"
        "  gl_Position = position;\n"
        "}\n";

    std::string fragmentShader =
        "#version 330 core\n"
        "\n"
        "layout(location=0)out vec4 color;"
        "\n"
        "void main()\n"
        "{\n"
        "  color=vec4(1.0,0.0,0.0,1.0);\n"
        "}\n";
    unsigned int shader = CreateShader(vertexShader,fragmentShader);
    glUseProgram(shader);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        //glBegin(GL_TRIANGLES);
        //glVertex2f(-0.5f, -0.5f);
        //glVertex2f(0.0f, 0.5f);
        //glVertex2f(0.5f, -0.5f);
        //glEnd();

        glDrawArrays(GL_TRIANGLES, 0,3);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }
    glDeleteProgram(shader);

    glfwTerminate();
    return 0;
}

不同于之前,这里我使用了新的方法来画三角形。

下面是新的三角形画法:

float positions[6] =
{
    -0.5f, -0.5f,
    0.0f, 0.5f,
    0.5f, -0.5f
};

unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float),positions,GL_STATIC_DRAW);

glEnableVertexAttribArray(0);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

仅靠这些还不能在屏幕上显示出一个三角形,还要继续添加OpenGL渲染的步骤,这些我们待会儿说。

我来逐步解释一下上面代码的作用;

float positions[6] =
{
    -0.5f, -0.5f,
    0.0f, 0.5f,
    0.5f, -0.5f
};

这段代码定义了一个包含三个顶点坐标的数组,每个顶点由两个浮点数表示(X 和 Y 坐标)。这些顶点坐标定义了一个位于屏幕中心的等腰三角形,顶点坐标如下:

  • 第一个顶点:(-0.5, -0.5)
  • 第二个顶点:(0.0, 0.5)
  • 第三个顶点:(0.5, -0.5)

这些坐标被用作顶点数据,可以通过OpenGL的顶点缓冲区对象(VBO)来传递给渲染管线,从而绘制这个三角形。这个代码片段是OpenGL中的基础步骤之一,用于准备顶点数据以进行渲染。

请注意,这里的坐标是以标准化设备坐标(Normalized Device Coordinates,NDC)表示的,范围从 -1 到 1。实际渲染时,这些坐标会经过变换和投影,最终映射到屏幕上的像素位置。

unsigned int buffer;

用于定义一个无符号整数变量 buffer,这个变量通常用来表示OpenGL中的缓冲区对象标识符(如顶点缓冲区对象、帧缓冲区对象等)。

 glGenBuffers(1, &buffer);

是OpenGL函数调用,用于生成缓冲区对象的标识符(ID)。让我解释一下这个函数的作用:

  • glGenBuffers:这是一个OpenGL函数,用于生成一个或多个缓冲区对象的标识符。在这里,我们生成一个缓冲区对象,所以是生成单个标识符。

  • (1, &buffer):这是函数的参数。1 表示生成一个标识符,&buffer 是用于接收生成的标识符的变量的地址。在这里,buffer 是我之前声明的无符号整数变量,用于存储生成的缓冲区对象的标识符。

通过调用这个函数,OpenGL会为我生成一个唯一的标识符,用于标识一个缓冲区对象。之后,你可以通过这个标识符来操作和管理这个缓冲区对象,比如绑定、填充数据等操作。

这个函数很长,不好记忆,那么我们把它拆开看看,

gl是OpenGL函数的前缀,这个是必须要加的,

“gen”是“generate”的缩写,表示生成,

“buffer”表示缓冲区对象,

因此,glGenBuffers 的意思可以理解为“生成缓冲区对象的标识符”。

glBindBuffer(GL_ARRAY_BUFFER, buffer);

是OpenGL中用于绑定缓冲区对象的函数调用。让我解释一下这段代码的含义:

  • glBindBuffer:这是一个OpenGL函数,用于将一个缓冲区对象绑定到OpenGL上下文中的指定缓冲区目标。

  • GL_ARRAY_BUFFER:这是一个缓冲区目标的常量,表示要绑定的缓冲区对象的类型。在这个情况下,它表示顶点缓冲区对象。

  • buffer:这是我之前生成的缓冲区对象的标识符。通过这个标识符,我可以引用特定的缓冲区对象。

通过调用 glBindBuffer(GL_ARRAY_BUFFER, buffer);,将指定的缓冲区对象绑定到OpenGL上下文中的当前顶点缓冲区目标。这意味着后续的顶点数据操作将应用于这个特定的缓冲区对象。

在绑定缓冲区之后,可以使用其他函数来填充数据、配置属性等操作。完成操作后,通常会使用 glBindBuffer(GL_ARRAY_BUFFER, 0); 解绑缓冲区,以确保后续的操作不会影响到这个缓冲区对象。

 同样,我来解释一下这个函数的命名方式,

"bind" 表示将一个对象绑定到OpenGL上下文的特定目标,

综合起来,当我们说 "bind a buffer" 时,意味着将一个缓冲区对象绑定到特定的缓冲区目标,以便后续的操作将作用于这个缓冲区对象。在操作缓冲区对象时,需要使用 bind 来确定正在操作的对象,然后使用 buffer 来描述这个对象的类型。

glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float),positions,GL_STATIC_DRAW);

是一个OpenGL函数,用于将数据上传到缓冲区对象中。让我解释一下这段代码的含义:

  • GL_ARRAY_BUFFER:这是一个缓冲区目标的常量,表示要绑定的缓冲区对象的类型。在这个情况下,它表示顶点缓冲区对象。

  • 6 * sizeof(float):这个参数表示要上传的数据的大小,以字节为单位。在这里,你上传了包含6个浮点数的数据数组,每个浮点数占用4个字节(sizeof(float))。

  • positions:这是一个指向包含要上传数据的数组的指针,即顶点的坐标数据。

  • GL_STATIC_DRAW:这是一个提示,告诉OpenGL你打算如何使用这些数据。在这个情况下,GL_STATIC_DRAW 表示这些数据将不会在绘制过程中被频繁修改,因此OpenGL可以根据需要对内部数据进行优化。

通过调用 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);,将顶点数据上传到绑定到 GL_ARRAY_BUFFER 目标的缓冲区对象中。这样,OpenGL就可以在渲染过程中使用这些数据来绘制图形。

需要注意的是,这只是上传数据到缓冲区对象中的第一步。接下来,可能需要在顶点着色器中设置属性指针,以告诉OpenGL如何解释这些数据,从而正确地渲染图形。

这个函数使用起来比较复杂,我来介绍一下它的函数签名,

void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);

这里是参数的解释:

  • target:缓冲区的目标,表示将数据上传到哪种类型的缓冲区对象。常见的值包括 GL_ARRAY_BUFFER(顶点缓冲区)、GL_ELEMENT_ARRAY_BUFFER(索引缓冲区)等。

  • size:要上传的数据大小,以字节为单位。

  • data:指向要上传的数据的指针。

  • usage:数据使用提示,告诉OpenGL如何使用这些数据,以便优化内存和性能。常见的值包括 GL_STATIC_DRAWGL_DYNAMIC_DRAW 等。

通过调用 glBufferData,你可以将数据上传到指定的缓冲区对象中,以便在渲染过程中使用。

glEnableVertexAttribArray(0);

是一个OpenGL函数,用于启用指定的顶点属性数组。让我解释一下这段代码的含义:

  • 0:这是一个顶点属性的索引,表示要启用的顶点属性数组。在这里,索引为0表示启用顶点位置属性。

通过调用 glEnableVertexAttribArray(0);,你告诉OpenGL要启用顶点位置属性数组,以便在渲染时使用。这是因为在使用顶点缓冲区对象绘制时,你可以将多个顶点属性存储在不同的顶点属性数组中,然后使用 glEnableVertexAttribArray 来启用这些属性数组。

在顶点着色器中,你需要通过指定的属性索引(在这里是0)来访问启用的顶点属性。通过启用和设置多个顶点属性,你可以在渲染过程中使用多个属性来定义顶点的属性,比如位置、法线、颜色、纹理坐标等。

这么写可能不太好理解,让我们用画画来类比,

想象你正在绘制一个彩色的风景画,你有一组颜料盒,每个盒子里装着不同颜色的颜料。你还有几个画笔,每支画笔可以绘制不同的部分。

  • 在OpenGL中,你的画布是屏幕,你的风景是3D模型。
  • 顶点属性数组就像是你的颜料盒,每个属性数组存储不同的顶点属性,比如位置、颜色、纹理坐标等。
  • 每支画笔就是你的顶点着色器,它决定了如何绘制每个顶点。
  • glEnableVertexAttribArray(0); 就相当于告诉你的画笔,你要使用颜料盒中的第一种颜色(索引0),也就是启用位置属性数组。

因此,这句话就是在告诉OpenGL的画笔(顶点着色器):“嘿,我要用位置属性这个颜料盒(属性数组)中的颜色(数据)来绘制我的风景(模型)!” 这样,OpenGL就知道在绘制过程中如何使用顶点属性数据来渲染图形了。

这个函数也比较难以理解,拆开来解释下,

  • gl:OpenGL 库的前缀,表示这个函数是属于OpenGL库的一部分。
  • Enable:启用的意思,表示你要激活或开启某个功能。
  • Vertex:顶点的意思,通常用于表示3D图形中的一个点。
  • AttribArray:属性数组,指的是一组包含顶点属性数据的数组。在OpenGL中,你可以在属性数组中存储顶点的各种属性,如位置、颜色、法线、纹理坐标等。

综合起来,glEnableVertexAttribArray 表示你要启用或开启一个顶点属性数组,以便在OpenGL渲染中使用这些属性数据。这个函数的调用告诉OpenGL,你想要激活某个顶点属性数组,从而在绘制过程中使用这些属性数据来定义模型的特征。

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

让我来解释一下 glVertexAttribPointer 函数的参数:

  • 0:这是顶点属性的索引,表示要设置的顶点属性数组的索引。在这里,索引0表示设置顶点位置属性数组。

  • 2:这是指定每个顶点属性的组件数量。在这里,表示每个顶点位置有两个组件,即 x 和 y 坐标。

  • GL_FLOAT:这是指定顶点属性的数据类型。在这里,表示顶点位置属性的数据类型是浮点数。

  • GL_FALSE:这是一个布尔值,用于指定是否应该将顶点属性的值标准化。在这里,表示不标准化顶点位置属性的值。

  • sizeof(float) * 2:这是指定顶点属性数组中每个顶点属性的字节数。在这里,表示每个顶点位置属性由两个浮点数(每个浮点数占4字节)组成,所以是 sizeof(float) * 2 字节。

  • 0:这是指定顶点属性数组中第一个顶点属性的偏移量。在这里,表示从数组的开头开始。

通过调用 glVertexAttribPointer 函数,你告诉OpenGL如何解释顶点属性数组中的数据。在这个例子中,它告诉OpenGL如何解释顶点位置属性的数据:每个顶点位置由两个浮点数组成,不标准化,每个顶点属性在数组中的偏移量为0。这些设置将在渲染时被顶点着色器使用,以正确地处理顶点位置属性。

把单词拆开来看,

  • gl:OpenGL 库的前缀,表示这个函数是属于OpenGL库的一部分。
  • Vertex:顶点的意思,通常用于表示3D图形中的一个点。
  • Attrib:属性的缩写,表示顶点的一个特征或属性,如位置、颜色、法线等。
  • Pointer:指针的意思,表示指向数据的指针。在这里,它指的是告诉OpenGL如何访问顶点属性数据的指针。

glBindBuffer(GL_ARRAY_BUFFER, 0);

是一个OpenGL函数调用,让我为你解释一下这个函数的作用:

  • gl:OpenGL 库的前缀,表示这个函数是属于OpenGL库的一部分。
  • Bind:绑定的意思,表示把一个对象或资源绑定到OpenGL上下文中,以便在后续的操作中使用。
  • Buffer:缓冲区的意思,表示一个用于存储数据的内存块,通常用于存储顶点数据、纹理数据等。
  • GL_ARRAY_BUFFER:这是OpenGL中的一个常量,表示绑定目标为顶点属性数组的缓冲区。
  • 0:这是一个特殊的值,表示要解绑目标缓冲区。

综合起来,glBindBuffer(GL_ARRAY_BUFFER, 0); 表示你正在将顶点属性数组的缓冲区解绑定,即将之前绑定的缓冲区与顶点属性数组分离。在OpenGL中,通过绑定和解绑缓冲区,你可以在渲染过程中使用不同的缓冲区数据来绘制不同的图形。将目标缓冲区设置为0,表示将当前绑定的缓冲区解绑定,以后的操作将不再影响该缓冲区。

所以,这句代码的作用是取消之前与顶点属性数组绑定的缓冲区,以便后续的操作不再受该缓冲区的影响。文章来源地址https://www.toymoban.com/news/detail-673882.html

到了这里,关于简单着色器编写(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenGL和OpenGL ES显示YUV图片的着色器差别(一)

    这里解释的只是用于显示YUV图片的代码,没有增加任何效果: OpenGL 的片段着色器片段: OpenGL 的顶点着色器片段: OpenGL ES 的片段着色器片段: OpenGL ES的顶点着色器片段: 差别: 添加了  #version 320 es  指令,指定使用 OpenGL ES 3.2 版本。 使用  in  和  out  替代了原来

    2024年02月02日
    浏览(37)
  • OpenGL ES 3.0 着色器程序二进制化

    之前有位读者提问:C++ 如何将 OpenGL ES 的着色器程序二进制(保存),然后在其他地方加载使用?现在写篇文章介绍下。 将着色器程序二进制化(Shader Program Binary)有哪些好处? 快速加载和解析 :使用二进制形式的着色器程序可以更快地加载和解析,因为不需要进行编译和

    2024年02月07日
    浏览(40)
  • OpenGL ES 2.0 for Android教程(二):定义顶点和着色器

    文章传送门 OpenGL ES 2.0 for Android教程(一) OpenGL ES 2.0 for Android教程(三) OpenGL ES 2.0 for Android教程(四) OpenGL ES 2.0 for Android教程(五) OpenGL ES 2.0 for Android教程(六) OpenGL ES 2.0 for Android教程(七) OpenGL ES 2.0 for Android教程(八) OpenGL ES 2.0 for Android教程(九) 本章介绍我们

    2023年04月14日
    浏览(42)
  • OpenGL ES 2.0 for Android教程(三):编译着色器并绘制到屏幕

    文章传送门 OpenGL ES 2.0 for Android教程(一) OpenGL ES 2.0 for Android教程(二) OpenGL ES 2.0 for Android教程(四) OpenGL ES 2.0 for Android教程(五) OpenGL ES 2.0 for Android教程(六) OpenGL ES 2.0 for Android教程(七) OpenGL ES 2.0 for Android教程(八) OpenGL ES 2.0 for Android教程(九) 本章将继续我

    2023年04月26日
    浏览(57)
  • 【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~ 虽然OpenGL的三维制图功能非常强大,但是它主要为计算机设计的,对于嵌入式设备和移动端设备来说显得比较臃肿,所以业界又设计了专供嵌入式设备的OpenGL ES 它相当于OpenGL的精简版,因为嵌入式设备追求性价比,所以能不做的

    2024年02月04日
    浏览(49)
  • vscode shadertoy插件,非常方便的glsl着色器编写工具

    很著名的shadertoy网站,集合了非常多大神利用数学写出美妙的shader效果。像shadertoy创始人之一的IQ大神它在这方面有很多的建树。他的利用光线步进和躁声可以创建很多不可思议的3D场景。  vscode有一件shadertoy的插件,安装后可以新建一个*.glsl文件,写好代码就可以直接运行看

    2024年04月09日
    浏览(33)
  • OpenGL ES入门教程(一)编写第一个OpenGL程序

    从本文开始我将参考学习OpenGL ES应用开发实践指南 Android卷 [(美)KevinBrothaler著](提取码: 394m),并基于自己的理解以更加通俗易懂的方式讲解如何应用OpenGL ES。本系列教程的目标是应用OpenGL,所以不会涉及太多的理论知识,主要讲解方式是基于简单功能的代码拆解,学会对

    2024年02月06日
    浏览(47)
  • 让AI臣服,而不是被它替代!让ChatGPT为我们编写Unity3d Shaderlab的着色器(shader)

    ChatGPT的火热大家应该都有目共睹,文案工作者、翻译工作者和画师等各种行业都在被嘲即将失业。不光是这些岗位的员工,作为资深社畜程序猿也能感受到会受到冲击。网上很多人都在发ChatGPT写的代码,并开始大肆宣扬AI要取代程序员了,今天测一测使用ChatGPT来生成一些代码,

    2023年04月23日
    浏览(45)
  • 计算机图形学,OpenGL编写的一个可实现旋转缩放移动的房间,内有数十种交互

    #include stdlib.h #includestdio.h #includewindows.h #include GL/glut.h #include math.h #include gl/GLU.h //颜色宏定义 #define white 1.0f, 1.0f, 1.0f #define black 0.0f, 0.0f, 0.0f #define red 1.0f, 0.0f, 0.0f #define blue 0.0f, 0.0f, 1.0f #define skyBlue 135.0/255.0, 206.0/255.0, 1.0f #define plum 1.0f, 187.0/255.0, 1.0f //浅紫色 #define pink 1.0f, 1

    2024年04月17日
    浏览(63)
  • 实验二:OpenGL的简单动画

    一、实验目的 1.掌握OpenGL的闲置函数。 2.掌握OpenGL的时间函数。 3.掌握OpenGL的简单动画功能。 4.了解OpengGL裁剪窗口、视区、显示窗 口的概念和它们之间的关系。 5.进一步掌握OpenGL基本图元的绘制。 二、实验内容 1.闲置函数的使用与简单动画。 1)旋转的六边形如实验图2-1所

    2024年02月05日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包