Cesium进阶教程——自定义图形、外观、绘图基础、现有着色器移植至Cesium、ShadowMapping、视频GIS、模型压平、卷帘

基础必看

https://blog.csdn.net/m0_55049655/article/details/139720401

参考路线

http://www.xt3d.online/tutorial/further/article.html

自定义图形

https://blog.csdn.net/m0_55049655/article/details/138908327

https://blog.csdn.net/m0_55049655/article/details/140306837

https://blog.51cto.com/u_15080020/4200536

https://blog.csdn.net/xietao20/article/details/142913781

在Cesium中,绘制带颜色的三角形可以使用 PrimitiveGeometry,结合 Material 来实现。以下是一个详细的步骤和代码示例:

必要的输入

  • 三角形节点的坐标 (以数组形式提供,例如 [x1, y1, z1, x2, y2, z2, ...])。
  • 三角形的节点颜色 (对应每个节点的颜色,例如 [color1, color2, color3],每个颜色是 Cesium.Color 对象)。
  • 三角形的索引值(定义每个三角形的三个顶点索引)。

实现步骤

  1. 创建顶点数组 :根据节点的坐标创建一个 Float32Array,代表所有的顶点坐标。
  2. 创建颜色数组 :将颜色信息转换为 Uint8Array,每个颜色包含 RGBA 四个分量。
  3. 定义索引:根据提供的索引值定义三角形顶点的连接关系。
  4. 生成 Geometry 对象 :使用 Cesium 的 Geometry 来存储顶点、颜色和索引信息。
  5. 创建 Primitive :将 Geometry 包裹在一个 Primitive 中,添加到 Cesium 场景中。

代码示例

以下是完整的代码实现:

javascript 复制代码
// 三角形节点的坐标数组 [x1, y1, z1, x2, y2, z2, ...]
const positions = new Float32Array([
  0.0, 0.0, 0.0,   // 节点1
  1.0, 0.0, 0.0,   // 节点2
  0.0, 1.0, 0.0    // 节点3
]);

// 每个节点对应的颜色数组 [r, g, b, a, r, g, b, a, ...]
const colors = new Uint8Array([
  255, 0, 0, 255,   // 红色 (节点1)
  0, 255, 0, 255,   // 绿色 (节点2)
  0, 0, 255, 255    // 蓝色 (节点3)
]);

// 三角形的索引数组(定义三角形的顶点关系)
const indices = new Uint16Array([
  0, 1, 2  // 一个三角形,由节点1, 2, 3组成
]);

// 创建几何体
const geometry = new Cesium.Geometry({
  attributes: {
    position: new Cesium.GeometryAttribute({
      componentDatatype: Cesium.ComponentDatatype.FLOAT,
      componentsPerAttribute: 3,
      values: positions
    }),
    color: new Cesium.GeometryAttribute({
      componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE,
      componentsPerAttribute: 4,
      values: colors,
      normalize: true // 归一化到 [0, 1]
    })
  },
  indices: indices,
  primitiveType: Cesium.PrimitiveType.TRIANGLES // 指定绘制三角形
});

// 创建材质
const appearance = new Cesium.PerInstanceColorAppearance({
  flat: true, // 关闭光照影响
  translucent: false // 不透明
});

// 创建 Primitive
const primitive = new Cesium.Primitive({
  geometryInstances: new Cesium.GeometryInstance({
    geometry: geometry
  }),
  appearance: appearance
});

// 添加到场景
viewer.scene.primitives.add(primitive);

代码解读

  1. 顶点和颜色的绑定
    • GeometryAttribute 用于绑定顶点坐标和颜色信息。
    • 颜色数组的 normalize: true 参数确保颜色范围从 [0, 255] 映射到 [0.0, 1.0]
  2. 索引的作用
    • 索引定义了顶点的连接顺序,减少重复存储顶点的开销。
  3. 材质和外观
    • PerInstanceColorAppearance 直接使用颜色属性,无需纹理。
    • 设置 flat: truetranslucent: false 可以提升渲染效率。

注意事项

  • 如果需要动态更新顶点或颜色,可以重新创建 Geometry 或使用 CustomShader 实现更灵活的渲染。
  • 确保坐标和颜色的数组长度对应,否则会引发错误。

尝试运行这段代码,你应该能看到一个由三角形组成的彩色几何体!

外观

Cesium 中,Material 是一个强大的工具,用于定义几何体外观。它允许开发者通过 顶点着色器 (Vertex Shader)和 片段着色器 (Fragment Shader)实现自定义效果。以下将从 Material 架构着色器编程 、以及 GPU 与 CPU 数据传递 等方面进行详解。


1. Cesium 的 Material 架构

在 Cesium 中,Material 是通过 GLSL 代码(WebGL 的着色器语言)实现的。Cesium 提供了一些预定义的 Material 类型(例如 ColorMaterialProperty),也允许用户定义自定义着色器。

Material 的构成
  1. 顶点着色器(Vertex Shader):处理每个顶点的逻辑,计算顶点的变换(位置、法线等)。
  2. 片段着色器(Fragment Shader):处理每个片元的逻辑,定义像素的颜色、纹理等属性。
  3. Uniforms:从 CPU 向 GPU 传递的全局数据,通常是不变的值(如时间、模型矩阵)。
  4. Varyings:从顶点着色器传递到片段着色器的中间数据,用于共享信息。
  5. Attributes:每个顶点的数据(如位置、法线、颜色等)。

2. 自定义 Material 示例

以下是创建一个动态颜色渐变 Material 的示例。

javascript 复制代码
// 创建自定义材质
const customMaterial = new Cesium.Material({
    fabric: {
        type: 'CustomMaterial', // 自定义类型名
        uniforms: {
            u_time: 0.0, // 时间参数(Uniform)
            u_color1: new Cesium.Color(1.0, 0.0, 0.0, 1.0), // 起始颜色
            u_color2: new Cesium.Color(0.0, 0.0, 1.0, 1.0), // 结束颜色
        },
        source: `
            // 顶点着色器代码
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                czm_material material = czm_getDefaultMaterial(materialInput);
                float mixRatio = abs(sin(u_time)); // 动态变化的混合因子
                material.diffuse = mix(u_color1.rgb, u_color2.rgb, mixRatio); // 颜色渐变
                material.alpha = 1.0; // 不透明
                return material;
            }
        `,
    },
});

// 创建带自定义材质的实体
viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(0, 0, 0),
    ellipsoid: {
        radii: new Cesium.Cartesian3(500000.0, 500000.0, 500000.0),
        material: customMaterial, // 应用自定义材质
    },
});

