1. 引言

Cesium自1.87.1版本,开始支持3DTileset使用CustomShader:

Added CustomShader class for styling Cesium3DTileset or ModelExperimental with custom GLSL shaders

在CesiumJS 1.97版本,支持Model entities使用CustomShader:

Model entities now support CustomShader

具体可参考:Releases · CesiumGS/cesium (github.com)

使用CustomShader,编写自定义的Shader,可以实现一些炫酷的特效

本文描述使用CustomShader,实现3D Tiles模型的一些特效

数据来源:功能示例(Vue版) | Mars3D三维可视化平台 | 火星科技

数据地址:http://data.mars3d.cn/3dtiles/jzw-hefei/tileset.json

2. CustomShader

Cesium中Cesium3DTileset的加载代码如下:

<body>
<!-- Include the CesiumJS JavaScript and CSS files -->
<script src="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> <div id="cesiumContainer"></div> <script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlMTk4ZTYyNy00MjkxLTRmZWYtOTg1MS0wOThjM2YzMzIzYzEiLCJpZCI6NzEyMSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0ODMxNzI5OX0.rKV8Ldl_bgR3lVvNsbHhTX62j8JH8ADCIWAwk7tXpr8';
const viewer = new Cesium.Viewer('cesiumContainer'); const tilesets = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: "//data.mars3d.cn/3dtiles/jzw-hefei/tileset.json"
})); tilesets.readyPromise.then(function (tileset) {
viewer.flyTo(tileset);
});
</script>
</body>

效果如下:

在Cesium3DTileset中,支持设置CustomShader,示例如下:

const customShader = new Cesium.CustomShader(/* ... */);

// Applying to all tiles in a tileset.
const tileset = await Cesium.Cesium3DTileset.fromUrl(
"http://example.com/tileset.json", {
customShader: customShader
});
viewer.scene.primitives.add(tileset);

具体信息可参考:

参考:CustomShader - Cesium DocumentationCustomShader的构造示例如下:

const customShader = new CustomShader({
uniforms: {
u_colorIndex: {
type: Cesium.UniformType.FLOAT,
value: 1.0
},
u_normalMap: {
type: Cesium.UniformType.SAMPLER_2D,
value: new Cesium.TextureUniform({
url: "http://example.com/normal.png"
})
}
},
varyings: {
v_selectedColor: Cesium.VaryingType.VEC3
},
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {
v_selectedColor = mix(vsInput.attributes.color_0, vsInput.attributes.color_1, u_colorIndex);
vsOutput.positionMC += 0.1 * vsInput.attributes.normal;
}
`,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
material.normal = texture(u_normalMap, fsInput.attributes.texCoord_0);
material.diffuse = v_selectedColor;
}
`
});

具体的参数及含义如下:

名字 类型 描述
mode CustomShaderMode (可选)自定义着色器模式
lightingModel LightingModel (可选)照明模型(例如 PBR 或未照明)
translucencyMode CustomShaderTranslucencyMode (可选)用于定义半透明模式
uniforms Object <string, UniformSpecifier> (可选)用于定义uniforms
varyings Object <string, VaryingType> (可选)用于声明着色器中使用的其他 GLSL varyings
vertexShaderText string (可选)作为 GLSL 代码字符串的自定义顶点着色器,必须包含一个名为 vertexMain 的 GLSL 函数
fragmentShaderText string (可选)作为 GLSL 代码字符串的自定义片段着色器,必须包含一个名为fragmentMain的GLSL函数

更为具体的CustomShader使用可参考CustomShader指南:CustomShaderGuide

通过阅读这份指南,基本可以完全了解CustomShader的使用,此处主要讲述FragmentShader的使用

FragmentShaderText必须包含函数void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material),其中FragmentInput包含的数据与结构如下:

struct FragmentInput {
// Processed attribute values. See the Attributes Struct section below.
Attributes attributes;
// Feature IDs/Batch IDs. See the FeatureIds Struct section below.
FeatureIds featureIds;
// Metadata properties. See the Metadata Struct section below.
Metadata metadata;
// Metadata class properties. See the MetadataClass Struct section below.
MetadataClass metadataClass;
// Metadata statistics. See the Metadata Statistics Struct section below
MetadataStatistics metadataStatistics;
};

czm_modelMaterial 包含的数据与结构如下:

