高频更新中,内容可能滞后或有变动

效果展示:

123

简介

在认真阅读并学习了WebGL Programming Guide一书后,萌生了制作一个Web端渲染器的想法。由于Web端的全平台特性,之后做了什么材质特效,可以在这个平台上制作展示效果后,无论是手机还是什么设备都可以实时观看,同时也可以很方便地以iframe的形式插入到博文中,顺便还能找机会学学web三件套,可谓是一举多得。

虽然我基本是完全没用过web三件套,但是我不信我硬写写不出来,直接开干。

结果,嘿,您猜怎么着?还真给我写出来了!

界面以及操作

预期要实现的功能为:可以编写简单脚本;可以修改shader并看到效果;可以旋转摄像机,放大缩小;

界面展示

  • 在示例项目中,使用了SimpleRotateCamera作为摄像机,所以在视口左键可以旋转视角,右键可以缩放;
  • 点击右下角标签可以显示我自己实现的代码编辑器,在其中有指定想要编辑的脚本和shader,编辑后点击右下角应用即可;
  • 代码编辑器中第一个Script是场景脚本,可以随意修改场景相关逻辑,其他的则是指定的editableShaderList中的shader;

设计框架介绍

  • 整体为一个WebGLRenderer类,其中有表示场景的Scene类和负责代码编辑器的CodeEditor类
  • Scene类中储存着渲染需要用到的各种资源,渲染的基本单位为Mesh类
  • Actor类为可放置在世界中物品的基类,从其中派生出了Mesh、Light、Camera类。其中Mesh为可渲染的物品,包含一个模型(Model类)和一个材质(Material类);Light为灯光;Camera为摄像机;
  • Model类是3D模型,通过读入的Obj文件加载(现在只支持三角面,且面数小于2w);
  • Material类是材质类,包含三个着色器(Shader类):Base、Add、ShadowCaster,分别负责主要光源着色、其他光源着色、阴影投射。玩家赋予的材质参数及其值也会储存在其中;
  • Shader类是着色器类,包括顶点着色器和片段着色器,通过读入的GLSL文件编译生成着色器代码。

制作教程

  1. 【WebGL】从零开始的Web端渲染器(1)——框架搭建
  2. 【WebGL】从零开始的Web端渲染器(2)——添加阴影
  3. 【WebGL】从零开始的Web端渲染器(3)——法线贴图
  4. 【WebGL】从零开始的Web端渲染器(4)——贴图及阴影抗锯齿(还在写)

使用教程

可编辑Script

控制整个场景的生成以及运行逻辑的脚本,在确认修改后会刷新渲染器重新开始渲染。整体而言还算比较复杂,所以基本上只用修改,不用删掉重写。

脚本结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 新建场景内各类元素
// 包括相机 灯光 材质 模型 Mesh 贴图等;
let camera = new Camera(...); //也可以使用SimpleRotateCamera
let light = new Light(...);

// 材质由shader组成 shader由顶点和片段着色器文件组成
let shadowCaster = new Shader('...', '...');
let texShader = new Shader('...', '...');
let texMaterial = new Material(texShader, shadowCaster);

// Mesh为可渲染对象 由一个模型和一个材质组成
let cube = new Model('...');
let meshCube = new Mesh(new Transform(), cube, texMaterial);

// 根据具体情况 可能需要新建贴图
let textureOnion = new Texture('...', gl.TEXTURE_2D);

// 要编辑代码的Shader列表
this.codeEditor.editableShaderList = [texShader];
// 清屏颜色
this.clearColor = [0.1, 0.1, 0.11, 1.0];

// 构建场景函数
this.bulidScene = (scene) =>
{
// 需要构建的有 模型列表 材质列表 贴图列表
// Mesh列表 灯光列表 摄像机
// 只有传入Scene的资源会被初始化 未传入的资源不会被初始化 在运行时无法使用
scene.modelList = [cube, sphere, plane];
scene.materialList = [diffuseMaterial, texMaterial];
scene.textureList = [textureSky, textureOnion];
scene.meshList = [meshCube, floor];
scene.lightList = [light];
scene.camera = camera;
}

// 自定义开始游戏函数 在开始渲染时运行一次
this.customBeginPlay = () =>
{
// 写一些只用在开始时运行一次的逻辑
texMaterial.setVector3f('...', 0.2, 0.2, 0.2);
texMaterial.setTexture('...', textureOnion);
}

// 自定义Tick函数 渲染时逐帧运行
this.customTick = (deltaSecond) =>
{
// 写一些需要逐帧运行的逻辑
meshCube.addRotationOffset(new Vector3([0, 1.5, 0]).multiplyf(deltaSecond));
}

// 在下方可以写其他函数

各种类的构造函数请看API。

可用资源

图片资源(/Res/Image/)