// 更新时间参数
viewer.clock.onTick.addEventListener(() => {
    customMaterial.uniforms.u_time += viewer.clock.deltaTime;
});
代码说明
  1. fabric 定义了材质结构。
  2. uniforms 是从 CPU 传递到 GPU 的参数,支持动态更新。
  3. source 是 GLSL 着色器代码,定义了颜色渐变逻辑。

3. 顶点着色器详解

顶点着色器的主要作用是处理顶点数据并计算最终的顶点位置。

关键点
  1. 输入
    • attributes:顶点属性,如位置、法线、纹理坐标。
    • uniforms:全局常量参数。
  2. 输出
    • gl_Position:顶点在屏幕上的位置。
    • varyings:传递给片段着色器的数据。
示例
glsl 复制代码
attribute vec3 position;
attribute vec3 normal;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

varying vec3 vNormal;

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    vNormal = normal;
}

4. 片段着色器详解

片段着色器负责计算每个像素的颜色。

关键点
  1. 输入
    • varyings:从顶点着色器传递的数据。
    • uniforms:全局参数。
  2. 输出
    • gl_FragColor:最终片元颜色。
示例
glsl 复制代码
varying vec3 vNormal;

uniform vec3 lightDirection;

void main() {
    float brightness = max(dot(normalize(vNormal), normalize(lightDirection)), 0.0);
    gl_FragColor = vec4(vec3(brightness), 1.0);
}

5. GPU 和 CPU 之间的数据传递

Cesium 提供了友好的接口来传递数据:

  1. Uniforms

    • 用于传递全局数据,如时间、颜色、纹理等。

    • Material 中通过 uniforms 字段定义。

    • 动态更新方法:

      javascript 复制代码
      customMaterial.uniforms.u_time = newValue;
  2. Attributes

    • 每个顶点的数据,如位置、法线。
    • Cesium 自动处理基本的顶点数据,但你也可以通过 Geometry 自定义。
  3. Textures

    • Cesium 支持将纹理传递给 GPU,通常通过 Uniform 实现。

    • 示例:

      javascript 复制代码
      const texture = new Cesium.Texture({
          context: viewer.scene.context,
          source: imageElement,
      });
      customMaterial.uniforms.u_texture = texture;

6. 着色器编程中的关键概念

1. 模型-视图-投影矩阵
  • 用于将世界坐标系的顶点转换到屏幕坐标系。
  • Cesium 自动为大多数几何体处理这些矩阵。
2. 法线和光照
  • 在顶点着色器中计算法线,并传递给片段着色器以实现光照效果。
3. 颜色混合
  • 使用 GLSL 的 mix 函数,可以实现颜色渐变或插值。
4. 动态效果
  • 利用时间参数(u_time)可以实现波浪、脉冲等动态视觉效果。

7. 实现复杂效果的技巧

1. 多纹理混合

将多个纹理通过自定义逻辑混合,创建复杂的表面外观。

glsl 复制代码
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float mixRatio;

void main() {
    vec4 color1 = texture2D(texture1, gl_TexCoord[0].st);
    vec4 color2 = texture2D(texture2, gl_TexCoord[0].st);
    gl_FragColor = mix(color1, color2, mixRatio);
}
2. 法线贴图

使用法线贴图来模拟复杂的表面细节。


总结

  • 顶点着色器:处理顶点位置,计算中间数据。
  • 片段着色器:处理像素颜色,定义最终的视觉效果。
  • GPU-CPU 数据传递:通过 Uniforms 和 Attributes 实现,Cesium 提供了友好的接口。

通过以上知识,可以在 Cesium 中实现丰富的自定义渲染效果!

3D热力图绘制

在Cesium中绘制3D热力图可以为数据可视化提供强大的展示能力。以下是关于如何在Cesium中实现3D热力图绘制的详细说明。


1. 了解热力图和3D热力图

  • 热力图是通过颜色来表达数据强度的一种可视化手段,通常用于显示某一地理区域的数据分布。
  • 3D热力图不仅通过颜色显示数据,还结合高度或体积的变化来体现数据的三维分布。

2. 实现3D热力图的关键步骤

2.1 数据准备

热力图的数据通常包括以下内容:

  • 地理坐标(经纬度)。
  • 数据值(如温度、密度或强度)。

确保数据经过适当的预处理,比如去除异常值或归一化处理。


2.2 热力图生成技术

在Cesium中,可以使用以下几种方式实现3D热力图:

方法 1:使用 Cesium 的 Primitive 和 Polygon
  1. 计算数据范围

    根据数据的值生成颜色和高度的映射关系。

  2. 生成网格

    将目标区域划分为多个小网格,每个网格代表一个采样点。

  3. 动态绘制高度柱(Extruded Height)

    为每个网格创建一个 Polygon,其高度(extrudedHeight)由数据值决定,颜色根据数据值映射至色谱(例如从蓝到红)。

javascript 复制代码
viewer.entities.add({
    name: "Heatmap Column",
    polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray([lon1, lat1, lon2, lat2, lon3, lat3]),
        extrudedHeight: dataValue * heightFactor, // 数据值映射为高度
        material: Cesium.Color.fromCssColorString(colorMapping(dataValue)) // 数据值映射为颜色
    }
});
方法 2:借助第三方库

使用开源库(如 heatmap.js 或其他热力图生成工具)来生成2D热力图纹理,再将其投影到Cesium地图上,甚至可以结合3D高度。

  1. 生成热力图纹理

    使用 heatmap.js 创建热力图图片(PNG)。

  2. 投影到 Cesium 地图上

    将生成的图片作为材质贴到平面或地形上。

javascript 复制代码
const heatmapImageryProvider = new Cesium.SingleTileImageryProvider({
    url: 'path/to/heatmap-image.png',
    rectangle: Cesium.Rectangle.fromDegrees(west, south, east, north)
});
viewer.imageryLayers.addImageryProvider(heatmapImageryProvider);
  1. 叠加 3D 高度
    如果需要3D效果,可以为热力图纹理增加基于值的高程。

2.3 使用 Shader 实现

通过 WebGL 着色器(Shader)实现更加复杂的3D热力图效果:

  1. 传递数据到 Shader

    使用 Cesium.Material 或自定义 Primitive,将热力图数据以纹理或属性形式传递到 GPU。

  2. 编写 Fragment Shader

    • 使用颜色梯度映射值。
    • 控制每个像素的高度和透明度。
