写了一段小小的着色器代码,关于模型爆炸的,原理就是将不同的片元着色器向着法线的方向移动。虽然有点小简陋,但是加入一个小demo的情景倒也可以看看。
废话不多说,直接上代码。
<script type="module">
import ExplosiveModel from './src/ExplosiveModel.js'
Cesium.ExperimentalFeatures.enableModelExperimental = true;
var initCesium = new InitCesium();
var viewer = initCesium.initViewer("cesiumContainer", {
orderIndependentTranslucency: false,
infoBox: false,
selectionIndicator: false,
shouldAnimate: true,
});
var hpr = new Cesium.HeadingPitchRoll(0, 0, 0);
var fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator(
"north",
"west"
);
var models = {
milkTruck:
"./data/model/house/scene.gltf",
};
var explosiveModel = new ExplosiveModel(viewer);
//创建被爆炸的模型
explosiveModel.createExplosiveModel({
id:'s22fs',
modelUrl:"./data/model/house/scene.gltf",
x:123.0749919,
y:44.0503726,
z:4
});
var start = Cesium.JulianDate.fromDate(new Date());
var stop = Cesium.JulianDate.addSeconds(
start,
120,
new Cesium.JulianDate()
);
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
// viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
viewer.clock.multiplier = 1;
viewer.clock.shouldAnimate = true;
viewer.timeline.zoomTo(start, stop);
var planePosition = Cesium.Cartesian3.fromDegrees(123.0749919,44.0503706,4);
var planePosition2 = Cesium.Cartesian3.fromDegrees(123.2415, 44.0503706, 2000);
var position = new Cesium.SampledPositionProperty();
position.addSample(start, planePosition2);
position.addSample(stop, planePosition);
var hpr = new Cesium.HeadingPitchRoll(
3.1,
-0.2,
0.0
);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(
planePosition,
hpr
);
var entity = viewer.entities.add({
model: {
uri: "./data/model/Cesium_Air.glb",
scale: 0.11,
},
position: position,
orientation: orientation,
});
viewer.trackedEntity = entity;
var cTime = function (scene, time) {
if(time.secondsOfDay >= stop.secondsOfDay) {
explosiveModel.modelExplode(explosiveModel.getById('s22fs'));
viewer.scene.preUpdate.removeEventListener(cTime);
}
}
console.log(cTime)
viewer.scene.preUpdate.addEventListener(cTime);
</script>
const {ModelExperimental,CustomShader,Ellipsoid,Transforms,UniformType,Cartesian3,PrimitiveCollection,HeadingPitchRoll} = Cesium;
export default class ExplosiveModel {
constructor(viewer) {
this.viewer = viewer;
this.modelCollection = new PrimitiveCollection();
this.models = {};
this.viewer.scene.primitives.add(this.modelCollection);
}
/**
* 创建一个可爆炸的模型实体
* @param {*} entityData id,modelUrl,x,y,z,hpr
*/
createExplosiveModel(entityData) {
const {id,modelUrl,x,y,z,hpr=new HeadingPitchRoll(0, 0, 0),} = entityData;
const model = this.modelCollection.add(
ModelExperimental.fromGltf({
gltf: modelUrl, // "./CesiumMilkTruck.glb",
customShader: new CustomShader(this._getCustomShader()),
modelMatrix: Transforms.headingPitchRollToFixedFrame(
Cartesian3.fromDegrees(x,y,z),
hpr,
Ellipsoid.WGS84,
Transforms.localFrameToFixedFrameGenerator("north","west")
),
})
);
model.readyPromise.then(function (model) {
viewer.camera.flyToBoundingSphere(model.boundingSphere, {
duration: 0.5,
});
});
// this.models.push(model);
this.models[id] = model;
}
modelExplode(primitive) {
primitive.customShader?.setUniform("u_flag", 0);
const timer = window.setTimeout(() => {
this.modelExplodeStop(primitive);
window.clearTimeout(timer);
}, 600);
}
modelExplodeStop(primitive) {
primitive.customShader?.setUniform("u_flag", 1);
}
modelExplodeById(id) {
const model = this.models[id];
if(model) {
model.customShader?.setUniform("u_flag", true);
}
}
getById(id) {
return this.models[id]
}
removeAll() {
// this.models.forEach(model=>{
// model.destroy();
// });
this.modelCollection = this.modelCollection && this.modelCollection.destroy();
this.models = {};
}
removeById(id) {
if(this.models[id]) {
this.modelCollection.remove(this.models[id]);
delete this.models[id];
console.log(this.models);
}
}
_getCustomShader () {
return {
uniforms: {
u_flag: {
type: UniformType.INT,
value: 2,
},
// u_drag: {
// type: Cesium.UniformType.VEC2,
// value: new Cesium.Cartesian2(0.0, 0.0),
// },
u_speed: {
type:UniformType.FLOAT,
value:3.0
}
// czm_frameNumber:{
// type: Cesium.UniformType.FLOAT,
// value: 1.0
// },
},
//positionMC +=(vsInput.attributes.normalMC.x , vsInput.attributes.normalMC.y ,0.02 * u_drag.x * vsInput.attributes.normalMC.z);
//positionMC += vec3(a_vertex.x ,a_vertex.y ,a_vertex.z) * vsInput.attributes.normalMC;
//positionMC += vsInput.attributes.normalMC * vsInput.attributes.normalMC;
vertexShaderText:
`
attribute vec4 position;
void vertexMain(VertexInput vsInput, inout vec3 positionMC)
{
if(u_flag == 0) {
float cycle = u_speed * mod(czm_frameNumber , 100.0);
positionMC += vsInput.attributes.normalMC * position.xyz;
positionMC += 0.01 * cycle * vsInput.attributes.normalMC;
}
else if(u_flag == 1) {
positionMC += 0.01 * 300.0 * vsInput.attributes.normalMC;
}
else
positionMC += 0.01 * vsInput.attributes.normalMC;
}`
,
// material.diffuse = vec3(flagColor);
// fragmentShaderText: `
// void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
// gl_FragColor
// }
// `
}
}
}
时间太久远了,去年写的小demo,有些东西也记不清了,但是可以参考借鉴一下。