跳到主要内容

材质颜色

每个物体都有自己的颜色,颜色可以数字化地由红色、绿色和蓝色三个分量组成,通常被缩写为RGB。例如,要获取一个alice蓝的话,我们可以这样定义:

// 用rgba值定义颜色
auto color = _clr3(0.941, 0.973, 1.000);
// 直接采用color库中定义好的颜色接口
auto color1 = _aliceblue();

我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的颜色。换句话说,那些不能被物体所吸收的颜色就是我们能够感知到的物体的颜色。上面定义的材质颜色是它在白色光源下能被我们感知到的颜色,但如果光源是其他颜色,那么最终的颜色向量就是:

auto lightColor = _clr3(0.0, 1.0, 1.0);
resultColor = color * lightColor;

在引擎中有以下几种方式直接定义几何的颜色属性:

  • 通过材质的Uniform参数定义
  • 通过顶点缓冲定义
提示

由于这些定义过程比较繁琐,我们在材料库中将这些方法封装为简单的材质接口,您可以参考:使用材质库

颜色作为Uniform参数

可以在创建材质时,直接为它定义颜色属性。这个颜色属性是包含在material的parameter参数中,下面的例子中,材质中的颜色属性名称为color,然后在fragment shader也声明一个uniform变量:color,参与计算从而得到最终的颜色输出fragColor。

std::string vertexSource = R"(
#version 330 core

in vec2 positions;

void main()
{
gl_Position = vec4(positions, 0.0, 1.0);
}
)";

std::string fragmentSource = R"(
#version 330 core

out vec4 fragColor;
uniform vec3 color;

void main()
{
fragColor = vec4(color, 1.0);
}
)";

auto material = _material(
_program(
vertexSource, fragmentSource
),
_parameters({
{"color", _clr3(0.4, 0.6, 0.2)}
})
);

运行程序,可以看到下面这样的效果:

texture

颜色作为VBO

上面介绍的uniform color是程序与着色器之间进行数据交互的一类工具,但如果我们需要为每个顶点设置不同颜色,从而形成渐变效果的时候,就需要采用下面的方法了。

我们从之前的几何教程中,已经了解了如何利用VBO定义几何顶点位置,这里我们也利用VBO定义顶点颜色,比如下面这个例子中所做的。

auto geometry = _geometry(
{
{"positions", _vertices({-0.5, -0.5, 0.5, -0.5, 0.0, 0.5})},
// 三个顶点分别是红、绿、蓝色
{"colors", _vertices({1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0})},
},
_triangles(3)
);

然后我们将顶点颜色数据发送到顶点着色器中,只要将它作为做一个顶点属性输入就行。

std::string vertexSource = R"(
#version 330 core

in vec2 positions;
// 将color VBO作为输入变量
in vec3 colors;
// 定义一个输出变量,传递到fragment shader中
out vec3 v_Color;

void main()
{
gl_Position = vec4(positions, 0.0, 1.0);
v_Color = colors;
}
)";

std::string fragmentSource = R"(
#version 330 core

out vec4 fragColor;
// 不再使用uniform类型,而是使用从vertex shader传输进来的v_Color
in vec3 v_Color;

void main()
{
fragColor = vec4(v_Color, 1.0);
}
)";

auto material = _material(
_program(
vertexSource, fragmentSource
)
);

运行程序,我们可以看到下面的效果:

texture