javascript 复制代码
Cesium.Material.fromType('Heatmap3D', {
    fabric: {
        type: 'Heatmap3D',
        uniforms: {
            colorGradient: gradientTexture,
            dataTexture: dataTexture
        },
        source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                // 核心逻辑:颜色和高度映射
            }
        `
    }
});

3. 优化和交互

3.1 性能优化
  • 数据网格的分辨率控制:根据视图范围动态调整网格大小。
  • 着色器优化:尽量减少复杂计算。
3.2 提供交互功能
  • 鼠标悬停:显示特定区域的数据值。
  • 动态更新:响应实时数据变化,更新热力图显示。

4. 示例代码

以下是完整的代码片段示例:

javascript 复制代码
// 创建 Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer');

// 示例数据
const data = [
    { lon: 120.1, lat: 30.2, value: 10 },
    { lon: 120.2, lat: 30.3, value: 20 },
    // ...
];

// 绘制 3D 热力柱
data.forEach(d => {
    viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(d.lon, d.lat),
        cylinder: {
            length: d.value * 100, // 高度
            topRadius: 0,
            bottomRadius: 500, // 半径
            material: Cesium.Color.fromCssColorString(colorMapping(d.value)) // 颜色
        }
    });
});

// 映射函数示例
function colorMapping(value) {
    if (value < 10) return '#00FF00';
    if (value < 20) return '#FFFF00';
    return '#FF0000';
}

5. 总结

通过以上方法,您可以在Cesium中实现丰富的3D热力图效果。根据需求选择合适的技术,结合性能优化和交互功能,能够为用户提供更直观的地理数据可视化体验。

绘图基础

https://www.cnblogs.com/jiujiubashiyi/p/17124717.html

https://blog.csdn.net/m0_55049655/article/details/139720401

Cesium中的顶点着色器和片段着色器使用详解

Cesium 是一个基于 WebGL 的 3D 地图渲染框架,它支持通过自定义着色器(Shader)控制图形渲染的细节。WebGL 渲染管线包括顶点着色器和片段着色器两个主要阶段,Cesium 同样可以自定义和扩展这些功能。


1. 着色器基础

  1. 顶点着色器(Vertex Shader)

    • 主要任务是处理几何数据,如顶点的位置、法向量等。
    • 输入:顶点属性(如位置、法线、纹理坐标等)。
    • 输出:每个顶点的变换结果(如屏幕空间位置)。
  2. 片段着色器(Fragment Shader)

    • 主要任务是为每个像素(片段)计算颜色。
    • 输入:顶点着色器输出的插值数据。
    • 输出:像素颜色(以及透明度)。

2. Cesium 渲染管线概述

Cesium 的渲染管线是 WebGL 管线的封装,涉及以下步骤:

  1. 顶点数据:Cesium 使用缓冲区(Buffer)存储顶点数据。
  2. 自定义材质 :通过 MaterialAppearance 配置 GLSL 着色器。
  3. 渲染对象 :通过 Primitive 实例化对象,将着色器与几何结合。

3. 使用顶点和片段着色器的关键模块

  1. 创建顶点着色器和片段着色器

    在 Cesium 中,顶点和片段着色器是通过 GLSL 编写的,可以嵌入到自定义材质或 Primitive 中。例如:

    • 顶点着色器负责将地理坐标转换为屏幕空间。
    • 片段着色器控制每个像素的颜色或透明度。
  2. 绑定着色器到 Cesium 的渲染对象

    使用 Cesium 的 Primitive,结合自定义的 Appearance,将着色器与几何对象绑定。


4. Cesium 着色器示例:自定义渲染一片三角形网格

4.1 顶点着色器(Vertex Shader)
glsl 复制代码
attribute vec3 position; // 顶点位置
attribute vec3 color;    // 每个顶点的颜色
varying vec3 vColor;     // 传递到片段着色器的颜色

void main() {
    // 世界空间位置转换为裁剪空间
    gl_Position = czm_modelViewProjection * vec4(position, 1.0);
    // 将顶点颜色传递到片段着色器
    vColor = color;
}
4.2 片段着色器(Fragment Shader)
glsl 复制代码
precision mediump float;
varying vec3 vColor; // 从顶点着色器传递过来的颜色

void main() {
    // 设置片段颜色
    gl_FragColor = vec4(vColor, 1.0); // RGB + Alpha
}

4.3 构建 Cesium 渲染对象

在 Cesium 中,需要将顶点数据、着色器和渲染管线连接起来。

  1. 定义顶点数据
    包括三角形的顶点位置和颜色。
javascript 复制代码
const positions = new Float32Array([
    0.0, 0.0, 0.0, // 第一个顶点
    1.0, 0.0, 0.0, // 第二个顶点
    0.0, 1.0, 0.0  // 第三个顶点
]);

const colors = new Float32Array([
    1.0, 0.0, 0.0, // 红色
    0.0, 1.0, 0.0, // 绿色
    0.0, 0.0, 1.0  // 蓝色
]);
  1. 创建顶点属性缓冲区
    将数据绑定到 WebGL 缓冲区。
javascript 复制代码
const geometry = new Cesium.Geometry({
    attributes: {
        position: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.FLOAT,
            componentsPerAttribute: 3,
            values: positions
        }),
        color: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.FLOAT,
            componentsPerAttribute: 3,
            values: colors
        })
    },
    // 指定为三角形几何
    indices: new Uint16Array([0, 1, 2]),
    primitiveType: Cesium.PrimitiveType.TRIANGLES
});
  1. 编写自定义 Appearance
    使用自定义的顶点和片段着色器。
javascript 复制代码
const appearance = new Cesium.Appearance({
    materialSupport: Cesium.MaterialAppearance.MaterialSupport.BASIC,
    vertexShaderSource: `
        attribute vec3 position;
        attribute vec3 color;
        varying vec3 vColor;
        void main() {
            gl_Position = czm_modelViewProjection * vec4(position, 1.0);
            vColor = color;
        }
    `,
    fragmentShaderSource: `
        precision mediump float;
        varying vec3 vColor;
        void main() {
            gl_FragColor = vec4(vColor, 1.0);
        }
    `
});
  1. 创建 Primitive 对象并添加到场景
    将顶点数据和外观结合,渲染到 Cesium 场景中。
javascript 复制代码
const primitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry
    }),
    appearance: appearance,
    asynchronous: false
});

viewer.scene.primitives.add(primitive);

5. 完整示例代码

以下是完整的 Cesium 程序,用于渲染带颜色的三角形:

javascript 复制代码
const viewer = new Cesium.Viewer('cesiumContainer');

// 顶点数据
const positions = new Float32Array([
    0.0, 0.0, 0.0,
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0
]);

const colors = new Float32Array([
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    0.0, 0.0, 1.0
]);

// 创建几何
const geometry = new Cesium.Geometry({
    attributes: {
        position: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.FLOAT,
            componentsPerAttribute: 3,
            values: positions
        }),
        color: new Cesium.GeometryAttribute({
            componentDatatype: Cesium.ComponentDatatype.FLOAT,
            componentsPerAttribute: 3,
            values: colors
        })
    },
    indices: new Uint16Array([0, 1, 2]),
    primitiveType: Cesium.PrimitiveType.TRIANGLES
});

// 创建着色器外观
const appearance = new Cesium.Appearance({
    materialSupport: Cesium.MaterialAppearance.MaterialSupport.BASIC,
    vertexShaderSource: `
        attribute vec3 position;
        attribute vec3 color;
        varying vec3 vColor;
        void main() {
            gl_Position = czm_modelViewProjection * vec4(position, 1.0);
            vColor = color;
        }
    `,
    fragmentShaderSource: `
        precision mediump float;
        varying vec3 vColor;
        void main() {
            gl_FragColor = vec4(vColor, 1.0);
        }
    `
});

// 创建 Primitive
const primitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry
    }),
    appearance: appearance,
    asynchronous: false
});

// 添加到 Cesium 场景
viewer.scene.primitives.add(primitive);

6. 总结

通过以上步骤,您可以在 Cesium 中自定义顶点和片段着色器,实现对渲染管线的全面控制。本例中我们展示了如何绘制一个简单的三角形,并用每个顶点的颜色实现平滑的渐变效果。这种能力可以扩展到更复杂的渲染任务,比如动态纹理、光照计算或基于高度的数据可视化。

ShaderToy以及代码移植至Cesium

ShaderToy 详解与移植到 Cesium 的方法

1. 什么是 ShaderToy?

ShaderToy 是一个在线平台,用于创建和分享基于 GLSL(OpenGL Shading Language)的着色器。它允许开发者实时编写、调试和查看 GPU 着色器的效果,广泛用于学习图形编程、生成视觉效果和艺术创作。


2. ShaderToy 的核心组件

ShaderToy 着色器通常运行在 WebGL 环境,具有以下关键部分:

  1. 片段着色器(Fragment Shader)

    • 主函数为 mainImage(out vec4 fragColor, in vec2 fragCoord)
    • 使用 fragCoord 定位像素并计算输出颜色。
  2. 全局 Uniforms

    ShaderToy 提供了一些预定义的全局变量,便于开发者创建动态效果。

    • iResolution:画布的分辨率(像素)。
    • iTime:运行时间(秒)。
    • iMouse:鼠标位置。
    • iChannel0 - iChannel3:纹理通道,用于输入纹理或音频数据。
  3. 纹理采样和噪声生成

    ShaderToy 支持使用噪声函数、渐变和纹理来实现复杂效果。


3. 将 ShaderToy 着色器移植至 Cesium 的步骤

Cesium 支持 WebGL 和 GLSL 着色器,因此可以将 ShaderToy 的着色器逻辑移植到 Cesium 的材质系统中,例如通过 Cesium.MaterialPrimitive 实现。


3.1 准备 ShaderToy 着色器

在 ShaderToy 上找到目标着色器代码,并确认其主要逻辑。以一个简单的着色器为例:

glsl 复制代码
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    fragColor = vec4(uv, 0.5 + 0.5 * sin(iTime), 1.0);
}

这段代码生成了一个动态颜色随时间变化的效果。


3.2 移植到 Cesium 的材质系统

步骤 1:创建自定义材质

Cesium 的 Material 支持自定义 GLSL 代码,可以直接移植 ShaderToy 的片段着色器。

javascript 复制代码
Cesium.Material._materialCache.addMaterial('ShaderToyMaterial', {
    fabric: {
        type: 'ShaderToyMaterial',
        uniforms: {
            iResolution: new Cesium.Cartesian2(1920, 1080),
            iTime: 0.0
        },
        source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                czm_material material = czm_getDefaultMaterial(materialInput);
                vec2 fragCoord = materialInput.st * iResolution;
                vec2 uv = fragCoord / iResolution;
                material.diffuse = vec3(uv, 0.5 + 0.5 * sin(iTime));
                material.alpha = 1.0;
                return material;
            }
        `
    },
    translucent: false
});
  • czm_materialInput.st :Cesium 的纹理坐标(对应 fragCoord 的归一化版本)。
  • czm_material :Cesium 的材质结构,包括 diffuse(颜色)和 alpha(透明度)。

