使用mapbox为地图容器,结合threebox实现下雨效果,天气特效
效果图
主要代码
mapboxgl.accessToken = '你的token';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v9',
pitch: 80,
center: [116.201756, 39.326785],//坐标
zoom: 16, //层级
antialias: true
});
map.addLayer({
id: 'custom_layer',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, mbxContext) {
window.tb = new Threebox(
map,
mbxContext,
{ defaultLights: true }
);
camera = map.getFreeCameraOptions();
var mesh = addRainMesh();
mesh = window.tb.Object3D({ obj: mesh, units: 'meters', bbox: false, anchor: 'center' })
.setCoords([116.201756, 39.326785, 0]);
mesh.setRotation({ x: 90, y: 0, z: 0 });
tb.add(mesh)
},
render: function (gl, matrix) {
tb.update();
map.triggerRepaint();
}
});
function addRainMesh() {
// 雨的盒子
const box = new THREE.Box3(
new THREE.Vector3(-5000, 0, -5000),
// 下雨的范围
new THREE.Vector3(5000, 5000, 5000)
);
//创建雨(雨的材质)
material = new THREE.MeshBasicMaterial({
transparent: true,
opacity: 0.5,
map: new THREE.TextureLoader().load("./image/drop.png"),
depthWrite: false,
});
material.onBeforeCompile = function (shader, renderer) {
const getFoot = `
uniform float top;
uniform float bottom;
uniform float time;
#include
float angle(float x, float y){
return atan(y, x);
}
vec2 getFoot(vec2 camera,vec2 normal,vec2 pos){
vec2 position;
float distanceLen = distance(pos, normal);
float a = angle(camera.x - normal.x, camera.y - normal.y);
pos.x > normal.x ? a -= 0.785 : a += 0.785;
position.x = cos(a) * distanceLen;
position.y = sin(a) * distanceLen;
return position + normal;
}
`;
const begin_vertex = `
vec2 foot = getFoot(vec2(cameraPosition.x, cameraPosition.z), vec2(normal.x, normal.z), vec2(position.x, position.z));
float height = top - bottom;
float y = normal.y - bottom - height * time;
y = y + (y < 0.0 ? height : 0.0);
float ratio = (1.0 - y / height) * (1.0 - y / height);
y = height * (1.0 - ratio);
y += bottom;
y += position.y - normal.y;
vec3 transformed = vec3( foot.x, y, foot.y );
`;
shader.vertexShader = shader.vertexShader.replace(
"#include ",
getFoot
);
shader.vertexShader = shader.vertexShader.replace(
"#include ",
begin_vertex
);
shader.uniforms.cameraPosition = {
value: new THREE.Vector3(0, 200, 0),
};
shader.uniforms.top = {
value: 5000,
};
shader.uniforms.bottom = {
value: 0,
};
shader.uniforms.time = {
value: 0,
};
material.uniforms = shader.uniforms;
};
var geometry = new THREE.BufferGeometry();
const vertices = [];
const normals = [];
const uvs = [];
const indices = [];
// 雨量
for (let i = 0; i < 5000; i++) {
const pos = new THREE.Vector3();
pos.x = Math.random() * (box.max.x - box.min.x) + box.min.x;
pos.y = Math.random() * (box.max.y - box.min.y) + box.min.y;
pos.z = Math.random() * (box.max.z - box.min.z) + box.min.z;
const height = (box.max.y - box.min.y) / 15;
const width = height / 50;
vertices.push(
pos.x + width,
pos.y + height / 2,
pos.z,
pos.x - width,
pos.y + height / 2,
pos.z,
pos.x - width,
pos.y - height / 2,
pos.z,
pos.x + width,
pos.y - height / 2,
pos.z
);
normals.push(
pos.x,
pos.y,
pos.z,
pos.x,
pos.y,
pos.z,
pos.x,
pos.y,
pos.z,
pos.x,
pos.y,
pos.z
);
uvs.push(1, 1, 0, 1, 0, 0, 1, 0);
indices.push(
i * 4 + 0,
i * 4 + 1,
i * 4 + 2,
i * 4 + 0,
i * 4 + 2,
i * 4 + 3
);
}
geometry.addAttribute(
"position",
new THREE.BufferAttribute(new Float32Array(vertices), 3)
);
geometry.addAttribute(
"normal",
new THREE.BufferAttribute(new Float32Array(normals), 3)
);
geometry.addAttribute(
"uv",
new THREE.BufferAttribute(new Float32Array(uvs), 2)
);
geometry.setIndex(new THREE.BufferAttribute(new Uint32Array(indices), 1));
var mesh = new THREE.Mesh(geometry, material);
return mesh;
}
function render() {
// 下雨速率
time = (time + clock.getDelta() * 0.3) % 1;
if (!camera) {
return
}
material.cameraPosition = camera.position;
if (material.uniforms) {
material.uniforms.time.value = time;
}
}
代码下载地址:https://download.csdn.net/download/AllBluefm/88781246?spm=1001.2014.3001.5503