本文在线示例查看。更多精彩内容尽在数字孪生平台,关注公众号:sky的数孪技术,技术交流、源码下载请添加VX:digital_twin123
基本信息
三维渲染库采用threejs,项目用vite打包。
版本:v1.1.0
场景解析
时空门
这一蓝一红时空门很酷炫,我封装了一个专门的 Portal
类来实现,每个 Portal 类都会创建 Particles、Halo、EventHorizon、Smoke、Lightnings。
Particles
创建粒子效果。根据 ringCount
和 count
数量来设置顶点数据。
需要一个 FlowField
对象来对顶点数据实现流动效果,这里面运用了交换纹理的技术,通过构造两个 RenderTarget
来实现纹理切换。
材质这块用的 ShaderMaterial
,其中片元着色器代码:
uniform vec3 uColor;
uniform sampler2D uMaskTexture;void main()
{float mask = texture2D(uMaskTexture, gl_PointCoord).r;gl_FragColor = vec4(uColor, mask);
}
每帧更新时,通过不断的对 FlowField
对象进行纹理重绘,来替代shader中的 uFBOTexture
。
Halo
创建圆环效果。这里只是用了一个PlaneGeometry,然后主要是在材质Shader中去计算纹理,具体逻辑可以看片元着色器shaders/portalHalo/fragment.glsl
的代码。
vec2 centeredUv = vUv - 0.5;
float distanceToCenter = length(centeredUv);float colorMixA = pow(distanceToCenter * 3.0, 4.0);
vec3 color = mix(uColorA, uColorB, colorMixA);float colorMixB = (distanceToCenter - 0.3) * 30.0;
colorMixB = clamp(colorMixB, 0.0, 1.0);
colorMixB = smoothstep(0.0, 1.0, colorMixB);
color = mix(color, uColorC, colorMixB);float alpha = (distanceToCenter - 0.33) * 20.0;
alpha = 1.0 - alpha;
alpha = smoothstep(0.0, 1.0, alpha);gl_FragColor = vec4(color, alpha);
EventHorizon
创建流动圆环效果。实现跟Halo基本一致,区别主要是片元着色器。这里用了perlin3d的噪声算法来模拟流动效果。
float smoke = perlin3d(vec3(smokeUv * vec2(50.0, 15.0), uTime * 0.001));
smoke *= halo;
smoke *= 2.0;vec3 color = mix(uColorStart, uColorEnd, smoke);gl_FragColor = vec4(color, smoke);
Smoke
创建烟雾效果。根据 count
数量,创建了一堆的大小为1的 PlaneGeometry
,赋予流动速度模拟烟雾。用如下烟雾图作为材质的 alphaMap
,混合颜色进行计算。
更新过程中,每个粒子都有一定的生命周期,能够渐渐消逝。
Lightnings
创建电离动态效果。与 Smoke 类似,创建同样大小为1的 PlaneGeometry
,用闪电灰度图作为 uMaskTexture
,混合颜色进行计算。
float outerAlpha = min(1.0, 1.0 - (length(vModelPosition.xy) - 1.0) * 10.0);float maskStrength = texture2D(uMaskTexture, vUv).r * outerAlpha * uAlpha;gl_FragColor = vec4(uColor, maskStrength);
更新过程与 Smoke 的粒子周期相同。
地面
地面的材质用的MeshStandardMaterial
,材质贴图应用了颜色贴图、法线贴图、位移贴图以及粗糙度贴图,并接受阴影;几何应用PlaneGeometry
。
灯光
本示例场景里添加了两个点光源来点缀场景。
this.lights.items.a = {}this.lights.items.a.color = '#ff0a00'this.lights.items.a.instance = new THREE.PointLight(this.lights.items.a.color, 11)
this.lights.items.a.instance.rotation.y = Math.PI
this.lights.items.a.instance.position.y = - 0.5
this.lights.items.a.instance.position.z = - 1.501
this.lights.items.a.instance.castShadow = true
this.lights.items.a.instance.shadow.camera.far = 7
this.lights.items.a.instance.shadow.normalBias = 0.005
this.scene.add(this.lights.items.a.instance)
人物模型
这个没啥好说的,添加模型,设置好比例位置即可。不过要记得把模型的receiveShadow
和castShadow
都要开启。