有一些简单的测试用图片;

  • Test.jpg:魂三洋葱哥Q版,1k;
  • Sky.jpg:WebGL Programming Guide使用的天空贴图,256*256;
  • Drop.png:简单的蒙版贴图,512*512;

材质贴图资源(/Res/Material/)

各种PBR材质贴图(虽然我这还没实现PBR渲染罢),BC (Base Color) N (Normal) R(Roughness) M (Metallic) AO (Ambient Occlusion);

  • Floor_BC、Floor_N、Floor_R、Floor_AO:Quixel Megascans下的Stone_Floor贴图资源,1k;
  • Pavement_BC、Pavement_N、Pavement_R:步行街道资源,1k;

3D模型资源(/Res/Model/)

常用以及测试用3D模型;

  • Cube.obj、Plane.obj、Quad.obj、Sphere.obj:最基础的简单模型;
  • Bunny5k.obj:斯坦福兔模型,5k面;
  • Suzanne.obj:猴头模型;

默认Shader(/DefaultShader/)

  • DefaultVert.vert:常用的顶点着色器,传出v_TexCoord、v_WorldNormal、v_WorldTangent、v_WorldBinormal、v_viewDir和v_PositionFromLight(用于计算阴影),正常使用基本够用。
  • Diffuse.frag、DiffuseBC.frag、DiffuseBCN.frag:简单的漫反射材质,bc为带基础色贴图,n为法线贴图;
  • Specular.frag、SpecularBC.frag、SpecularBCN.frag:简单的高光反射材质,bc为带基础色贴图,n为法线贴图;
  • ShadowCaster.vert、ShadowCaster.frag:阴影投射shader,一般不用改,除非是顶点动画。
  • S_BCNRAO.frag:用于高品质PBR材质的渲染,需要BC、N、R、AO贴图(金属度还没实现)

API

Scene

Scene(modelList, materialList, textureList, meshList, lightList, camera)

整个场景,只有输入的资源会被加载

输入名称 类型 描述 默认值
modelList Model[] 需要加载的模型 null
materialList Material[] 需要加载的材质 null
textureList Texture[] 需要加载的贴图 null
meshList Mesh[] 场景内的Mesh null
lightList Light[] 场景类的光源 null
camera Camera 渲染所用相机 null

Actor

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

Actor(transform)

一个具有Transform属性的,可以被放置在世界中的物体,是所有可以被放置在世界中的物体的基类。

输入名称 类型 描述 默认值
transform Transform 变换 new Transform()

getLocation() -> Vector3

返回位移信息

返回:位移的拷贝

getRotation() -> Vector3

返回旋转信息

返回:旋转的拷贝

getScale() -> Vector3

返回缩放信息

返回:缩放的拷贝

setLocation(location)

设置位置

输入名称 类型 描述 默认值
location Vector3 位置信息 null

setRotation(rotation)

设置旋转值

输入名称 类型 描述 默认值
rotation Vector3 旋转信息 null

setLocationAndRotation(location, rotation)

设置位置和旋转值

输入名称 类型 描述 默认值
location Vector3 位置信息 null
rotation Vector3 旋转信息 null

setScale(scale)

设置缩放值

输入名称 类型 描述 默认值
scale Vector3 缩放信息 null

addLocationOffset(offset)

添加位移偏移

输入名称 类型 描述 默认值
offset Vector3 位移偏移 null

addRotationOffset(offset)

添加旋转偏移

输入名称 类型 描述 默认值
offset Vector3 旋转偏移 null

getRotationMatrix() -> Matrix4

获取旋转矩阵

返回值:旋转矩阵

getForwardVector() -> Vector3

获取向前向量

返回值:向前向量

getUpVector() -> Vector3

获取向上向量

返回值:向上向量

getRightVector() -> Vector3

获取向右向量

返回值:向右向量

distanceToActor(actor) -> Number

返回与另一个Actor的距离

输入名称 类型 描述 默认值
actor Actor 另一个Actir null

返回值:距离

Mesh(继承自Actor)

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

Mesh(transform, model, material, bCastShadow)

可以被渲染的Actor 有一个Model和一个Material

输入名称 类型 描述 默认值
transform Transform 变换 null
model Model 模型 null
material Material 材质 null
bCastShadow boolean 投射阴影 true

setCastShadow(bCastShadow)

设置是否投射阴影

输入名称 类型 描述 默认值
bCastShadow boolean 投射阴影 null

copy() -> Mesh

复制一个相同的Mesh出来

返回值:复制的Mesh

Light(继承自Actor)

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

Light(transform, lightColor, intensity, lightType)

照亮场景的灯光,种类为LIGHT_TYPE,目前只实现了定向光。默认shadow map分辨率为2k。

输入名称 类型 描述 默认值
transform Transform 变换 null
lightColor Vector3 光照颜色 new Vector3([1, 1, 1])
intensity Number 强度 1
lightType LIGHT_TYPE 光源类型 LIGHT_TYPE.DIRECTIONAL

Camera(继承自Actor)

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

