前言
上一节实现了上升线效果,这一节继续修改上一节中的shader,添加颜色渐变效果和扩散扫光效果。
思路
颜色渐变:让扩散扫光的效果中间亮,两边暗,来模拟光的效果,可通过sin函数模拟效果,把扫光半径计算到0-PI之间。他们的值变化如下图,0,PI最暗,PI/2最亮。
扩散扫光:这个思路也比较简单,设置一个原点,然后第一帧模型距离这个原点0-10单位长度的所有的点进行发光,第二帧距离10-20单位长度的点进行发光,以此类推。
代码讲解
fragmentShader: `
//求距离的公式,平方和开根号
float distanceTo(vec2 src,vec2 dst)
{
float dx=src.x-dst.x;
float dy=src.y-dst.y;
float dv=dx*dx+dy*dy;
return sqrt(dv);
}
varying vec3 vPosition;
uniform float height;
uniform vec3 uFlowColor;
uniform vec3 uCityColor;
void main()
{
//模型的基础颜色
vec3 distColor=uCityColor;
//定位当前点位位置
vec2 position2D=vec2(vPosition.x,vPosition.y);
//求点到原点的距离
float Len=distanceTo(position2D,vec2(0,0));
if(Len>height*30.0&&Len<(height*30.0+130.0)){
// 颜色渐变
float dIndex = sin((Len - height*30.0) / 130.0 * 3.14);
//通过上面的渐变值进行颜色混合
distColor= mix(uFlowColor, distColor, 1.0-dIndex);
}
//最终颜色
gl_FragColor=vec4(distColor,1.0);
}`,
传入的值和上一节相比没有变化,主函数部分关于上升线效果的也不进行介绍了,想要了解可以看上一篇文章(juejin.cn/post/704371…) 下面说一下添加的部分。
- 函数新添加了一个计算两点(平面点)距离的函数
distanceTo,通过勾股定理计算两个点的距离。 vec2 position2D=vec2(vPosition.x,vPosition.y);是把从顶点着色器中的点的x,y坐标进行组合,重新生成了一个平面坐标。float Len=distanceTo(position2D,vec2(0,0))是计算模型点平面坐标到原点的距离,然后把距离在height*30.0和height*30.0+130.0之间的点进行混色。其中height*30是原点距发光环内半径的距离,height*30+130是原点距发光环外半径的距离,130.0是发光环的内径。float dIndex = sin((Len - height*30.0) / 130.0 * 3.14)是通过sin函数把距离在height*30.0到height*30.0+130.0之间的值进行计算,值从height*30.0到height*30.0+65.0到height*30.0+130.0分别是0.0——1.0——0.0,实现两边值小中间值大的效果。distColor= mix(uFlowColor, distColor, 1.0-dIndex)是通过mix函数进行颜色混色,把uFlowColor和distColor两个颜色通过1.0: 1.0-dIndex进行混色.实现最终效果。
完整代码
setCityMaterial(object) {
const shader = new THREE.ShaderMaterial({
uniforms: {
height: this.height,
uFlowColor: {
value: new THREE.Color("#5588aa"),
},
uCityColor: {
value: new THREE.Color("#1B3045"),
},
},
vertexShader: `
varying vec3 vPosition;
void main()
{
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader: `
float distanceTo(vec2 src,vec2 dst)
{
float dx=src.x-dst.x;
float dy=src.y-dst.y;
float dv=dx*dx+dy*dy;
return sqrt(dv);
}
varying vec3 vPosition;
uniform float height;
uniform float uStartTime;
uniform vec3 uSize;
uniform vec3 uFlowColor;
uniform vec3 uCityColor;
void main()
{
//模型的基础颜色
vec3 distColor=uCityColor;
// 流动范围当前点z的高度加上流动线的高度
float topY=vPosition.z+10.;
if(height>vPosition.z&&height<topY){
// 颜色渐变
float dIndex = sin((height - vPosition.z) / 10.0 * 3.14);
distColor = mix(uFlowColor, distColor, 1.0-dIndex);
}
//定位当前点位位置
vec2 position2D=vec2(vPosition.x,vPosition.y);
//求点到原点的距离
float Len=distanceTo(position2D,vec2(0,0));
if(Len>height*30.0&&Len<(height*30.0+130.0)){
// 颜色渐变
float dIndex = sin((Len - height*30.0) / 130.0 * 3.14);
distColor= mix(uFlowColor, distColor, 1.0-dIndex);
}
gl_FragColor=vec4(distColor,1.0);
}`,
transparent: true,
});
const city = new THREE.Mesh(object.geometry, shader);
city.position.set(
object.position.x,
object.position.y,
object.position.z
);
scene.add(city);
city.rotateX(-Math.PI / 2);
},
效果图
项目地址: github.com/lixiaochjaj…