创建canvas上下文
'use strict';
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
// make a canvas with text in the center
const makeTextCanvas = (text, width, height, color) => {
const ctx = document.createElement('canvas').getContext('2d')
ctx.canvas.width = width
ctx.canvas.height = height
ctx.font = `bold ${height * 5 / 6 | 0}px sans-serif`
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillStyle = color
ctx.fillText(text, width / 2, height / 2)
return ctx.canvas
};
顶点着色器
const vsGLSL = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 projection;
uniform mat4 modelView;
varying vec3 v_normal;
varying vec2 v_texcoord;
void main() {
gl_Position = projection * modelView * position;
v_normal = mat3(modelView) * normal;
v_texcoord = texcoord;
}
`;
变量声明部分
- attribute vec4 position
- 声明一个四维向量属性变量 "position",用于接收输入的顶点位置信息。每个顶点都有一个唯一的位置坐标,这个坐标通常是在模型空间中定义
- attrbute vec3 normal;
- 声明一个三维向量属性变量"normal",用于接收输入的顶点法线信息。顶点法线表示物体表面在该顶点处的朝向,对于光照计算非常重要
- attribute vce2 texcoord;
- 声明一个二维向量属性变量"texcoord",用于接收输入的顶点纹理坐标信息。纹理坐标用于确定如何从纹理图像中采样颜色值来应用到顶点上。
- uniform mat4 projection;
- 声明一个四维矩阵统一变量"projection",用于接收从应用程序传递过来的投影矩阵。投影矩阵定义了将3D场景投影到2D屏幕上的方式。
- uniform mat4 modelView;
- 声明一个四维矩阵统一变量"modelView",用于接收从应用程序传递过来的模型视图矩阵。模型视图矩阵是模型矩阵和视图矩阵的组合,用于将顶点从模型空间转换到视图空间。
varying变量部分
- varying vec3 v_normal;
- 声明一个三维向量可变变量“v_normal"。这个变量在顶点着色器中被赋值,并在后续的片段着色器中使用。它用于传递顶点法线信息从顶点着色器到片段着色器。
- varying vec2 v_texcoord;
- 声明一个二维向量可变变量"v_texcood"。同样,这个变量将在顶点着色器中被赋值,并在后续的片段着色中使用,用于传递顶点的纹理坐标信息。
主函数部分
- gl_Position = projection * modelView * position;
- 计算顶点在裁剪空间中的位置。首先将顶点的位置向量"position" 依次乘以模型视图矩阵"modelView" 和投影矩阵“projection”,得到最终在裁剪空间中的坐标。这个坐标将用于后续的裁剪和光栅化等渲染流程。
- v_normal = mat3(modelView) * normal;
- 将顶点的法线向量"normal"从模型空间转换到视图空间。通过提取模型矩阵的3x3部分(只考虑旋转和平移),然后与发现向量相乘,得到在视图空间中的法线向量,并将其存储在"v_normal"变量中,以便在片段着色器中进行光照计算。
- v_texcoord = texcoord;
- 将输入的顶点纹理坐标"texcoord"直接赋值给可变变量v_texcoord,以便在片段着色器中使用该纹理坐标从纹理图像中采样颜色值。
片元着色器
const fsGLSL = `
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord;
uniform sampler2D diffuse;
uniform sampler2D decal;
uniform vec4 diffuseMult;
uniform vec3 lightDir;
void main() {
vec3 normal = normalize(v_normal);
float light = dot(normal, lightDir) * 0.5 + 0.5;
vec4 color = texture2D(diffuse, v_texcoord) * diffuseMult;
vec4 decalColor = texture2D(decal, v_texcoord);
decalColor.rgb *= decalColor.a;
color = color * (1.0 - decalColor.a) + decalColor;
gl_FragColor = vec4(color.rgb * light, color.a);
}
`;
变量声明部分
- precision highp float;
- 设置浮点数的精度为高精度。有助于提高计算的准确性,但可能会对性能产生一定影响
- varying vec3 v_normal;
- 接收从顶点着色器传递过来的在视图空间中的顶点法线向量。
- varying vec2 v_texcoord;
- 接收从顶点着色器传递过来的顶点纹理坐标。
- uniform sampler2D diffuse;
- 声明一个二维纹理采样统一变量,用于名为"diffuse"的纹理图像中采样颜色值。通常这是物体的基本颜色纹理。
- uniform sampler2D decal;
- 声明一个二维纹理采样统一变量,用于名为"decal"的纹理图像中采样颜色值
- uniform vec4 diffuseMult;
- 声明一个四维向量统一变量,用于对基本颜色纹理进行缩放。可以用来调整物体的整体颜色强度。
- uniform vec3 lightDir;
- 声明一个三维向量统一变量,代表光照方向。
主函数部分
- vec3 normal = normalize(v_normal);
- 对从顶点着色器传递过来的法线向量进行归一化处理,确保其长度为1,以便在光照计算中使用准确的法线方向。
- float light = dot(normal,lightDir) * 0.5+0.5;
- 计算光照强度。通过计算归一化后的法线向量和光照方向向量的点积,得到一个值在[-1,1]质检的结果,这个结果标识法线与光照方向的夹角余弦值,然后将这个结果乘以0.5并加上0.5,使其范围变为[0,1],得到最终的光照强度值。
- vec4 color = texture2D(diffuse,v_texcoord) * diffuseMult;
- 从基本颜色纹理"diffuse"中,根据顶点的纹理坐标“v_texcoord”采样颜色值,并将其与"diffuseMult"相乘,得到物体的基本颜色。
- vec4 decalColor = texture2D(decal,v_texcoord)
- 从贴花纹理"decal"中,根据顶点的纹理坐标"v_texcoord"采样颜色值,得到贴花的颜色。
- decalColor.rgb *= decalColor.a;
- 将贴花颜色的RGB分量乘以其透明度分量"decalColor.a",实现透明效果。如果透明度为0,则贴花颜色完全透明(黑色)。
- color = color * (1.0- decalColor.a) + decalColor;
- 将基本颜色和贴花进行混合。首相将基本颜色乘以(1-贴花透明度),然后加上贴花颜色,实现贴花覆盖在基本颜色上的效果。
- gl_FragColor = vec4(color.rgb * light,color.a);
- 最终确定片段的颜色。将混合后的颜色的RGB分量乘以光照强度“light”,得到受光照影响的颜色,并将透明度分量保持不变,存储在输出变量"gl_FragColor"中,用于最终渲染。