步骤 2:应用材质

将材质应用到 Cesium 的对象上,如地形、实体或 Primitive

javascript 复制代码
viewer.entities.add({
    rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
        material: new Cesium.Material({
            fabric: {
                type: 'ShaderToyMaterial'
            }
        })
    }
});

3.3 将 ShaderToy 的 Uniforms 转换为 Cesium Uniforms

ShaderToy 的一些 Uniforms 需要用 Cesium 的方法进行动态更新:

  1. iTime:通过 Cesium 的动画循环更新时间。
javascript 复制代码
viewer.clock.onTick.addEventListener(() => {
    const material = viewer.entities.values[0].rectangle.material;
    material.uniforms.iTime += viewer.clock.tickDeltaSeconds;
});
  1. iResolution:可以设置为 Cesium 画布的大小。
javascript 复制代码
material.uniforms.iResolution = new Cesium.Cartesian2(
    viewer.canvas.clientWidth,
    viewer.canvas.clientHeight
);
  1. iMouse:通过事件监听鼠标位置。
javascript 复制代码
viewer.canvas.addEventListener('mousemove', (event) => {
    const rect = viewer.canvas.getBoundingClientRect();
    material.uniforms.iMouse = new Cesium.Cartesian2(
        event.clientX - rect.left,
        event.clientY - rect.top
    );
});

3.4 使用纹理通道(iChannel)

Cesium 支持加载和绑定纹理,可用于 ShaderToy 的纹理采样需求。

  1. 加载纹理
javascript 复制代码
Cesium.Material._materialCache.addMaterial('ShaderToyWithTexture', {
    fabric: {
        type: 'ShaderToyWithTexture',
        uniforms: {
            iChannel0: Cesium.buildImageMaterialProperty({
                image: 'path/to/texture.png'
            }),
            iResolution: new Cesium.Cartesian2(1920, 1080),
            iTime: 0.0
        },
        source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                czm_material material = czm_getDefaultMaterial(materialInput);
                vec2 uv = materialInput.st;
                vec4 textureColor = texture2D(iChannel0, uv);
                material.diffuse = textureColor.rgb;
                material.alpha = textureColor.a;
                return material;
            }
        `
    },
    translucent: false
});

4. 注意事项
  1. 坐标系统:ShaderToy 使用屏幕空间坐标,而 Cesium 在地理坐标和屏幕坐标之间转换时,需要确保纹理映射正确。
  2. 性能优化:复杂着色器可能导致 Cesium 场景帧率下降,建议优化 ShaderToy 着色器逻辑。
  3. 兼容性:某些 GLSL 函数在 WebGL 中可能不可用,需要调整代码。

5. 示例完整代码

以下是一个 ShaderToy 着色器移植到 Cesium 的完整示例:

javascript 复制代码
const viewer = new Cesium.Viewer('cesiumContainer');

// 添加自定义材质
Cesium.Material._materialCache.addMaterial('DynamicShaderToy', {
    fabric: {
        type: 'DynamicShaderToy',
        uniforms: {
            iResolution: new Cesium.Cartesian2(window.innerWidth, window.innerHeight),
            iTime: 0.0
        },
        source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
                czm_material material = czm_getDefaultMaterial(materialInput);
                vec2 uv = materialInput.st;
                material.diffuse = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(iTime));
                material.alpha = 1.0;
                return material;
            }
        `
    },
    translucent: false
});

