一、效果
二、技术栈
cesium 1.103 + vue3
三、代码实现
/*
动态墙材质
color 颜色
duration 持续时间 毫秒
trailImage 贴图地址
*/
import * as Cesium from 'cesium'
export default class DynamicWallMaterialProperty {
constructor(options) {
// 默认参数设置
this._definitionChanged = new Cesium.Event() // 材质定义变更事件
this._color = undefined // 颜色属性
this._colorSubscription = undefined // 颜色变化订阅
this.color = options.color // 从选项中获取颜色
this.duration = options.duration // 持续时间
this.trailImage = options.trailImage // 路径图像
this._time = new Date().getTime() // 当前时间戳
this._viewer = options.viewer // Cesium 视图对象
}
// 返回材质类型
getType(time) {
return MaterialType // 返回材质类型名称
}
getValue(time, result) {
if (!Cesium.defined(result)) {
result = {} // 如果结果未定义,则初始化为空对象
}
result.color = Cesium.Property.getValueOrClonedDefault(
this._color, // 获取颜色值
time, // 当前时间
Cesium.Color.WHITE, // 默认颜色为白色
result.color // 结果对象中的颜色属性
)
// 使用自定义的路径图像
result.image = this.trailImage
// 计算时间进度
if (this.duration) {
result.time =
((new Date().getTime() - this._time) % this.duration) / this.duration
}
this._viewer.scene.requestRender() // 请求重新渲染场景
return result
}
// 比较两个 DynamicWallMaterialProperty 对象是否相等
equals(other) {
return (
this === other || // 判断是否为同一对象
(other instanceof DynamicWallMaterialProperty && // 判断是否为 DynamicWallMaterialProperty 的实例
Cesium.Property.equals(this._color, other._color)) // 比较颜色属性
)
}
}
/**
* 带方向的墙体
* @param {*} options.get:true/false
* @param {*} options.count:数量
* @param {*} options.freely:vertical/standard
* @param {*} options.direction:+/-
*/
function _getDirectionWallShader(options) {
if (options && options.get) {
// 定义了一个函数 czm_getMaterial,输入参数为 materialInput,返回值为 czm_material 类型的材质。
var materail = `czm_material czm_getMaterial(czm_materialInput materialInput)
{
// 调用 czm_getDefaultMaterial 函数获取一个默认的材质实例,并将其存储在 material 变量中
czm_material material = czm_getDefaultMaterial(materialInput);
// 获取纹理坐标(st)的二维向量
vec2 st = materialInput.st;`
// 垂直方向动态效果
if (options.freely == 'vertical') {
//(由下到上)
// texture(image, vec2(u,v)),st.s 是水平方向上的纹理坐标,st.t 是垂直方向上的纹理坐标。
// 如果要实现上下垂直滚动的效果,就要设置st.t随时间的动态,而st.s值不变。
// 如果要实现左右水平滚动的效果,就要设置st.s随时间的动态,而st.t值不变。
materail +=
// 纹理采样,依据时间动态变化,fract 函数用于计算余数,使纹理坐标在[0, 1)范围内循环。
'vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(' +
options.count +
')*st.t' +
options.direction +
' time)));\n '
} else {
// 水平方向的动态效果
//(逆时针)
materail +=
'vec4 colorImage = texture(image, vec2(fract(float(' +
options.count +
')*st.s ' +
options.direction +
' time), fract(st.t)));\n '
console.log('materail2: ', materail)
}
//泛光
materail += `vec4 fragColor;
fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;
fragColor = czm_gammaCorrect(fragColor);
material.diffuse = colorImage.rgb;
material.alpha = colorImage.a;
material.emission = fragColor.rgb;
return material;
}`
return materail
}
}
// 定义属性
Object.defineProperties(DynamicWallMaterialProperty.prototype, {
isConstant: {
get: function () {
return false // 返回材质是否是常量(动态材质返回 false)
},
},
definitionChanged: {
get: function () {
return this._definitionChanged // 返回定义变更事件
},
},
color: Cesium.createPropertyDescriptor('color'), // 创建颜色属性描述符
})
// 定义一个变量MaterialType,其值为字符串'wallType'加上一个随机数
var MaterialType = 'wallType' + parseInt(Math.random() * 1000)
// 定义默认图像路径
let DynamicWallImage = '/src/assets/col.png'
// 将材质添加到缓存中
Cesium.Material._materialCache.addMaterial(MaterialType, {
fabric: {
type: MaterialType, // 设置材质类型
uniforms: {
color: new Cesium.Color(1.0, 0.0, 0.0, 0.5), // 设置颜色属性
image: DynamicWallImage, // 设置图像路径
time: -20, // 设置时间属性
},
source: _getDirectionWallShader({
get: true,
count: 3.0,
freely: 'vertical', //或者standard
direction: '+',
}),
},
translucent: function (material) {
return true // 确定材质是否是半透明的
},
})
调用
import DynamicWallMaterialProperty from '../../utils/cesium/WallDiffuseDymaticMaterial.js'
let positions = Cesium.Cartesian3.fromDegreesArray([
113.8236839, 22.528061, 113.9236839, 22.628061, 114.0236839, 22.528061,
113.9236839, 22.428061, 113.8236839, 22.528061,
])
// 绘制墙体
const wall = viewer.entities.add({
name: '立体墙效果',
wall: {
positions: positions,
// 设置高度
maximumHeights: new Array(positions.length).fill(600),
minimumHeights: new Array(positions.length).fill(0),
material: new DynamicWallMaterialProperty({
viewer,
// trailImage: '/src/assets/vertical.png',
trailImage: '/src/assets/standard.png',
color: Cesium.Color.RED,
duration: 1500,
}),
},
})
viewer.zoomTo(wall)
四、动态过程
(一) 垂直方向
图片资源
- 往下滚动
vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(3)*st.t + time)));
source: _getDirectionWallShader({
get: true,
count: 3.0,
freely: 'vertical', //或者standard
direction: '+',
}),
- 往上滚动
vec4 colorImage = texture(image, vec2(fract(st.s), fract(float(3)*st.t - time)));
source: _getDirectionWallShader({
get: true,
count: 3.0,
freely: 'vertical', //或者standard
direction: '-',
}),
(二) 水平方向
图片资源
- 顺时针
vec4 colorImage = texture(image, vec2(fract(float(8)*st.s - time), fract(st.t)));
source: _getDirectionWallShader({
get: true,
count: 20.0,
freely: 'standard', //或者standard
direction: '-',
}),
- 逆时针
vec4 colorImage = texture(image, vec2(fract(float(8)*st.s + time), fract(st.t)));
source: _getDirectionWallShader({
get: true,
count: 20.0,
freely: 'standard', //或者standard
direction: '+',
}),
纹理坐标系概述
- 坐标范围:
-
- 纹理坐标通常以
[0, 1]
范围表示。 vec2
类型的纹理坐标texture(image, vec2(u, v))
中:
- 纹理坐标通常以
-
-
u
是 x 轴坐标,通常用于水平采样。v
是 y 轴坐标,通常用于垂直采样。
-
-
u
和v
的值可以超出[0, 1]
范围,以实现纹理的重复或延展。
- 坐标系:
-
- 左下角为原点:在大多数图形应用中,纹理坐标系统以左下角为原点 (0, 0),右上角为 (1, 1)。
- 当 u 和 v 值都为 0 时,表示纹理的左下角,u 为 1 和 v 为 1 时表示纹理的右上角。
st
向量的组成
st
是一个 vec2
变量,包含了纹理坐标的两个分量:
st.s
:表示纹理的水平坐标(u 轴)。st.t
:表示纹理的垂直坐标(v 轴)
texture(image, vec2(u,v)),st.s 是水平方向上的纹理坐标,st.t 是垂直方向上的纹理坐标。
如果要实现上下垂直滚动的效果,就要设置st.t随时间的动态,而st.s值不变,也就是 v 方向上变,u 方向上不变
如果要实现左右水平滚动的效果,就要设置st.s随时间的动态,而st.t值不变,也就是 u 方向上变,v 方向上不变
五、泛光效果
定义一个 vec4 类型的变量 fragColor
存储片段颜色
设置fragColor的 rgb 分量颜色
对 fragColor 进行 gamma 校正
设置材质
alpha 值——material.alpha
diffuse 漫反射颜色 ——material.diffuse
emission 发光颜色 ——material.emission
//泛光
materail += `vec4 fragColor;
fragColor.rgb = (colorImage.rgb+color.rgb) / 1.0;
fragColor = czm_gammaCorrect(fragColor);
material.diffuse = colorImage.rgb;
material.alpha = colorImage.a;
material.emission = fragColor.rgb;
return material;
}`
1.为何使用一个 vec4 类型定义 fragColor
vec4 表示一个包含四个浮点数的数据类型,而fragColor
通常用来存储一个片段(一个像素)的颜色,其中包括红色、绿色、蓝色和 alpha(透明度)四个分量,所以用 vec4 类型来定义 fragColor
2.这里的 fragColor 的 rgb 分量是去纹理的 rgb 和传入颜色的 rgb 二者混合,除以 1,代表 rgb 颜色值已经是合适的范围(0.0 到 1.0)
3.gamma 校正
为什么
- Gamma 校正用于调整图像的亮度,使其更接近人眼感知的非线性方式。这在将计算的颜色显示到屏幕上时非常重要,可以提高视觉效果的自然性。
怎么做
- 使用
czm_gammaCorrect
函数应用 gamma 校正到fragColor
。
4.diffuse,alpha,emission
- Diffuse: 控制材质表面对光的漫反射,影响材质颜色的基调。
- Alpha: 控制材质的透明度。
- Emission: 控制材质自发光的颜色,使材质看起来像是自己发光。
六、参考文章
cesium加载电子围栏,通过shader自定义材质实现动态墙效果,cavans自定义材质实现分层效果_cesium自定义shader动画效果-CSDN博客