OpenGL教程(四)

前言

片段着色器(Fragment shader)

片段着色器是我们需要编写的第二个也是最后一个着色器程序,其主要用于计算每一个像素的颜色,在例子中为了简单我们会将每个颜色设置为橘黄色。

计算机中的颜色是由一个四维数组组成的,分别是红、绿,蓝以及透明度,通常被称为RGBA,在OpenGL或者GLSL中定义一个颜色需要吧每个部分定义到0.0和1.0之间,例如我们将红色和绿色都设置为1.0,那么就会得到二者混合之后的颜色黄色。

片段着色器只需要一个输出变量,其是一个四维向量,需要我们自己计算得出最后的颜色,对于输出的结果,我们可以使用out关键字,在三角形这个例子中,我们命名为FragColor,并将其颜色设置为橘黄色,将透明度设置为1,也就是完全不透明。

#version 330 core
    out vec4 FragColor;

    void main()
    {
        FragColor = vec4(1.0, 0.5f, 0.2f, 1.0f);
    }
}

片段着色器的编译过程与顶点着色器类似,其中需要注意的是将着色器的类型设置为GL_FRAGMENT_SHADER

unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader)

现在已经将需要的着色器都已经编译了,现在需要做的就是将编译好的着色器对象链接到我们之后需要使用的着色器程序,需要注意的是要检查编译着色器是否出错。

着色器程序

一个着色器程序对象是将多个着色器组合的结果,为了使用最近编译的着色器程序我们需要将这些着色器程序链接到着色器程序,然后在渲染对象的时候激活着色器对象,当我们调用渲染函数的时候就可以使用激活的着色器程序的着色器。

当我们将一个着色器链接进一个着色器程序的时候,每一个着色器的输出都是下一个着色器的输入,所以当输入与输出不匹配会引起错误。可以通过以下代码创建一个着色器程序:

unsigned int shaderProgram;
shaderProgram = glCreateProgram();

函数glCreateProgram会创建一个着色器程序并返回器创建对象的ID,在创建好着色器程序后,需要将编译好的着色器对象链接进着色器程序:

glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

与检查着色器编译相同,我们也需要检查链接的过程是否出错,

int success;
    char infoLog[512];
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
    }

现在已经创建了着色器程序,然后可以通过glUseProgram函数来激活。

glUseProgram(shaderProgram);

需要注意的是一旦我们将着色器编译进着色器程序后我们就不再需要着色器对象了,需要使用glDeleteShader将着色器对象删除:

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

现在我们已经将数据传输到GPU,且通过编写顶点着色器和片段着色器规定了GPU该如何处理顶点数据,但是现在OpenGL还不知道如何将顶点数据转化为顶点着色器的属性。顶点着色器允许我们任何我们想要的输入,只要这些输入符合顶点属性的格式,这带来了很大的灵活性,与此同时也以为着我们需要手动指定我们输入数据的哪一部分对应顶点属性的哪一部分,这也意味着我们需要指定在渲染前OpenGL该如何解释顶点数据。

我们的顶点缓冲数据是以下面这种形式组织的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iMISDT9i-1668436204057)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/959094ed287c41058af57427266f3af5~tplv-k3u1fbpfcp-watermark.image?)]

  • 位置数据被存储为32-bit(4个byte)的浮点值
  • 每个位置由三个这样的值组成
  • 三个值之间没有空隙,紧密排列在一个数组中
  • 数据的第一个值就是缓冲区域的开头

知道了顶点数据的排列形式,我们就可以通过glVertexAttribPointer告诉OpenGL该如何获取顶点数据(每一个顶点属性):

glVertexAttribPointer(0, 3, GL_POINT, GL_FALSE, 3 * sizeof(float), (void*) 0);
glEnableVertexAttribArray(0);

glVertexAttribPointer的参数较为复杂,其含义如下:

  • 其中的第一个参数指定我们想要配置哪一个顶点属性,在我们编写顶点着色器时,通过layout(location = 0)将定位的位置属性的loaction设置为0,所以这里我们将第一个属性设置为0。
  • 第二个参数指定顶点属性的大小,位置是一个vec3的三维向量,所以这里设置为3。
  • 第三个参数指定数据的类型,这里是GL_FLOAT。
  • 第四个参数是指定是否我们想要将我们的数据归一化,暂时与我们无关设置为GL_FALSE。
  • 第五个参数是步长,这个参数规定连续的顶点属性的偏移量,由于每个顶点都是由三个浮点数组成,然后每个顶点数据之间没有间隔,所以偏移量就是3个浮点数。
  • 最后一个参数是缓冲区域开始的偏移量,这是设置为0。

每一个顶点属性都是从VBO管理的内存中获取数据,内存中有很多VBO,那么该如何确定是哪一个VBO呢,调用glVertexAttribPointer

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值