03-Cesium自定义着色器完整代码以及注释

文章展示了如何使用CesiumJavaScript库创建一个自定义着色器,包括顶点着色器和片段着色器的代码,以实现3D平面上动态颜色变化的效果。通过设置顶点数据、纹理坐标和统一变量,实现了对3D图形的渲染控制。

1. 效果展示

2. 完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>自定义着色器完整代码</title>
    <!-- 线上 -->
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.107.1/Build/Cesium/Cesium.js"></script>
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.107.1/Build/Cesium/Widgets/widgets.css" rel="stylesheet" />

    <style>
      #map {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      }
    </style>
  </head>

  <body>
    <div id="map"></div>
    <script>
      Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhZjZkZDAwZC1mNTFhLTRhOTEtOGExNi00MzRhNGIzMDdlNDQiLCJpZCI6MTA1MTUzLCJpYXQiOjE2NjA4MDg0Njd9.qajeJtc4-kppqfR1--Y2FqCu5r3TE1xYYGnEQhy-JF0'
      const viewer = new Cesium.Viewer('map', {
        infoBox: false,
        shadows: true,
        terrainShadows: Cesium.ShadowMode.RECEIVE_ONLY,
        terrain: Cesium.Terrain.fromWorldTerrain(),
      })

      //平面的顶点数据
      let points = [110.2, 20.0, 112.2, 20.0, 110.2, 22.0, 112.2, 22.0]
      let positions = Cesium.Cartesian3.fromDegreesArray(points)
      //顶点对应的纹理坐标数据
      let sts = [0, 0, 0, 1, 1, 0, 1, 1]

      //顶点卷绕的方式
      let positionIndex = [0, 1, 2, 1, 2, 3]

      function primitivePlaneShader(options) {
        console.log(options, 'options')
        let viewer = options.viewer
        let vertexShader = v_shader()
        let fragShader = f_shader()
        let sts = new Uint8Array(options.sts) //纹理数据
        let positionIndex = new Uint16Array(options.positionIndex) //顶点索引数据
        let tempPosition = []
        for (var i = 0; i < options.positions.length; i++) {
          tempPosition.push(options.positions[i].x)
          tempPosition.push(options.positions[i].y)
          tempPosition.push(options.positions[i].z)
        }
        positions = new Float64Array(tempPosition) //顶点数据
        let geometry = createGeometry(positions, sts, positionIndex) //几何体
        let appearance = createAppearance(vertexShader, fragShader) //外观
        //primitive方式加载
        viewer.scene.primitives.add(
          new Cesium.Primitive({
            geometryInstances: new Cesium.GeometryInstance({
              //渲染的几何体
              geometry: geometry,
            }),
            appearance: appearance, //外观
            asynchronous: false,
          })
        )
      }
      function createAppearance(vertexShader, fragShader) {
        return new Cesium.Appearance({
          material: new Cesium.Material({
            /* 在Cesium中,fabric 是用于创建着色器材质(Shader Material)的对象。
            它允许您定义一种着色器材质类型,并通过uniforms(统一变量)传递外部数据给着色器。 */
            fabric: {
              /* 
              uniforms是一个包含统一变量(Uniform)的对象。
              统一变量是一种在着色器程序中定义的全局变量,
              它们的值可以在渲染过程中从CPU(JavaScript代码)传递给GPU(着色器代码)。 */
              uniforms: {
                speed: 0.1,
              },
              source: getMS(),
            },
          }),
          translucent: false, //显示不为半透明
          renderState: {
            blending: Cesium.BlendingState.PRE_MULTIPLIED_ALPHA_BLEND, //使用Alpha混合功能启用混合
            depthTest: { enabled: true }, //深度检测
            depthMask: true, //将深度值写入深度缓冲区
          },
          fragmentShaderSource: fragShader, //片段着色器
          vertexShaderSource: vertexShader, //顶点着色器
        })
      }
      //构建几何体
      function createGeometry(positions, sts, positionIndex) {
        return new Cesium.Geometry({
          attributes: {
            //几何顶点属性
            position: new Cesium.GeometryAttribute({
              componentDatatype: Cesium.ComponentDatatype.DOUBLE, //数据类型
              componentsPerAttribute: 3, //定义几个为一组
              values: positions, //坐标值
            }),
            st: new Cesium.GeometryAttribute({
              componentDatatype: Cesium.ComponentDatatype.FLOAT, //数据类型
              componentsPerAttribute: 2, //定义几个为一组
              values: sts, //坐标值
            }),
          },
          indices: positionIndex, //顶点索引
          primitiveType: Cesium.PrimitiveType.TRIANGLES, //图元类型
          boundingSphere: Cesium.BoundingSphere.fromVertices(positions), //包围球
        })
      }
      function v_shader() {
        // 这段着色器代码的作用是将顶点变换到裁剪空间,并传递纹理坐标给片段着色器,为后续的光栅化和渲染阶段做准备。
        return `
                in vec3 position3DHigh;//这是一个输入变量,表示高精度的3D位置。通常情况下,这个变量的值是由CesiumJS引擎在渲染过程中提供的,它表示当前处理的顶点或片段的高精度3D位置。
            		in vec3 position3DLow;//这也是一个输入变量,表示低精度的3D位置。在CesiumJS中,当高精度3D位置无法完全表示时,这个变量提供额外的信息,以便更准确地确定位置。
            		in float batchId;//这是一个输入变量,表示批次ID。在CesiumJS中,通常用于将相同类型的几何体分组在一起,以优化渲染性能。
            		in vec2 st;//这是一个输入变量,表示纹理坐标。
            		out vec2 v_st; //这是一个输出变量,表示处理后的纹理坐标。
            		void main() {
                  // czm_computePosition() //计算模型视图相对眼睛坐标空间中的顶点位置。
                  //czm_modelViewProjectionRelativeToEye//变换顶点位置到裁剪空间,并将结果保存在position中。
            		  vec4 position = czm_modelViewProjectionRelativeToEye *czm_computePosition();
                  //将输入变量st赋值给输出变量v_st,这样纹理坐标将在顶点着色器中传递给片段着色器。
            		   v_st = st;
                   //将经过变换后的顶点位置position赋值给内置变量gl_Position,这样OpenGL将使用这个值来确定顶点在屏幕上的位置。
            		   gl_Position = position;
            		}
              `
      }

      function f_shader() {
        return `
              in vec2 v_st;//这是一个输入变量,表示纹理坐标。在片段着色器中,v_st变量将包含插值后的纹理坐标值,这些值在顶点着色器中计算并传递给片段着色器。
              //uniform float speed;
              void main() {
                //这一行将纹理坐标(v_st)转换为范围在[-1, 1]的坐标(position)。在OpenGL中,纹理坐标的范围通常是[0, 1],而转换后的坐标在顶点着色器的插值过程中进行了变换,使其范围变为[-1, 1]。
            		   vec2 position = -1.0 + 2.0 *v_st;
                   //这行代码调用一个函数getSpeed(),该函数返回一个浮点数,表示速度。
            		   float speed = getSpeed();
                   //这一行根据帧号(czm_frameNumber)和速度(speed)计算时间(time)。czm_frameNumber是CesiumJS引擎提供的一个内置变量,表示当前渲染帧的序号。
            		   float time= czm_frameNumber *speed;
                   //计算颜色
            		   float r = abs( cos( position.x * position.y + time / 5.0 ));
            		   float g = abs( sin( position.x * position.y + time / 4.0 ) );
            		   float b = abs( cos( position.x * position.y + time / 3.0 ) );
                   //并将其赋值给特殊的输出变量out_FragColor,这个变量是CesiumJS中用于存储片段着色器输出颜色的内置变量。
            		   out_FragColor = vec4( r, g, b, 1.0 );
            		}

              `
      }

      function getMS() {
        return `#version 300 es
              uniform float speed;
              float getSpeed(){
            		  return speed;
            		}
              `
      }

      var plane = new primitivePlaneShader({
        viewer: viewer,
        positions: positions,
        sts: sts,
        positionIndex: positionIndex,
      })
      viewer.scene.camera.setView({
        destination: new Cesium.Cartesian3.fromDegrees(110.2, 20.0, 500000),
      })
    </script>
  </body>
</html>

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值