// 应用材质到实体
viewer.entities.add({
    rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
        material: new Cesium.Material({
            fabric: {
                type: 'DynamicShaderToy'
            }
        })
    }
});

// 动态更新 iTime
viewer.clock.onTick.addEventListener(() => {
    const material = viewer.entities.values[0].rectangle.material;
    material.uniforms.iTime += viewer.clock.tickDeltaSeconds;
});

通过这些步骤,您可以将 ShaderToy 的 GLSL 代码高效移植到 Cesium 场景中,用于实现炫酷的动态效果。

后处理

https://blog.csdn.net/m0_55049655/article/details/140263921

https://blog.csdn.net/m0_55049655/article/details/144428500

WebGL 中的后处理阶段

在 WebGL 中,后处理(Post-Processing)阶段是渲染管线的一部分,指的是在渲染场景或帧缓冲区内容之后,对整个帧进行额外的处理,以实现某些全屏效果或优化。后处理阶段通常会将场景的渲染结果作为输入纹理,使用额外的着色器(通常是片段着色器)来实现。


后处理的主要功能

  1. 视觉特效

    • 增强画面表现力,为场景增加特殊的视觉效果。
    • 例如:
      • 景深(Depth of Field):模拟摄像机对焦的模糊效果。
      • 运动模糊(Motion Blur):模拟物体快速移动时的模糊。
      • 泛光效果(Bloom):增强亮部区域的光晕效果。
      • 色调映射(Tone Mapping):处理高动态范围(HDR)图像以适配屏幕显示。
  2. 屏幕空间效果

    • 基于屏幕空间的后处理效果,使用屏幕上的深度或法线信息。
    • 例如:
      • 屏幕空间环境光遮蔽(SSAO):模拟物体之间遮挡的阴影效果。
      • 屏幕空间反射(SSR):实现镜面反射的效果。
      • 光晕(Lens Flare):模拟摄像机中的光斑。
  3. 图像优化

    • 调整画面亮度、对比度、饱和度等,优化整体画质。
    • 例如:
      • 伽马校正(Gamma Correction):修正亮度与色彩分布。
      • 色彩校正:调整色调和饱和度,统一画面风格。
      • 降噪:减少高频纹理中的噪点。
  4. 模拟屏幕或摄像机特性

    • 模拟现实中镜头、屏幕、胶片的特性。
    • 例如:
      • 失真(Distortion):模拟透镜的变形效果。
      • 伪像(Chromatic Aberration):模拟镜头中的色彩分散。
      • 颗粒(Film Grain):模拟老电影的颗粒感。
  5. 调试与辅助

    • 后处理阶段也常用于渲染调试和开发辅助。
    • 例如:
      • 深度可视化:将深度信息以灰度图显示。
      • 法线可视化:显示每个像素的法线方向。

后处理的工作流程

后处理的基本工作流程通常如下:

  1. 渲染到帧缓冲区(Frame Buffer Object, FBO)

    • 场景渲染的结果会被绘制到一个帧缓冲区,而不是直接输出到屏幕。
    • 帧缓冲区包含颜色纹理、深度纹理等。
  2. 使用全屏四边形进行处理

    • 创建一个覆盖整个屏幕的矩形(通常为两个三角形组成)。
    • 将帧缓冲区的内容作为纹理,传递给片段着色器。
  3. 后处理效果的实现

    • 在片段着色器中读取纹理信息,并根据需要实现特定效果。
  4. 输出最终结果

    • 将处理后的结果绘制到默认帧缓冲区(屏幕)上。

实现后处理的关键技术

  1. 帧缓冲区(Framebuffer Object, FBO)

    • WebGL 中后处理需要使用帧缓冲区将场景渲染结果保存为纹理,供后续处理。
  2. 纹理采样

    • 通过纹理采样操作,从帧缓冲区纹理中读取像素信息。
  3. 多通道渲染

    • 某些复杂效果需要多次渲染,生成多个中间纹理(例如 SSAO、HDR)。
  4. 片段着色器

    • 后处理的核心逻辑大部分在片段着色器中实现,通过操作像素级数据完成各种效果。

常见后处理效果实现原理

1. 模糊(Blur)
  • 原理
    • 读取周围像素的颜色值并求平均,生成模糊效果。
  • 实现
    • 高斯模糊(Gaussian Blur)通过二维卷积核实现逐渐变化的模糊。
glsl 复制代码
uniform sampler2D uTexture;
uniform vec2 uResolution;

void main() {
    vec2 texelSize = 1.0 / uResolution;
    vec4 color = vec4(0.0);
    
    // 简单高斯核
    float kernel[9];
    kernel[0] = 1.0; kernel[1] = 2.0; kernel[2] = 1.0;
    kernel[3] = 2.0; kernel[4] = 4.0; kernel[5] = 2.0;
    kernel[6] = 1.0; kernel[7] = 2.0; kernel[8] = 1.0;
    
    // 相邻像素偏移
    vec2 offset[9];
    offset[0] = vec2(-1, -1) * texelSize;
    offset[1] = vec2( 0, -1) * texelSize;
    offset[2] = vec2( 1, -1) * texelSize;
    offset[3] = vec2(-1,  0) * texelSize;
    offset[4] = vec2( 0,  0) * texelSize;
    offset[5] = vec2( 1,  0) * texelSize;
    offset[6] = vec2(-1,  1) * texelSize;
    offset[7] = vec2( 0,  1) * texelSize;
    offset[8] = vec2( 1,  1) * texelSize;

    // 加权采样
    for (int i = 0; i < 9; i++) {
        color += texture2D(uTexture, gl_FragCoord.xy / uResolution + offset[i]) * kernel[i];
    }
    color /= 16.0;
    
    gl_FragColor = color;
}
2. 景深(Depth of Field, DOF)
  • 原理
    • 利用深度值决定是否对某些区域模糊。
  • 实现
    • 使用深度纹理,计算每个像素到焦点的模糊程度。

后处理的优点和挑战

优点
  1. 灵活性:允许在一个统一的阶段对整个场景进行全局调整和特效应用。
  2. 多样性:通过组合不同效果,能够快速实现复杂的渲染目标。
  3. 性能优化:某些全屏效果(如抗锯齿)在后处理阶段比逐像素计算更高效。
