three材质shader分析
three材质shader分析
参考资料
- https://github.com/mrdoob/three.js
- https://juejin.cn/post/6964935853671972878
- https://www.cnblogs.com/zzatp/p/9274074.html
- https://juejin.cn/post/6977667236576591908
three材质的shader
three的shader位于如下的目录中,简单来说/ShaderLib
文件夹为每个材质对应的shader
,/ShaderChunk
内则为各个材质所需要的shader中所需函数、变量与常量。ShaderChunk.js
则引用前面两个所有的文件。UniformsLib.js
为shader
所需要的Uniform
变量,UniformsUtils.js
则为Uniform
工具函数。ShaderLib.js
将各个材质所需的shader
与Uniforms
组装后返回的map对象
1 | src/renderers |
基础网格材质(MeshBasicMaterial)
基础网格材质作为基础材质,包含了网格基础以及颜色和贴图相关shader
处理代码,该种材质不受光照的影响,所以不包含光照相关的shader
顶点shader
1 | // vertex shader |
片段shader
1 | // fragment |
Lambert网格材质(MeshLambertMaterial)
一种非光泽表面的材质,没有镜面高光。
该材质使用基于非物理的Lambertian模型来计算反射率。 这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。
使用Gouraud着色模型计算着色。这将计算每个顶点的着色 (即在vertex shader中)并在多边形的面上插入结果。
像较与基础网络材质,Lambert材质多了对光照与阴影的处理,其中的color
属性对应在光照下所计算的反射颜色,emissive
对应材质本身的颜色
在顶点sahder中lambert对光照和阴影分别做了处理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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129// vertex
vec3 diffuse = vec3( 1.0 );
GeometricContext geometry;
geometry.position = mvPosition.xyz;
geometry.normal = normalize( transformedNormal );
geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );
GeometricContext backGeometry;
backGeometry.position = geometry.position;
backGeometry.normal = -geometry.normal;
backGeometry.viewDir = geometry.viewDir;
vLightFront = vec3( 0.0 );
vIndirectFront = vec3( 0.0 );
vLightBack = vec3( 0.0 );
vIndirectBack = vec3( 0.0 );
IncidentLight directLight;
float dotNL;
vec3 directLightColor_Diffuse;
vIndirectFront += getAmbientLightIrradiance( ambientLightColor );
vIndirectFront += getLightProbeIrradiance( lightProbe, geometry.normal );
// 对应材质中的 side属性
// 判断两面都渲染的情况
vIndirectBack += getAmbientLightIrradiance( ambientLightColor );
vIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry.normal );
// 处理点光源
for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
getPointLightInfo( pointLights[ i ], geometry, directLight );
dotNL = dot( geometry.normal, directLight.direction );
directLightColor_Diffuse = directLight.color;
vLightFront += saturate( dotNL ) * directLightColor_Diffuse;
vLightBack += saturate( - dotNL ) * directLightColor_Diffuse;
}
// 处理聚光灯(SpotLight)
for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
getSpotLightInfo( spotLights[ i ], geometry, directLight );
dotNL = dot( geometry.normal, directLight.direction );
directLightColor_Diffuse = directLight.color;
vLightFront += saturate( dotNL ) * directLightColor_Diffuse;
vLightBack += saturate( - dotNL ) * directLightColor_Diffuse;
}
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
getDirectionalLightInfo( directionalLights[ i ], geometry, directLight );
dotNL = dot( geometry.normal, directLight.direction );
directLightColor_Diffuse = directLight.color;
vLightFront += saturate( dotNL ) * directLightColor_Diffuse;
vLightBack += saturate( - dotNL ) * directLightColor_Diffuse;
}
for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {
vIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );
vIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry.normal );
}
1
2
3
4
5
uniform vec3 emissive;
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
vec3 totalEmissiveRadiance = emissive;
Phong网格材质(MeshPhongMaterial)
该材质使用非物理的Blinn-Phong模型来计算反射率。 与MeshLambertMaterial中使用的Lambertian模型不同,该材质可以模拟具有镜面高光的光泽表面(例如涂漆木材)。
使用Phong着色模型计算着色时,会计算每个像素的阴影(在fragment shader, AKA pixel shader中),与MeshLambertMaterial使用的Gouraud模型相比,该模型的结果更准确,但代价是牺牲一些性能。 MeshStandardMaterial和MeshPhysicalMaterial也使用这个着色模型。
像较与Lambert网格材质,Phong网格材质多了shininess
属性,用于计算材质的镜面反射的反射强度,specular
属性则为镜面反射所计算的颜色
标准网格材质(MeshStandardMaterial)
MeshPhongMaterial 有一个参数用来设置 shininess(反射强度) 属性。MeshStandardMaterial 有2个参数用来分别设置 roughness(粗糙度) 和 metalness(金属性) 属性。
一种基于物理的标准材质,使用Metallic-Roughness工作流程。
基于物理的渲染(PBR)最近已成为许多3D应用程序的标准,例如Unity, Unreal和 3D Studio Max。
这种方法与旧方法的不同之处在于,不使用近似值来表示光与表面的相互作用,而是使用物理上正确的模型。 我们的想法是,不是在特定照明下调整材质以使其看起来很好,而是可以创建一种材质,能够“正确”地应对所有光照场景。
在实践中,该材质提供了比MeshLambertMaterial 或MeshPhongMaterial 更精确和逼真的结果,代价是计算成本更高。
计算着色的方式与MeshPhongMaterial相同,都使用Phong着色模型, 这会计算每个像素的阴影(即在fragment shader, AKA pixel shader中), 与MeshLambertMaterial使用的Gouraud模型相比,该模型的结果更准确,但代价是牺牲一些性能。
物理网格材质(MeshPhysicalMaterial)
MeshStandardMaterial的扩展,提供了更高级的基于物理的渲染属性:
Clearcoat: 有些类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度。Clearcoat可以在不需要重新创建一个透明的面的情况下做到类似的效果。
基于物理的透明度:.opacity属性有一些限制:在透明度比较高的时候,反射也随之减少。使用基于物理的透光性.transmission属性可以让一些很薄的透明表面,例如玻璃,变得更真实一些。
高级光线反射: 为非金属材质提供了更多更灵活的光线反射。