Cesium进阶学习四、shadertoy(着色器)

一、简介
shadertoy是一个基于webgl的分享Shader的开放平台,用户可以在上面根据既定规则分享自己编写的shader。在Cesium中要想实现一些酷炫的效果,唯一的一条路就是写shader,而shader的编写应该算是图形学中的难度天花板了。好在有很多shader大佬分享了自己编写的glsl效果,比如shadertoy网站上就是这些大牛们的作品,我们可以借鉴。
在这里插入图片描述

二、shadertoy着色器基本结构

shadertoy上的shader是纯2d绘图,没有几何顶点这些概念,它的绘图方式和canvas绘图方式很像,它将整个canvas作为绘图的画布,所以输入参数fragCoord的x值范围是(0,画布的宽度),fragCoord的y值范围是(0,画布的高度),画布的宽高在定义的输入参数中是iResolution,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。
在这里插入图片描述

如图所示,shadertoy上的shader示例最基本的着色器结构主要包括两个部分:
a、输入参数的定义
b、着色器的入口函数

1、输入参数,通过uniform来定义外部的输入值。

uniform vec3      iResolution;           // 视口分辨率,即画布的宽高
uniform float     iTime;                 // shader 的运行时间 秒
uniform float     iTimeDelta;            // 渲染时间 秒
uniform float     iFrameRate;            // shader 帧率
uniform int       iFrame;                // shader 帧率
uniform float     iChannelTime[4];       // 频道运行时间 不管
uniform vec3      iChannelResolution[4]; // 频道分辨率 不管
uniform vec4      iMouse;                // 鼠标坐标
uniform samplerXX iChannel0..3;          // 输入的纹理 比如我们从一张图片上采用颜色
uniform vec4      iDate;                 // 日期 年月日 不管
uniform float     iSampleRate;           // 声音采样 不管

2、入口函数mainImage

void mainImage(out vec4 fragColor, in vec2 fragCoord )
{
   
    fragColor = vec4(1.);
}

方法的第一个参数fragColor,是一个vec4类型的变量,表示最后输出的颜色值。
方法的第二个参数fragCoord,是一个vec2类型的变量,表示输入的像素坐标。

三、在cesium中如何使用

shadertoy上的着色器是在一个canvas画布上进行工作的,要移植到Cesium中,我们需要找一个载体来替代canvas。我们知道,Cesium绘制几何图形可以通过Entity和Primitive两种方式,那么只有Primitive+Appearance比较合适了,关于Primitive的使用及介绍,可以观看前面的章节。要将着色器移植到Cesium中,我们先来重点看看shadertoy上的shader着色器需要用到的参数。以下面这个例子讲解https://www.shadertoy.com/view/XdlSDs
在这里插入图片描述

glsl代码:

void mainImage(out vec4 fragColor, in vec2 fragCoord )
{
   
    vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
    float tau = 3.1415926535*2.0;
    float a = atan(p.x,p.y);
    float r = length(p)*0.75;
    vec2 uv = vec2(a/tau,r);

    //get the color
    float xCol = (uv.x - (iTime / 3.0)) * 3.0;
    xCol = mod(xCol, 3.0);
    vec3 horColour = vec3(0.25, 0.25, 0.25);

    if (xCol < 1.0) {
   

        horColour.r += 1.0 - xCol;
        horColour.g += xCol;
    }
    else if (xCol < 2.0) {
   

        xCol -= 1.0;
        horColour.g += 1.0 - xCol;
        horColour.b += xCol;
    }
    else {
   

        xCol -= 2.0;
        horColour.b += 1.0 - xCol;
        horColour.r += xCol;
    }

    // draw color beam
    uv = (2.0 * uv) - 1.0;
    float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));
    vec3 horBeam = vec3(beamWidth);
    fragColor = vec4((( horBeam) * horColour), 1.0);
}

a、首先是fragCoord,前面介绍过,fragCoord表示当前处理的像素坐标,是一个vec2类型,fragCoord.x范围为(0,画布宽度),fragCoord.y范围为(0,画布高度)。
b、其次是iResolution,iResolution代表的是当前画布的宽高,即绘图区域的尺寸,所以fragCoord.x范围就是(0,iResolution.x),fragCoord.y范围就是(0,iResolution.y)。
c、然后我们还在代码中看到有个iTime,该参数代表当前运行的时间,一般用来实现动画,因为您会发现大多数shader的效果都是动态的。
d、最后是输出结果fragColor,代表最后计算的颜色输出值,在Cesium中为out_FragColor。

接下来介绍在Cesium如何获取对应的参数:

a、fragCoord在Cesium有个gl_FragCoord与之对应,这是一个WebGL内置的变量。
b、iResolution在Cesium有个czm_viewport与之对应,不过使用时采用zw分量即 czm_viewport.zw
c、iTime在Cesium中没有对应的变量,我们可以通过变量的方式传递一个参数,然后在渲染时不断修改该值,不过这种方式略显麻烦,在Cesium中我们可以用float iTime=czm_frameNumber/100.来模拟,czm_frameNumber代表当前帧,是一个自增长的数值,所以可以用来模拟时间不断地增长。

接下来我们实操一下,在Cesium中实现该shader的效果:

1、首先我们创建一个Primitive并添加到sene中

let xMin = 115.894604, yMin = 39.516896, xMax = 117.431959, yMax = 40.630521;
let rect = new Cesium.Rectangle(Cesium.Math.toRadians(xMin), Cesium.Math.toRadians(yMin), Cesium.Math.toRadians(xMax), Cesium.Math.toRadians(yMax));
const rectangle = new Cesium.RectangleGeometry({
   
    rectangle: rect,
    height: 10000.0,
});
const geometry = Cesium.RectangleGeometry.createGeometry(rectangle);
viewer.scene.primitives.add(new Cesium.Primitive({
   
    geometryInstances: new Cesium.GeometryInstance({
   
        geometry: geometry
    }), 
}));

2、此时会发现什么也看不见,这是因为没有设置外观,我们创建一个默认的外观

let appearance = new Cesium.MaterialAppearance({
   
     material: new Cesium.Material({
   
         fabric: {
   
             type: "Color",
             uniforms: {
   
                 color: Cesium.Color.RED
             }
         }
     }), 
 })
 primitive.appearance = appearance;

在这里插入图片描述

3、接下来我们为外观添加片元着色器,并将shadertoy上的shader赋值给外观的片元着色器属性。

shadertoy上glsl代码:

 fragmentShaderSource: `  
  void mainImage( out vec4 fragColor, in vec2 fragCoord )
  {
   
       vec2 p = (2.0*fragCoord.xy-iResolution.xy)/iResolution.y;
      float tau = 3.1415926535*2.0;
      float a = atan(p.x,p.y);
      float r = length(p)*0.75;
      vec2 uv = vec2(a/tau,r);

      //get the color
      float xCol = (uv.x - (iTime / 3.0)) * 3.0;
      xCol = mod(xCol, 3.0);
      vec3 horColour = vec3(0.25, 0.25, 0.25);

      if (xCol < 1.0) {
   

          horColour.r += 1.0 - xCol;
          horColour.g += xCol;
      }
      else if (xCol < 2.0) {
   

          xCol -= 1.0;
          horColour.g += 1.0 - xCol;
          horColour.b += xCol;
      }
      else {
   

          xCol -= 2.0;
          horColour.b += 1.0 - xCol;
          horColour
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cesium进阶学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值