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

基础必看

WEBGL基础(从渲染管线角度解读)

参考路线

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 场景中。

代码示例

以下是完整的代码实现:

// 三角形节点的坐标数组 [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 的示例。

// 创建自定义材质
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:传递给片段着色器的数据。
示例
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:最终片元颜色。
示例
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 字段定义。
    • 动态更新方法:
      customMaterial.uniforms.u_time = newValue;
      
  2. Attributes

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

    • Cesium 支持将纹理传递给 GPU,通常通过 Uniform 实现。
    • 示例:
      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. 多纹理混合

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

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)由数据值决定,颜色根据数据值映射至色谱(例如从蓝到红)。

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 地图上
    将生成的图片作为材质贴到平面或地形上。

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

    • 使用颜色梯度映射值。
    • 控制每个像素的高度和透明度。
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. 示例代码

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

// 创建 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)
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)
precision mediump float;
varying vec3 vColor; // 从顶点着色器传递过来的颜色

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

4.3 构建 Cesium 渲染对象

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

  1. 定义顶点数据
    包括三角形的顶点位置和颜色。
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 缓冲区。
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
    使用自定义的顶点和片段着色器。
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 场景中。
const primitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: geometry
    }),
    appearance: appearance,
    asynchronous: false
});

viewer.scene.primitives.add(primitive);

5. 完整示例代码

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

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 上找到目标着色器代码,并确认其主要逻辑。以一个简单的着色器为例:

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 的片段着色器。

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

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 的动画循环更新时间。
viewer.clock.onTick.addEventListener(() => {
    const material = viewer.entities.values[0].rectangle.material;
    material.uniforms.iTime += viewer.clock.tickDeltaSeconds;
});
  1. iResolution:可以设置为 Cesium 画布的大小。
material.uniforms.iResolution = new Cesium.Cartesian2(
    viewer.canvas.clientWidth,
    viewer.canvas.clientHeight
);
  1. iMouse:通过事件监听鼠标位置。
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. 加载纹理
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 的完整示例:

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)通过二维卷积核实现逐渐变化的模糊。
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

在这里插入图片描述

// 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的阴影功能默认是关闭的,需要手动开启:
      viewer.shadows = true;
      
  2. 光源设置
    Cesium目前支持两种主要光源:

    • 太阳光:通过viewer.scene.sun自动计算太阳位置和方向。
    • 定制光源:通过编写自定义的着色器实现。
  3. ShadowMap配置
    Cesium使用ShadowMap类来管理阴影贴图的生成与应用。其主要参数包括:

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

    示例代码:

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

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

场景视频融合的实现

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

1. 加载视频纹理

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

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物体的阴影精确投射到视频平面上。
示例代码:
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 对象,用于在渲染过程中修改模型的顶点或片段数据。

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. 修改顶点输出

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

示例代码:

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. 创建范围数据

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

const flattenBounds = {
    minLon: 100.0,
    maxLon: 101.0,
    minLat: 30.0,
    maxLat: 31.0,
    flattenHeight: 50.0
};

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


4. 判断坐标关系

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

示例代码:

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,可以动态调整压平的高度。

例如:

const flattenHeight = 50.0; // 压平后的高度

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

将 CustomShader 应用于模型

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

示例:

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

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

最终完整代码

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

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)。

示例代码:
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. 基于条件隐藏模型
    使用场景中的时间、位置或事件控制模型隐藏。

示例代码:
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. 实现动画效果
    动态更新卷帘参数,形成卷帘移动的动画。

示例代码:
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. 动态控制对角线遮罩范围
    通过条件判断,逐步扩大或缩小对角线遮罩范围。

示例代码:
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 的参数。
动态控制代码:
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 功能动态调整模型的渲染行为,再结合事件监听和动画逻辑实现更灵活的交互。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938494.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

理解数据结构 hashtable的简易理解思路

结构图 为了方便演示&#xff0c;下图中分区算法为下标取模 private int hashFun(int id) {//使用 hash并取模return id % size;}Hashtable的结构如图所示&#xff1a;是一个数组&#xff08;元素为各个链表的表头&#xff09; 多个链表组成&#xff0c;也就是说 hashtable 结…

【YashanDB知识库】kettle同步PG至崖山提示no encryption pg_hba.conf记录

【问题分类】数据导入导出 【关键字】数据同步&#xff0c;kettle&#xff0c;数据迁移&#xff0c;pg_hba.conf 【问题描述】使用kettle同步postgresql至崖山数据库时提示以下报错信息&#xff1a; 【问题原因分析】pg_hba.conf 文件中没有正确配置允许从 IP 地址 连接到数…

记录2024-leetcode-字符串DP

10. 正则表达式匹配 - 力扣&#xff08;LeetCode&#xff09;

UE5制作伤害浮动数字

效果演示&#xff1a; 首先创建一个控件UI 添加画布和文本 文本设置样式 添加伤害浮动动画&#xff0c;根据自己喜好调整&#xff0c;我设置了缩放和不透明度 添加绑定 转到事件图表&#xff0c;事件构造设置动画 创建actor蓝图类 添加widget 获取位置 设置位移 创建一个被击中…

【USB-HID】“自动化键盘“

这里写目录标题 【USB-HID】"自动化键盘"1. 前言2. 框架3. 实现3.1 模拟键盘按键输入 【USB-HID】“自动化键盘” 1. 前言 最近从朋友那了解了一种"自动化键盘"&#xff0c;能够通过上位机录制按键脚本&#xff0c;然后执行脚本&#xff0c;实现物理键盘…

STM32F407ZGT6-UCOSIII笔记4:时间片轮转调度