Camera(transform, FOV, nearClip, farClip)

最简单的渲染世界的摄像机

输入名称 类型 描述 默认值
transform Transform 变换 null
FOV Number 视野角度 60
nearClip Number 近剪裁平面 0.1
farClip Number 远剪裁平面 100

SimpleRotateCamera(继承自Camera)

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

SimpleRotateCamera(lookAtPoint, distance, FOV, nearClip, farClip)

始终看向一点,并可以绕其旋转的相机

输入名称 类型 描述 默认值
lookAtPoint Vector3 看向的目标点 new Vector3([0, 0, 0])
distance Number 距目标点的距离 6 (2 ~ 10)
FOV Number 视野角度 60
nearClip Number 近剪裁平面 0.1
farClip Number 远剪裁平面 100

Shader

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Shader.js

Shader(vShaderFile, fShaderFile)

着色器,由顶点着色器和片元着色器文件组成

输入名称 类型 描述 默认值
vShaderFile String 顶点着色器路径 null
fShaderFile String 片元着色器路径 null

Material

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Material.js

Material(baseShader, shadowCaster, materialType, queueOffset)

材质,需要一个Base着色器与阴影投射着色器,种类有MATERIAL_TYPE

输入名称 类型 描述 默认值
baseShader Shader Base着色器 用于计算主光源 null
shadowCaster Shader 阴影投射着色器 用于投射阴影 null
materialType MATERIAL_TYPE 材质类型 MATERIAL_TYPE.OPAQUE
queueOffset Number 渲染队列偏移 0

setMaterialType(materialType, offset)

设置材质类型

输入名称 类型 描述 默认值
materialType MATERIAL_TYPE 材质类型 null
offset Number 渲染队列偏移 null

setBlendFactor(srcFactor, desFactor)

设置混合系数

输入名称 类型 描述 默认值
srcFactor GLenum 源混合系数 null
desFactor GLenum 目标混合系数 null

setCullMode(cullMode)

设置材质剔除模式系数

输入名称 类型 描述 默认值
cullMode CULL_MODE 剔除模式 null

setVector3f(param, x, y, z)

设置Shader三维参数

输入名称 类型 描述 默认值
param String 参数名称 null
x Number x 0
y Number y 0
z Number z 0

setVector4f(param, x, y, z, w)

与上面的类似

setTexture(param, texture)

与上面的类似

Model

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Model.js

Model(objFile, scale)

模型为Obj格式3D模型文件,目前只支持三角面

输入名称 类型 描述 默认值
objFile String Obj文件路径 null
scale Number 模型缩放 1

Texture

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Texture.js

Texture(texFile, texType)

贴图文件,会自动绑定到Texture Unit

输入名称 类型 描述 默认值
texFile String 贴图文件路径 null
texUnit GLenum 贴图类型 gl.TEXTURE_2D

Transform

代码:https://github.com/1keven1/WebGLRenderer/blob/main/Actor.js

Transform(location, rotation, scale)

储存变换信息的结构体

输入名称 类型 描述 默认值
lodation Vector3 位移 new Vector3([0, 0, 0])
rotation Vector3 旋转 new Vector3([0, 0, 0])
scale Vector3 缩放 new Vector3([0, 0, 0])

copy() -> Transform

复制一份Transform出来

返回值:复制出的Transform

Vector3

更新中…

可以看这里:https://github.com/1keven1/WebGLRenderer/blob/main/Lib/cuon-matrix.js

和这里:https://github.com/1keven1/WebGLRenderer/blob/main/FunctionLibrary.js

枚举值

LIGHT_TYPE

光源种类

  • DIRECTIONAL:定向光照
  • POINT:点光源
  • SPOT:聚光灯

MATERIAL_TYPE

材质类型(影响混合模式、深度检测和渲染队列)

  • OPAQUE:不透明
  • MASKED:遮罩
  • TRANSLUCENT:半透明
  • ADDITIVE:叠加

CULL_MODE

剔除模式

  • BACK:剔除背面
  • FRONT:剔除正面
  • OFF:关闭剔除

其他函数库

代码:https://github.com/1keven1/WebGLRenderer/blob/main/FunctionLibrary.js

clamp(float, min, max) => Number

将输入值钳制在上下限之间

输入名称 类型 描述 默认值
float Number 输入数据 null
min Number 下限 0
max Number 上限 1

返回值:钳制后的值

fInterpTo(current, target, deltaSecond, interpSpeed) => Number

对浮点数向目标值进行平滑差值,距离越近速度越慢

输入名称 类型 描述 默认值
current Number 当前值 null
target Number 目标值 null
deltaSecond Number 世界Delta Time null
interpSpeed Number 插值速度 null

返回值:下一帧的值

isPowerOf2(number) => Boolean

判断某个数是否是二的整数次幂

输入名称 类型 描述 默认值
number Number 要检测的数 null

返回值:是否是二的次幂