Real-Time 3D Graphics with WebGL 2
上QQ阅读APP看书,第一时间看更新

Vertex Shader

Let's cover a sample vertex shader:

#version 300 es

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat4 uNormalMatrix;
uniform vec3 uLightDirection;
uniform vec3 uLightDiffuse;
uniform vec3 uMaterialDiffuse;

in vec3 aVertexPosition;
in vec3 aVertexNormal;

out vec4 vVertexColor;

void main(void) {
vec3 normal = normalize(vec3(uNormalMatrix * vec4(aVertexNormal, 1.0)));

vec3 lightDirection = normalize(uLightDirection);

float LambertianTerm = dot(normal, -lightDirection);

vVertexColor = vec4(uMaterialDiffuse * uLightDiffuse * LambertianTerm,
1.0);

gl_Position = uProjectionMatrix * uModelViewMatrix *
vec4(aVertexPosition, 1.0);
}

On first inspection, we can identify the attributes, uniforms, and varyings that we will use, along with some matrices that we will discuss later. We can also see that the vertex shader has a main function that does not accept parameters and instead returns void. Inside, we can see some ESSL functions, such as normalize and dot, along with some arithmetical operators.

#version 300 es

This string must be the very first line of your shader. No comments or blank lines are allowed before it!  #version 300 es tells WebGL that you want to use WebGL 2's shader language (GLSL ES 3.00). If that isn’t written as the first line, the shader language defaults to WebGL 1.0's GLSL ES 1.00, which has fewer features.

There are three uniforms that we haven’t discussed yet:

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat4 uNormalMatrix;

We can see that these three uniforms are 4x4 matrices. These matrices are required in the vertex shader to calculate the location for vertices and normals whenever we move the camera. There are a couple of operations here that involve using these matrices:

vec3 normal = normalize(vec3(uNormalMatrix * vec4(aVertexNormal, 1.0)));

The previous line of code calculates the transformed normal:

gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);

This line calculates the transformed vertex positiongl_Position is a special output variable that stores the transformed vertex position.

We will come back to these operations in Chapter 4, Cameras. For now, we should acknowledge that these uniforms and operations deal with camera and world transformations (rotation, scale, and translation).

Returning to the main function’s code, we can clearly see that the Lambertian reflection model is being implemented. The dot product of the normalized normal and light direction vector is obtained and then multiplied by the light and material diffuse components. Finally, this result is passed into the vVertexColor varying to be used in the fragment shader, as follows:

vVertexColor = vec4(uMaterialDiffuse * uLightDiffuse * LambertianTerm, 1.0);

Also, as we are calculating the color in the vertex shader and then automatically interpolating it for the fragments of every triangle, we are using the Goraud interpolation method.