本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册 编写熟悉一下 UCOSIII系统的 时间片轮转调度 文章提供测试代码讲解、完整工程下载、测试效果图 目录 解决上文的卡系统问题&#xff1a; 使能时间片轮转调度&#xff1a; 任务初始化定义更改&#xff1a; 文件结构…

【Flask+OpenAI】利用Flask+OpenAI Key实现GPT4-智能AI对话接口demo - 从0到1手把手全教程(附源码)

文章目录 前言环境准备安装必要的库 生成OpenAI API代码实现详解导入必要的模块创建Flask应用实例配置OpenAI API完整代码如下&#xff08;demo源码&#xff09;代码解析 利用Postman调用接口 了解更多AI内容结尾 前言 Flask作为一个轻量级的Python Web框架&#xff0c;凭借其…

搭建springmvc项目

什么是springmvc MVC它是一种设计理念。把程序按照指定的结构来划分: Model模型 View视图 Controller控制层 springmvc框架是spring框架的一个分支。它是按照mvc架构思想设计的一款框架。 springmvc的主要作用: 接收浏览器的请求数据&#xff0c;对数据进行处理&#xff0c;…

Three.js相机Camera控件知识梳理

原文&#xff1a;https://juejin.cn/post/7231089453695238204?searchId20241217193043D32C9115C2057FE3AD64 1. 相机类型 Three.js 主要提供了两种类型的相机&#xff1a;正交相机&#xff08;OrthographicCamera&#xff09;和透视相机&#xff08;PerspectiveCamera&…

为“行车大脑”降温:Simdroid-EC助力汽车ECU设计研发

ECU&#xff08;Electronic Control Unit&#xff0c;电子控制单元&#xff09;被誉为汽车的行车大脑&#xff0c;在工作时会产生大量的热量&#xff0c;而其散热存在以下难题&#xff1a;一是工作环境恶劣&#xff0c;ECU常处于高温环境中&#xff1b;二是ECU所处的空间较为狭…

改进系列(6):基于DenseNet网络添加TripletAttention注意力层实现的番茄病害图像分类

目录 1. DenseNet 介绍 2. TripletAttention 3. DenseNet TripletAttention 4. 番茄场景病害病虫识别 4.1 数据集情况 4.2 训练 4.3 训练结果 4.4 推理 1. DenseNet 介绍 DenseNet是一种深度学习架构&#xff0c;卷积神经网络&#xff08;CNN&#xff09;的一种变体&…

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库 环境下载 MySQL 5.7.44 包安装标题检查服务是否启动成功遇到的问题登陆&修改密码&远程访问 环境 操作系统&#xff1a;Ubuntu 20.04.4 LTS 数据库&#xff1a;MySQL 5.7.34 内核版本&#xff1a;x86_64&#xff08;amd…

0基础学前端-----CSS DAY6

0基础学前端-----CSS DAY6 视频参考&#xff1a;B站Pink老师 今天是CSS学习的第六天&#xff0c;今天开始的笔记对应Pink老师课程中的CSS第三天的内容。 本节重点&#xff1a;CSS的三大特性以及CSS的盒子模型。 1.CSS的三大特性 CSS有三个重要特性&#xff1a;层叠性、继承性…

手写Redis分布式锁+RedisUtil二次封装

文章目录 1.手写Redis分布式锁1.RedisShareLockUtil2.使用方式 2.RedisUtil二次封装1.RedisUtil2.使用案例 1.手写Redis分布式锁 1.RedisShareLockUtil package com.sunxiansheng.redis.util;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springfra…

Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 预览

文章目录 一、简介二、下载 QtPdfium三、加载 QtPdfium 动态库四、Demo 使用 关于QT Widget 其它文章请点击这里: QT Widget 国际站点 GitHub: https://github.com/chenchuhan 国内站点 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF&#x…

IO的入门

目录 1.IO概述1.1流的分类 2.字符流2.1 案例 1.IO概述 IO&#xff08;Input/Output&#xff09;:输入和输出&#xff0c;指的是某个设备或环境进行数据的输入或者输出。例如&#xff1a;键盘的输入&#xff0c;再比如显示器就是输出设备&#xff0c;输出图像。 对于java来说输…

el-table表格嵌套子表格:展开所有内容;对当前展开行内容修改,当前行默认展开;

原文1 原文2 原文3 一、如果全部展开 default-expand-all"true" 二、设置有数据的行打开下拉 1、父table需要绑定两个属性expand-row-key和row-key <el-table:data"tableData":expand-row-keys"expends" //expends是数组&#xff0c;设置…

canal详解及demo

提示&#xff1a;如何保证Redis中的数据与数据库中的数据一致性&#xff1f;数据同步canal的介绍和demo、大型企业如何实现mysql到redis的同步&#xff1f;使用binlog实时更新redis缓存、canal的接入教程、win下canal的服务器端、canal客户端的创建、连接、测试教程、数据同步方…

平方根无迹卡尔曼滤波(SR-UKF)的MATLAB例程,使用三维非线性的系统

本MATLAB 代码实现了平方根无迹卡尔曼滤波&#xff08;SR-UKF&#xff09;算法&#xff0c;用于处理三维非线性状态估计问题 文章目录 运行结果代码概述代码 运行结果 三轴状态曲线对比&#xff1a; 三轴误差曲线对比&#xff1a; 误差统计特性输出&#xff08;命令行截图&…

汇编DOSBox 如何使文件可以运行

1.在vscode编写&#xff08;其他也可以&#xff09;如何在vscode中编写汇编语言并在终端进行调试(保姆级别&#xff09;_如何在vscode编译asm-CSDN博客 2.点击ML615中的DOS 2.1在命令行中输入命令 ml 文件名.asm ml 文件名.obj 2.2 将生成的exe文件移动到Assembly里面 这个文件…