1.下雪粒子效果启动后,新增在模型上添加积雪效果;

This commit is contained in:
zhangquan 2025-07-31 18:11:52 +08:00
parent 7a861756c6
commit eef0209e58
3 changed files with 109 additions and 0 deletions

View File

@ -31,6 +31,8 @@ export const useWeatherParticle = (viewer) => {
weather = new SnowEffect(_viewer, { weather = new SnowEffect(_viewer, {
snowSize: 0.02, // ❄大小最好小于0.02 snowSize: 0.02, // ❄大小最好小于0.02
snowSpeed: 60.0, // 速度 snowSpeed: 60.0, // 速度
isCover: true, // 是否显示积雪覆盖效果
coverage: 0.3, // 积雪覆盖(混色)占比
}); });
weather.show(true); weather.show(true);
}; };

View File

@ -13,6 +13,9 @@ class SnowEffect {
options = options || {}; options = options || {};
this.snowSize = Cesium.defaultValue(options.snowSize, 0.02); // ❄大小最好小于0.02 this.snowSize = Cesium.defaultValue(options.snowSize, 0.02); // ❄大小最好小于0.02
this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 60.0); // 速度 this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 60.0); // 速度
// 积雪效果
this.isCover = Cesium.defaultValue(options.isCover, false); // 是否显示积雪覆盖效果
this.coverage = Cesium.defaultValue(options.coverage, 0.3); // 积雪覆盖(混色)占比
this.viewer = viewer; this.viewer = viewer;
this.init(); this.init();
} }
@ -31,6 +34,27 @@ class SnowEffect {
}, },
}); });
this.viewer.scene.postProcessStages.add(this.snowStage); this.viewer.scene.postProcessStages.add(this.snowStage);
if(this.isCover) {
const coverShader = new Cesium.CustomShader({
uniforms: {
u_lightColor: {
type: Cesium.UniformType.VEC3,
value: new Cesium.Cartesian3(1, 1, 1),
},
u_snowAlpha: {
type: Cesium.UniformType.FLOAT,
value: this.coverage,
},
},
fragmentShaderText: this.cover()
})
for (let index = 0; index < this.viewer.scene.primitives.length; index++) {
const primitive = this.viewer.scene.primitives.get(index);
if(primitive instanceof Cesium.Cesium3DTileset) {
primitive.customShader = coverShader;
}
}
}
} }
destroy() { destroy() {
@ -43,6 +67,19 @@ class SnowEffect {
} }
delete this.snowSize; delete this.snowSize;
delete this.snowSpeed; delete this.snowSpeed;
// 销毁积雪效果
if(this.isCover === undefined) return;
if(this.isCover) {
for (let index = 0; index < this.viewer.scene.primitives.length; index++) {
const primitive = this.viewer.scene.primitives.get(index);
if(primitive instanceof Cesium.Cesium3DTileset) {
primitive.customShader = undefined;
}
}
delete this.isCover;
delete this.coverStage;
}
} }
show(visible) { show(visible) {
this.snowStage.enabled = visible; this.snowStage.enabled = visible;
@ -82,5 +119,71 @@ class SnowEffect {
}\n\ }\n\
"; ";
} }
cover() {
return `
#define MAX_RADIUS 2
// Set to 1 to hash twice. Slower, but less patterns.
#define DOUBLE_HASH 0
// Hash functions shamefully stolen from:
// https://www.shadertoy.com/view/4djSRW
#define HASHSCALE1 .1031
#define HASHSCALE3 vec3(.1031, .1030, .0973)
float hash12(vec2 p)
{
vec3 p3 = fract(vec3(p.xyx) * HASHSCALE1);
p3 += dot(p3, p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3.z);
}
vec2 hash22(vec2 p)
{
vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3);
p3 += dot(p3, p3.yzx+19.19);
return fract((p3.xx+p3.yz)*p3.zy);
}
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
vec3 positionEC = fsInput.attributes.positionEC;
vec3 positionMC = fsInput.attributes.positionMC;
vec2 uv = fsInput.attributes.texCoord_0 * 500.;
vec3 pos_dx = dFdx(positionEC);
vec3 pos_dy = dFdy(positionEC);
vec3 normalEC = normalize(cross(pos_dx, pos_dy));
vec4 positionWC = normalize(czm_inverseView * vec4(positionEC,1.0));
vec3 normalWC = normalize(czm_inverseViewRotation * normalEC);
float time = czm_frameNumber / 60.0;
vec2 p0 = floor(uv);
vec2 circles = vec2(0.);
for (int j = -MAX_RADIUS; j <= MAX_RADIUS; ++j)
{
for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i)
{
vec2 pi = p0 + vec2(i, j);
#if DOUBLE_HASH
vec2 hsh = hash22(pi);
#else
vec2 hsh = pi;
#endif
vec2 p = pi + hash22(hsh);
float t = fract(0.3*time + hash12(hsh));
vec2 v = p - uv;
float d = length(v) - (float(MAX_RADIUS) + 1.)*t;
float h = 1e-3;
float d1 = d - h;
float d2 = d + h;
float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1);
float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2);
circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t));
}
}
circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1));
vec3 n = vec3(circles, sqrt(1. - dot(circles, circles)));
material.diffuse = mix(material.diffuse, vec3(1.0) , u_snowAlpha * smoothstep(0., .5, dot(positionWC.xyz, normalWC)));
material.diffuse *= min(max(0.0, dot(normalEC, czm_sunDirectionEC) * 1.0) + u_lightColor, 1.0);
}
`;
}
} }
export default SnowEffect; export default SnowEffect;

View File

@ -25,6 +25,10 @@ const options = ref({
}, },
ditu: 'tianditu', // ditu: 'tianditu', //
isTerrainProvider: true, // isTerrainProvider: true, //
modelList: [
'/model/hu_ma_shan/tileset.json',
'/model/yi_liu/tileset.json'
], //
}) })
const showProperty = ref(false); // const showProperty = ref(false); //
const propertyData = ref([]) const propertyData = ref([])