/**
* @property {vec3} diffuse Incoming light that scatters evenly in all directions.
* @property {float} alpha Alpha of this material. 0.0 is completely transparent; 1.0 is completely opaque.
* @property {vec3} specular Color of reflected light at normal incidence in PBR materials. This is sometimes referred to as f0 in the literature.
* @property {float} roughness A number from 0.0 to 1.0 representing how rough the surface is. Values near 0.0 produce glossy surfaces, while values near 1.0 produce rough surfaces.
* @property {vec3} normalEC Surface's normal in eye coordinates. It is used for effects such as normal mapping. The default is the surface's unmodified normal.
* @property {float} occlusion Ambient occlusion recieved at this point on the material. 1.0 means fully lit, 0.0 means fully occluded.
* @property {vec3} emissive Light emitted by the material equally in all directions. The default is vec3(0.0), which emits no light.
*/
struct czm_modelMaterial {
vec3 diffuse;
float alpha;
vec3 specular;
float roughness;
vec3 normalEC;
float occlusion;
vec3 emissive;
};

综上,将Cesium3DTileset设置为白色的示例代码如下:

<body>
<!-- Include the CesiumJS JavaScript and CSS files -->
<script src="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> <div id="cesiumContainer"></div> <script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlMTk4ZTYyNy00MjkxLTRmZWYtOTg1MS0wOThjM2YzMzIzYzEiLCJpZCI6NzEyMSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0ODMxNzI5OX0.rKV8Ldl_bgR3lVvNsbHhTX62j8JH8ADCIWAwk7tXpr8';
const viewer = new Cesium.Viewer('cesiumContainer'); const customShader = new Cesium.CustomShader({
lightingModel: Cesium.LightingModel.UNLIT,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
material.diffuse = vec3(1.0);
material.alpha = 1.0;
}
`,
}); // Applying to all tiles in a tileset.
const tilesets = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: "//data.mars3d.cn/3dtiles/jzw-hefei/tileset.json",
customShader: customShader
})); tilesets.readyPromise.then(function (tileset) {
viewer.flyTo(tileset);
}); </script>
</body>

效果如下:

将Cesium3DTileset设置光带的示例代码如下:

<body>
<!-- Include the CesiumJS JavaScript and CSS files -->
<script src="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.101/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> <div id="cesiumContainer"></div> <script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlMTk4ZTYyNy00MjkxLTRmZWYtOTg1MS0wOThjM2YzMzIzYzEiLCJpZCI6NzEyMSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0ODMxNzI5OX0.rKV8Ldl_bgR3lVvNsbHhTX62j8JH8ADCIWAwk7tXpr8';
const viewer = new Cesium.Viewer('cesiumContainer'); const customShader = new Cesium.CustomShader({
lightingModel: Cesium.LightingModel.UNLIT,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
float _baseHeight = 0.0; // 物体的基础高度,需要修改成一个合适的建筑基础高度
float _heightRange = 60.0; // 高亮的范围(_baseHeight ~ _baseHeight + _heightRange) 默认是 0-60米
float _glowRange = 300.0; // 光环的移动范围(高度)
float vtxf_height = fsInput.attributes.positionMC.z-_baseHeight;
float vtxf_a11 = fract(czm_frameNumber / 120.0) * 3.14159265 * 2.0;
float vtxf_a12 = vtxf_height / _heightRange + sin(vtxf_a11) * 0.1;
material.diffuse*= vec3(vtxf_a12, vtxf_a12, vtxf_a12);
float vtxf_a13 = fract(czm_frameNumber / 360.0);
float vtxf_h = clamp(vtxf_height / _glowRange, 0.0, 1.0);
vtxf_a13 = abs(vtxf_a13 - 0.5) * 2.0;
float vtxf_diff = step(0.005, abs(vtxf_h - vtxf_a13));
material.diffuse += material.diffuse * (1.0 - vtxf_diff);
}
`,
}); // Applying to all tiles in a tileset.
const tilesets = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: "//data.mars3d.cn/3dtiles/jzw-hefei/tileset.json",
customShader: customShader
})); tilesets.readyPromise.then(function (tileset) {
viewer.flyTo(tileset);
}); </script>
</body>

fragmentShaderText代码复制自:Cesium1.87+ 实现建筑泛光效果 - 简书 (jianshu.com)

效果如下:

3. 参考资料

[1] Custom Shaders 3D Tiles - Cesium Sandcastle

[2] cesium/Documentation/CustomShaderGuide at main · CesiumGS/cesium · GitHub

[3] CustomShader - Cesium Documentation

[4] 功能示例(Vue版) | Mars3D三维可视化平台 | 火星科技

[5] Cesium1.87+ 实现建筑泛光效果 - 简书 (jianshu.com)

[6] Cesium3Dtilesets 使用customShader的解读以及泛光效果示例_cesium customshader_liuqing0.0的博客-CSDN博客

