Cesium之CustomShader

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>

效果如下:

image-20230403224016199

在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>

效果如下:

image-20230404001249582

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

效果如下:

image-20230404001704653

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博客

posted @   当时明月在曾照彩云归  阅读(3585)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示