挑战
  1. 性能消耗:后处理需要额外的帧缓冲区和纹理采样,可能带来性能开销。
  2. 复杂性:实现高质量后处理效果(如 SSAO、体积光)可能涉及复杂的数学和算法。
  3. 纹理分辨率限制:后处理效果依赖于帧缓冲区分辨率,低分辨率可能导致效果不够清晰。

总结

WebGL 中的后处理阶段主要用于对渲染结果进行全局调整和特效应用。通过利用帧缓冲区、纹理采样和片段着色器,可以实现如模糊、景深、环境光遮蔽等丰富的效果。后处理为场景渲染提供了强大的扩展能力,是现代图形渲染中的重要组成部分。

Cesium中PostProcessStage

bash 复制代码
// Simple stage to change the color
const fs =`
    uniform sampler2D colorTexture;
    in vec2 v_textureCoordinates;
    uniform float scale;
    uniform vec3 offset;
    void main() {
        vec4 color = texture(colorTexture, v_textureCoordinates);
        out_FragColor = vec4(color.rgb * scale + offset, 1.0);
    }`;
scene.postProcessStages.add(new Cesium.PostProcessStage({
    fragmentShader : fs,
    uniforms : {
        scale : 1.1,
        offset : function() {
            return new Cesium.Cartesian3(0.1, 0.2, 0.3);
        }
    }
}));

// Simple stage to change the color of what is selected.
// If czm_selected returns true, the current fragment belongs to geometry in the selected array.
const fs =`
    uniform sampler2D colorTexture;
    in vec2 v_textureCoordinates;
    uniform vec4 highlight;
    void main() {
        vec4 color = texture(colorTexture, v_textureCoordinates);
        if (czm_selected()) {
            vec3 highlighted = highlight.a * highlight.rgb + (1.0 - highlight.a) * color.rgb;
            out_FragColor = vec4(highlighted, 1.0);
        } else {
            out_FragColor = color;
        }
    }`;
const stage = scene.postProcessStages.add(new Cesium.PostProcessStage({
    fragmentShader : fs,
    uniforms : {
        highlight : function() {
            return new Cesium.Color(1.0, 0.0, 0.0, 0.5);
        }
    }
}));
stage.selected = [cesium3DTileFeature]

Cesium获取深度图

屏幕坐标反算世界坐标

https://blog.csdn.net/qq_52254412/article/details/139982116?spm=1001.2014.3001.5502

1\]巨博 城市雨洪模型配置式集成与三维可视化研究.\[D\].南京师范大学,2024.

阴影贴图

ShadowMap

https://blog.csdn.net/m0_55049655/article/details/140423323

https://blog.csdn.net/m0_55049655/article/details/140423480

在Cesium中,阴影贴图(Shadow Map)是实现场景中逼真阴影效果的主要技术之一。以下是对阴影贴图的详细解析及其在Cesium中使用的指导,并进一步探讨如何利用此技术实现场景视频融合。


阴影贴图基本原理

阴影贴图是一种基于图像的算法,用于模拟光源投射的阴影。其主要步骤如下:

  1. 从光源视角渲染深度图
    • 渲染场景,记录每个像素到光源的距离(深度值)。
  2. 场景渲染时检测阴影
    • 从场景相机的视角渲染场景,计算每个像素在光源视角下的深度值。
    • 将此值与阴影贴图中的深度值比较。如果像素的深度值大于阴影贴图记录值,则该像素被认为在阴影中。

Cesium中的阴影实现

Cesium中的阴影效果基于WebGL实现,并支持对地形、模型和几何体的阴影渲染。以下是关键点:

  1. 启用阴影

    • Cesium的阴影功能默认是关闭的,需要手动开启:

      javascript 复制代码
      viewer.shadows = true;
  2. 光源设置

    Cesium目前支持两种主要光源:

    • 太阳光:通过viewer.scene.sun自动计算太阳位置和方向。
    • 定制光源:通过编写自定义的着色器实现。
  3. ShadowMap配置

    Cesium使用ShadowMap类来管理阴影贴图的生成与应用。其主要参数包括:

    • enabled:是否启用阴影。
    • size:阴影贴图的分辨率,值越高阴影效果越细腻,但性能开销也更大。
    • softShadows:是否启用软阴影。
    • maximumDistance:阴影影响的最大距离。

    示例代码:

    javascript 复制代码
    viewer.scene.shadowMap.enabled = true;
    viewer.scene.shadowMap.size = 2048; // 提高分辨率
    viewer.scene.shadowMap.softShadows = true; // 开启软阴影
  4. 为特定对象启用阴影

    • castShadows:是否投射阴影。
    • receiveShadows:是否接收阴影。
      示例:
    javascript 复制代码
    model.castShadows = true;
    model.receiveShadows = true;

场景视频融合的实现

在视频融合场景中,目标是将真实视频的内容与虚拟3D场景无缝融合,这可以通过阴影贴图和视频纹理技术实现。

1. 加载视频纹理

使用Cesium的材质系统,将视频作为纹理映射到平面几何体上:

javascript 复制代码
const videoElement = document.createElement('video');
videoElement.src = 'path_to_video.mp4';
videoElement.loop = true;
videoElement.play();

const videoMaterial = new Cesium.Material({
    fabric: {
        type: 'Image',
        uniforms: {
            image: videoElement
        }
    }
});

const videoPlane = viewer.entities.add({
    rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(minLon, minLat, maxLon, maxLat),
        material: videoMaterial
    }
});
2. 与阴影贴图结合
  • 确保视频平面可以接收3D物体投射的阴影。
  • 通过配置receiveShadows,使视频纹理表面接收来自虚拟场景的阴影。
3. 校准视频与场景

为了实现无缝融合,需要对视频与3D场景进行视角、位置和光照校准:

  • 位置校准:确保视频平面在3D场景中的地理位置与视频内容一致。
  • 光照一致性:调整Cesium中的光源方向,使其与视频中的光影方向匹配。
  • 投影匹配 :使用Cesium的ShadowMap功能,将3D物体的阴影精确投射到视频平面上。
示例代码:
javascript 复制代码
const shadowMap = viewer.scene.shadowMap;
shadowMap.enabled = true;
shadowMap.size = 2048;

const boxEntity = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(lon, lat, height),
    box: {
        dimensions: new Cesium.Cartesian3(10, 10, 10),
        material: Cesium.Color.RED,
        castShadows: true
    }
});

videoPlane.receiveShadows = true;

优化与注意事项

  1. 性能优化

    • 阴影贴图分辨率:在视觉效果与性能之间找到平衡。
    • 裁剪范围:限制阴影贴图的作用范围,减少多余计算。
  2. 融合效果

    • 视频中的动态光影与虚拟场景光影可能不一致,这需要通过后期调试微调光源位置与方向。
  3. 多光源支持

    如果场景需要多个光源(例如多个虚拟灯光),需要自行扩展Cesium的着色器代码。


