cesium.js 自定义shader实现流动尾线

cesium.js 实现流动尾线

最近需要实现运动的线条,有拖尾的效果,然后再网上查看了一下大佬做的流动线的样例,大佬样例链接引发了我的想法,发现只需要再将纹理进行重复,改变运动的速率就可以实现这个功能,下面来简单的说明一下实现的过程。
纹理图
首先从我们使用的纹理图来入手分析实现的过程,这样纹理图使用的是渐变的效果,我直接将这张图片作为材质,给线条添加上去,就会得到一个渐变的线条。效果如下所示(因为后面的颜色的透明度为0,所以后半部分是看不见的)
cesium.js 自定义shader实现流动尾线_第1张图片
思考一下我们怎样才能让这个线条动起来,准确的来说是怎么控制材质让其运动,我们将上面那张纹理图以左下角为原点,横向为S轴,纵向为T轴。发现如果使其运动起来,只需要传递给着色器一个动态变化的时间,根据不同的时间在S轴方向上取到不同的颜色值,就能够使线条运动起来,其实就是每个片元在不同的时间取到对应的颜色值(不明白的可以看一下WebGL的渲染流程,重要的片元着色器如何着色)
我这里只贴上着色器的source里的代码,其他的参考上面给得链接大佬写的代码

"\
  uniform float time;\n\
  uniform sampler2D image;\n\
  czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  {\n\
     czm_material material = czm_getDefaultMaterial(materialInput);\n\
     vec2 st = materialInput.st;\n\
     vec4 colorImage = texture2D(image, vec2(fract(st.s-time), st.t));\n\
     material.alpha = colorImage.a ;\n\
     material.diffuse = colorImage.rgb;\n\
     return material;\n\
  }";

最主要的就是vec4 colorImage = texture2D(image, vec2(fract(st.s-time), st.t));这行代码。我们主要对纹理坐标的S的取值减去一个我们动态传入的时间,最后用fract()函数将st.s取值保证在[0,1]之间。
按照上面说的可能还有人不能理解 fract(st.s-time) 这里特别说明一下:这里传入的时间处理过后取值也是[0,1],为什么st.s-time线条就运动起来了呢?举一个不太恰当的例子就是加入st.s的值为0.1,那么fract(0.1-time)的取值就是[0,1]在time变化的一个周期内fract(0.1-time)就是将纹理贴图里S轴方向的颜色值全部取了一遍,time周期变化取值也就周期变化。(这个比喻确实不太恰当,希望能帮助理解)。
运行效果如下(因为gif上传大小有限制 动图做的效果不好)

这样只是有一条线在运动,通过纹理重复可以将其变成多个一起运动,实现起来也是非常的简单,简单说一下,就是将st 乘一个你想要重复的个数,下面取值的时候再用fract()将其限制在[0,1]。简单说一下纹理重复的原理,就是将st的值扩大,而从纹理坐标中取颜色值时利用fract()函数限制取值。如果还理解不了,举个例子假如纹理坐标为[0.1,0.1] 我们将其扩大了十倍,就变成了[1.0,1.0],那是不是在本身在0-0.1这个区间内只能取到纹理的1/100,而现在在0-0.1的区间上取到了整个纹理,利用fract() 帮助我们在当st>1时取其小数部分,就实现了纹理重复。
下面是着色器的source里的代码

"\
 uniform vec4 color;\n\
  uniform float time;\n\
  uniform sampler2D image;\n\
  czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  {\n\
     czm_material material = czm_getDefaultMaterial(materialInput);\n\
     vec2 st = materialInput.st*10.0;\n\
     vec4 colorImage = texture2D(image, vec2(fract(st.s-time*10.0), fract(st.t)));\n\
     material.alpha = colorImage.a * color.a;\n\
     material.diffuse = color.rgb;\n\
     return material;\n\
  }";

上面的写法也不是最好的,其实我们只是想要在S轴上进行纹理重复,其实我们只需要将st.s10.0就可以了,更推荐这样写: vec2 st = materialInput.st;vec4 colorImage = texture2D(image, vec2(fract(st.s10.0-time10.0), st.t));time10.0 是加快time变化的周期,乘的数值越大变化速率越快。也可以改变纹理图的颜色,如上所示rgb采用自己想要的颜色值,透明度值采用纹理的透明度值。效果图如下。

gif图做的不是很好,本身的效果比这个要好,在贴一张图片吧。
cesium.js 自定义shader实现流动尾线_第2张图片
Cesium.js自定义shader实现流动尾线,就说到这里,希望能给你带来帮助,有什么错误欢迎大佬对小白指点一二,如有转载请附上原文地址。3D的世界里山高水长,还得继续默默前行。

生活不只有诗和远方,还有面包和牛奶。

你可能感兴趣的:(前端,Cesium.js)