Cesium之CustomShader的更多相关文章

  1. CesiumJS 2022^ 原理[5] - 着色器相关的封装设计

    目录 1. 对 WebGL 接口的封装 1.1. 缓冲对象封装 1.2. 纹理与采样参数封装 1.3. 着色器封装 1.4. 上下文对象与渲染通道 1.5. 统一值(uniform)封装 1.6. 渲 ...

  2. cesium自定义气泡窗口infoWindow

    一.自定义气泡窗口与cesium默认窗口效果对比: 1.cesium点击弹出气泡窗口显示的位置固定在地图的右上角,默认效果: 2.对于习惯arcgis或者openlayer气泡窗口样式的giser来说 ...

  3. cesium核心类Viewer简介

    1.简单描述Viewer Viewer类是cesium的核心类,是地图可视化展示的主窗口,cesium程序应用的切入口,扮演必不可少的核心角色. 官网的英文解析如下: A base widget fo ...

  4. Cesium简介以及离线部署运行

    Cesium简介 cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎,一款开源3DGIS的js库.cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区 ...

  5. Cesium教程系列汇总

    Cesium系列目录: 应用篇 入门 Cesium应用篇:1快速搭建 影像 Cesium应用篇:2影像服务(上) Cesium应用篇:2影像服务(下) 控件 Cesium应用篇:3控件(1)Clock ...

  6. Cesium原理篇:GroundPrimitive

    今天来看看GroundPrimitive,选择GroundPrimitive有三个目的:1 了解GroundPrimitive和Primitive的区别和关系 2 createGeometry的特殊处 ...

  7. Cesium原理篇:Batch

    通过之前的Material和Entity介绍,不知道你有没有发现,当我们需要添加一个rectangle时,有两种方式可供选择,我们可以直接添加到Scene的PrimitiveCollection,也可 ...

  8. Cesium原理篇:Material

    Shader 首先,在本文开始前,我们先普及一下材质的概念,这里推荐材质,普及材质的内容都是截取自该网站,我觉得他写的已经够好了.在开始普及概念前,推荐一首我此刻想到的歌<光---陈粒>. ...

  9. Cesium原理篇:Property

    之前主要是Entity的一个大概流程,本文主要介绍Cesium的属性,比如defineProperties,Property(ConstantProperty,CallbackProperty,Con ...

  10. Cesium原理篇:5最长的一帧之影像

    如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...

随机推荐

  1. zookeeper源码(08)请求处理及数据读写流程

    ServerCnxnFactory 用于接收客户端连接.管理客户端session.处理客户端请求. ServerCnxn抽象类 代表一个客户端连接对象: 从网络读写数据 数据编解码 将请求转发给上层组 ...

  2. SATA学习笔记——OOB信号

    一.SATA物理层概述 说OOB之前,首先得了解一下SATA结构以及物理层的含义. SATA主要包括:应用层(Application Layer), 传输层(Transport Layer),链路层( ...

  3. useMemo与useCallback

    useMemo与useCallback useMemo和useCallback都可缓存函数的引用或值,从更细的角度来说useMemo则返回一个缓存的值,useCallback是返回一个缓存函数的引用. ...

  4. cf思维题

    1.B. Paranoid String 题意:操作一:01可以变成1,操作二:10可以变成0.给定一个串,判断字串经过若干次操作,能否长度变成1,统计数量. 思路:对01来说,1可以吃掉0,然后前边 ...

  5. win32 - 关于GDI的RGB的数据分析

    此文章为小结,仅供参考. 第一种情况,从桌面DC获取RGBA的数据. 32位 HDC hdc, hdcTemp; RECT rect; BYTE* bitPointer; int x, y; int ...

  6. 【Android 逆向】【ARM汇编】 arm64部分知识

    arm64寄存器更多 X0-X30 SP CPSR PC 64位 W0-W30 32位 PC寄存器的值禁止修改 参数放在 X0-X7/W0-W7 结果放在 X0 函数返回 RET 相当于 bl lr ...

  7. 【补档_C51单片机】基于C51的蜂鸣器音乐盒工程源码解析(可播放《打上花火》)

    项目地址:https://gitee.com/daycen/c51-music-box 通过Keil uVision3打开即可使用 以前做的一些小硬件,现补档至博客 1 功能及总体方案 1.1 功能描 ...

  8. 【LeetCode贪心#05】K 次取反后最大化的数组和(自定义sort、二重贪心)

    K次取反后最大化的数组和 力扣题目链接(opens new window) 给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这 ...

  9. 【Java复健指南02】方法的注意事项

    [方法] 方法基本内容 √访问修饰符 ​ (作用是控制方法使用的范围) ​ 可选,[有四种:public\protected\默认\private],具体在后面说 √返回类型 ​ 1.一个方法最多有一 ...

  10. 扣子(coze.cn)| 由浅入深,手把手带你实现Java转型学习助手

    扣子(coze.cn)是一款用来开发新一代 AI Chat Bot 的应用编辑平台,无论你是否有编程基础,都可以通过这个平台来快速创建各种类型的 Chat Bot,并将其发布到各类社交平台和通讯软件上 ...