通过以上方法,Cesium的阴影贴图与视频纹理技术可实现高质量的场景视频融合,为虚拟与现实的结合提供了丰富的可能性。

  • 视频融合 视频纹理 视频贴图
  • 水文模型模拟过程可视化[二三维,输入+中间+输出数据] All in Cesium?

模型分析

模型压平

在Cesium中,CustomShader 类提供了一个强大的方式来定制模型的渲染行为。通过自定义着色器,可以对模型进行特定的操作,例如模型压平(将部分区域的高度调整为指定值)。以下是实现模型压平的详细步骤。


步骤详解

1. 创建 CustomShader

创建一个 CustomShader 对象,用于在渲染过程中修改模型的顶点或片段数据。

javascript 复制代码
const customShader = new Cesium.CustomShader({
    vertexShaderText: `
        void main() {
            czm_modelViewPosition = czm_modelView * vec4(position, 1.0);
        }
    `,
    fragmentShaderText: `
        void main() {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    `
});

此时,vertexShaderTextfragmentShaderText 定义了基本的顶点着色器和片段着色器结构。后续会逐步完善顶点处理逻辑以实现压平效果。


2. 修改顶点输出

在顶点着色器中,修改顶点位置以实现压平效果。

示例代码:

javascript 复制代码
const customShader = new Cesium.CustomShader({
    vertexShaderText: `
        void main() {
            vec4 positionInModel = czm_modelView * vec4(position, 1.0);
            
            // 自定义逻辑:修改顶点高度
            if (positionInModel.z > 50.0) { // 假设压平的高度为50
                positionInModel.z = 50.0;
            }

            gl_Position = czm_projection * positionInModel;
        }
    `
});

这段代码中:

  • positionInModel.z 表示顶点的高度。
  • 根据条件判断是否将顶点高度设置为指定值。

3. 创建范围数据

创建一个描述压平范围的数据,例如一个地理边界框或者特定区域的坐标集合。

javascript 复制代码
const flattenBounds = {
    minLon: 100.0,
    maxLon: 101.0,
    minLat: 30.0,
    maxLat: 31.0,
    flattenHeight: 50.0
};

通过这种方式,可以明确指定需要压平的区域范围以及压平后的高度。


4. 判断坐标关系

在顶点着色器中,加入对顶点坐标与范围数据的判断逻辑。

示例代码:

javascript 复制代码
const customShader = new Cesium.CustomShader({
    vertexShaderText: `
        uniform vec4 flattenBounds; // (minLon, minLat, maxLon, maxLat)
        uniform float flattenHeight;

        void main() {
            vec4 positionInModel = czm_modelView * vec4(position, 1.0);

            // 将模型坐标转换为经纬度坐标
            vec3 positionInWGS84 = czm_modelToWGS84Matrix * positionInModel.xyz;

            // 判断是否在范围内
            if (positionInWGS84.x > flattenBounds.x && positionInWGS84.x < flattenBounds.z &&
                positionInWGS84.y > flattenBounds.y && positionInWGS84.y < flattenBounds.w) {
                
                // 设置压平高度
                positionInModel.z = flattenHeight;
            }

            gl_Position = czm_projection * positionInModel;
        }
    `,
    uniforms: {
        flattenBounds: new Cesium.Cartesian4(flattenBounds.minLon, flattenBounds.minLat, flattenBounds.maxLon, flattenBounds.maxLat),
        flattenHeight: flattenBounds.flattenHeight
    }
});

说明:

  • 使用 uniform 变量将范围数据传递到着色器中。
  • 使用 czm_modelToWGS84Matrix 将模型坐标转换为地理坐标。

5. 设置压平高度

压平的核心操作是将符合条件的顶点高度设置为指定值。通过控制变量 flattenHeight,可以动态调整压平的高度。

例如:

javascript 复制代码
const flattenHeight = 50.0; // 压平后的高度

// 更新 customShader 的 uniform
customShader.setUniform('flattenHeight', flattenHeight);

将 CustomShader 应用于模型

CustomShader 对象绑定到模型上,使其生效。

示例:

javascript 复制代码
const model = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
        url: 'path/to/model.gltf',
    })
);

// 将自定义着色器应用于模型
model.customShader = customShader;

最终完整代码

以下代码整合了上述步骤,展示了完整实现:

javascript 复制代码
const flattenBounds = {
    minLon: 100.0,
    maxLon: 101.0,
    minLat: 30.0,
    maxLat: 31.0,
    flattenHeight: 50.0
};

const customShader = new Cesium.CustomShader({
    vertexShaderText: `
        uniform vec4 flattenBounds; // (minLon, minLat, maxLon, maxLat)
        uniform float flattenHeight;

        void main() {
            vec4 positionInModel = czm_modelView * vec4(position, 1.0);

            // 将模型坐标转换为经纬度坐标
            vec3 positionInWGS84 = czm_modelToWGS84Matrix * positionInModel.xyz;

            // 判断是否在范围内
            if (positionInWGS84.x > flattenBounds.x && positionInWGS84.x < flattenBounds.z &&
                positionInWGS84.y > flattenBounds.y && positionInWGS84.y < flattenBounds.w) {
                
                // 设置压平高度
                positionInModel.z = flattenHeight;
            }

            gl_Position = czm_projection * positionInModel;
        }
    `,
    uniforms: {
        flattenBounds: new Cesium.Cartesian4(flattenBounds.minLon, flattenBounds.minLat, flattenBounds.maxLon, flattenBounds.maxLat),
        flattenHeight: flattenBounds.flattenHeight
    }
});

const model = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
        url: 'path/to/model.gltf',
    })
);

model.customShader = customShader;

注意事项

  1. 性能优化

    • 压平范围较小时,可以减少对所有顶点的判断逻辑。
    • 使用更低分辨率的模型可能减少计算量。
  2. 准确性校准

    • 如果范围数据不准确,可能导致压平效果偏差。
  3. 动态交互

    • 通过监听用户交互(如鼠标点击),可以动态修改压平区域和高度。

这样实现的模型压平在场景中可以很好地适应各种地形修改需求,特别适用于建筑物基底调整或地形分析场景。

卷帘

在 Cesium 中实现卷帘效果需要结合自定义着色器(CustomShader)、屏幕空间计算(Screen Space)以及 Cesium 提供的模型显示与隐藏控制功能。以下是分步实现自定义卷帘效果的具体方法,包括屏幕区域卷帘、模型隐藏、上下卷帘、对角线卷帘。


1. 自定义卷帘的实现思路

卷帘效果是通过动态调整模型或地形的可见区域来实现的。常见方法包括:

  • 利用屏幕坐标(Screen Space)进行遮罩计算。
  • 使用 CustomShader 修改顶点或片段渲染逻辑。
  • 动态更新遮罩参数(如卷帘位置、方向等)。

2. 实现屏幕区域卷帘

屏幕区域卷帘控制场景中某一部分可见,其余部分被遮挡。

实现步骤:
  1. 计算屏幕坐标遮罩区域

    使用屏幕坐标定义卷帘范围,利用 gl_FragCoord 获取当前片段的屏幕位置。

  2. 定义遮罩逻辑

    CustomShader 的片段着色器中,将超出卷帘范围的像素隐藏(例如通过设置透明度为 0)。

示例代码:
javascript 复制代码
const customShader = new Cesium.CustomShader({
    fragmentShaderText: `
        uniform vec2 screenBounds; // 卷帘边界 (x = 左/右界限, y = 上/下界限)

        void main() {
            // 获取屏幕坐标
            vec2 screenPosition = gl_FragCoord.xy;

            // 检查是否在卷帘范围内
            if (screenPosition.x > screenBounds.x || screenPosition.y > screenBounds.y) {
                discard; // 丢弃像素
            }

            gl_FragColor = vec4(1.0); // 保留像素
        }
    `,
    uniforms: {
        screenBounds: new Cesium.Cartesian2(500.0, 300.0) // 自定义屏幕区域
    }
});

const model = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
        url: 'path/to/model.gltf',
    })
);

model.customShader = customShader;

3. 模型隐藏

通过动态调整模型的可见性,可以实现对模型的隐藏或显示。

实现步骤:
  1. 设置模型显示状态

    Cesium 提供 show 属性控制模型是否可见。

  2. 基于条件隐藏模型

    使用场景中的时间、位置或事件控制模型隐藏。

示例代码:
javascript 复制代码
const model = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
        url: 'path/to/model.gltf',
    })
);

// 隐藏模型
model.show = false;

// 显示模型
model.show = true;

4. 上下卷帘

上下卷帘控制场景从上向下或从下向上依次显示。

实现步骤:
  1. 动态控制屏幕 Y 坐标的可见性

    在片段着色器中,根据屏幕的 Y 坐标动态调整遮罩范围。

  2. 实现动画效果

    动态更新卷帘参数,形成卷帘移动的动画。

示例代码:
javascript 复制代码
const customShader = new Cesium.CustomShader({
    fragmentShaderText: `
        uniform float curtainY; // 当前卷帘 Y 坐标

        void main() {
            // 获取屏幕 Y 坐标
            float screenY = gl_FragCoord.y;

            // 判断是否在卷帘范围内
            if (screenY > curtainY) {
                discard; // 丢弃像素
            }

            gl_FragColor = vec4(1.0); // 保留像素
        }
    `,
    uniforms: {
        curtainY: 300.0 // 初始卷帘位置
    }
});

// 动画更新
viewer.scene.preRender.addEventListener(() => {
    const time = Date.now() * 0.001;
    customShader.setUniform('curtainY', 300.0 + Math.sin(time) * 200.0);
});

model.customShader = customShader;

5. 对角线卷帘

对角线卷帘根据屏幕对角线范围动态调整场景显示。

实现步骤:
  1. 计算对角线方向的屏幕坐标

    使用 gl_FragCoord 和对角线公式计算片段的对角线位置。

  2. 动态控制对角线遮罩范围

    通过条件判断,逐步扩大或缩小对角线遮罩范围。

示例代码:
javascript 复制代码
const customShader = new Cesium.CustomShader({
    fragmentShaderText: `
        uniform float diagonalPosition; // 当前对角线卷帘位置

        void main() {
            // 计算屏幕坐标和对角线位置
            float screenX = gl_FragCoord.x;
            float screenY = gl_FragCoord.y;
            float diagonal = screenX + screenY;

            // 判断是否在对角线卷帘范围内
            if (diagonal > diagonalPosition) {
                discard; // 丢弃像素
            }

            gl_FragColor = vec4(1.0); // 保留像素
        }
    `,
    uniforms: {
        diagonalPosition: 600.0 // 初始对角线位置
    }
});

// 动态更新对角线位置
viewer.scene.preRender.addEventListener(() => {
    const time = Date.now() * 0.001;
    customShader.setUniform('diagonalPosition', 600.0 + Math.sin(time) * 300.0);
});

model.customShader = customShader;

6. 整合控制与动画

通过事件和动画逻辑,整合各类卷帘效果。

示例:
  • 使用 GUI 或交互事件切换不同卷帘模式。
  • 动态调整 CustomShader 的参数。
动态控制代码:
javascript 复制代码
let currentEffect = 'vertical'; // 当前卷帘模式

// 监听用户交互
viewer.scene.canvas.addEventListener('click', () => {
    if (currentEffect === 'vertical') {
        currentEffect = 'diagonal';
    } else {
        currentEffect = 'vertical';
    }
});

// 根据模式切换卷帘逻辑
viewer.scene.preRender.addEventListener(() => {
    const time = Date.now() * 0.001;

    if (currentEffect === 'vertical') {
        customShader.setUniform('curtainY', 300.0 + Math.sin(time) * 200.0);
    } else if (currentEffect === 'diagonal') {
        customShader.setUniform('diagonalPosition', 600.0 + Math.sin(time) * 300.0);
    }
});

总结

通过上述步骤,可以实现 Cesium 中自定义卷帘效果,包括:

  1. 屏幕区域卷帘:限制特定屏幕区域的显示。
  2. 模型隐藏:动态控制模型的可见性。
  3. 上下卷帘:从上到下或从下到上显示场景。
  4. 对角线卷帘:沿屏幕对角线显示场景内容。

卷帘效果的核心是通过自定义着色器和 Cesium 的 CustomShader 功能动态调整模型的渲染行为,再结合事件监听和动画逻辑实现更灵活的交互。

相关推荐
来自星星的坤2 小时前
【Vue 3 + Vue Router 4】如何正确重置路由实例(resetRouter)——避免“VueRouter is not defined”错误
前端·javascript·vue.js
香蕉可乐荷包蛋6 小时前
浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)
前端·javascript·es6
未来之窗软件服务7 小时前
资源管理器必要性———仙盟创梦IDE
前端·javascript·ide·仙盟创梦ide
西哥写代码8 小时前
基于cornerstone3D的dicom影像浏览器 第十八章 自定义序列自动播放条
前端·javascript·vue
清风细雨_林木木8 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
雪芽蓝域zzs9 小时前
JavaScript splice() 方法
开发语言·javascript·ecmascript
森叶10 小时前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
霸王蟹10 小时前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹10 小时前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
codelxy10 小时前
vue引用cesium,解决“Not allowed to load local resource”报错
javascript·vue.js