提交 f3c475d0 authored 作者: 詹银鑫's avatar 詹银鑫

新增烟雾效果无人机移动效果

上级 fb9d11bf
...@@ -17,6 +17,7 @@ import arrow from "@/assets/texture/arrow.png" ...@@ -17,6 +17,7 @@ import arrow from "@/assets/texture/arrow.png"
import point from "@/assets/texture/point1.png" import point from "@/assets/texture/point1.png"
import flyLineFocus from "@/assets/texture/guangquan01.png" import flyLineFocus from "@/assets/texture/guangquan01.png"
import mapFlyline from "@/assets/texture/flyline6.png" import mapFlyline from "@/assets/texture/flyline6.png"
import smoke from "@/assets/texture/smoke.png"
// 焦点贴图 // 焦点贴图
import focusArrowsTexture from "@/assets/texture/focus/focus_arrows.png" import focusArrowsTexture from "@/assets/texture/focus/focus_arrows.png"
import focusBarTexture from "@/assets/texture/focus/focus_bar.png" import focusBarTexture from "@/assets/texture/focus/focus_bar.png"
...@@ -89,6 +90,7 @@ export class Assets { ...@@ -89,6 +90,7 @@ export class Assets {
{ type: "Texture", name: "mapFlyline", path: mapFlyline }, { type: "Texture", name: "mapFlyline", path: mapFlyline },
{ type: "Texture", name: "arrow", path: arrow }, { type: "Texture", name: "arrow", path: arrow },
{ type: "Texture", name: "point", path: point }, { type: "Texture", name: "point", path: point },
{ type: "Texture", name: "smoke", path: smoke },
// focus // focus
{ type: "Texture", name: "focusArrows", path: focusArrowsTexture }, { type: "Texture", name: "focusArrows", path: focusArrowsTexture },
......
...@@ -58,6 +58,8 @@ import gsap from "gsap"; ...@@ -58,6 +58,8 @@ import gsap from "gsap";
import emitter from "@/utils/emitter"; import emitter from "@/utils/emitter";
import { InteractionManager } from "three.interactive"; import { InteractionManager } from "three.interactive";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 引入模型加载模块 // 引入模型加载模块
import { Resource } from "@/mini3d/utils/Resource"; import { Resource } from "@/mini3d/utils/Resource";
...@@ -68,6 +70,15 @@ function sortByValue(data) { ...@@ -68,6 +70,15 @@ function sortByValue(data) {
export class World extends Mini3d { export class World extends Mini3d {
constructor(canvas, assets) { constructor(canvas, assets) {
super(canvas); super(canvas);
this.controls = new OrbitControls(
this.camera.instance,
this.renderer.instance.domElement
);
this.controls.target.set(0, 0, 0);
this.controls.minPolarAngle = Math.PI / 6;
this.controls.maxPolarAngle = Math.PI * 0.44;
// 中心坐标 // 中心坐标
// this.geoProjectionCenter = [113.280637, 23.125178] // this.geoProjectionCenter = [113.280637, 23.125178]
this.geoProjectionCenter = [110.840171, 39.864362]; this.geoProjectionCenter = [110.840171, 39.864362];
...@@ -118,6 +129,9 @@ export class World extends Mini3d { ...@@ -118,6 +129,9 @@ export class World extends Mini3d {
this.initEnvironment(); this.initEnvironment();
this.init(); this.init();
console.log("执行了 这些代码"); console.log("执行了 这些代码");
this.droneMoveState = { w: false, a: false, s: false, d: false };
window.addEventListener("keydown", (e) => this.onKeyDown(e));
window.addEventListener("keyup", (e) => this.onKeyUp(e));
} }
init() { init() {
// 标签组 // 标签组
...@@ -181,6 +195,12 @@ export class World extends Mini3d { ...@@ -181,6 +195,12 @@ export class World extends Mini3d {
0.5, 0.5,
5 5
); );
// 创建火焰和烟雾
this.createFireWithSmoke([
[110.9801, 39.8002],
[111.0806, 39.7005],
// ...更多经纬度
]);
// 创造3d地形 // 创造3d地形
// this.createTerrain() // this.createTerrain()
// 创造geoJson图 // 创造geoJson图
...@@ -1690,111 +1710,13 @@ export class World extends Mini3d { ...@@ -1690,111 +1710,13 @@ export class World extends Mini3d {
waterGroup, waterGroup,
}; };
} }
createLineWater() {
// 获取水的GeoJSON线数据
let mapJsonData = this.assets.instance.getResource("linewater");
let lineWaterJson;
try {
lineWaterJson =
typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
} catch (e) {
console.error("linewater 解析失败", e);
return { lineWaterGroup: null };
}
// 加载法线贴图
const textureLoader = new THREE.TextureLoader();
let base_url = import.meta.env.BASE_URL || "/";
const normalMap = textureLoader.load(
base_url + "assets/json/waternormals.jpg"
);
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// 可选:加载一张水面颜色贴图
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// 动画流动
this.time.on("tick", () => {
normalMap.offset.x += 0.002; // 控制流动速度和方向
normalMap.offset.y += 0.001;
// 如果有颜色贴图,也可以流动
// waterMap.offset.x += 0.001;
});
// 创建线水组
const lineWaterGroup = new Group();
const projection = geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0]);
(lineWaterJson.features || []).forEach((feature) => {
const geometry = feature.geometry;
if (!geometry) return;
let lines = [];
if (geometry.type === "LineString") {
lines = [geometry.coordinates];
} else if (geometry.type === "MultiLineString") {
lines = geometry.coordinates;
}
lines.forEach((line) => {
const points = line.map(([lng, lat]) => {
const [x, y] = projection([lng, lat]);
return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表
});
const geometryLine = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({
color: 0x3bb9ff,
linewidth: 2,
transparent: true,
opacity: 0.8,
depthWrite: false,
});
const lineObj = new THREE.Line(geometryLine, material);
lineObj.renderOrder = 11;
lineWaterGroup.add(lineObj);
});
// lines.forEach((line) => {
// const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26);
// });
// if (points.length < 2) return;
// const curve = new THREE.CatmullRomCurve3(points);
// const tubeGeometry = new THREE.TubeGeometry(curve, 64, 0.05, 8); // 0.05为线粗
// // const material = new THREE.MeshBasicMaterial({
// // color: 0x3bb9ff,
// // transparent: true,
// // opacity: 0.8,
// // depthWrite: false,
// // });
// const material = new THREE.MeshStandardMaterial({
// color: 0x153e7e,
// transparent: true,
// opacity: 0.5,
// side: DoubleSide,
// depthWrite: false,
// normalMap: normalMap,
// normalScale: new THREE.Vector2(1, 1), // 可调节凹凸强度
// // map: waterMap, // 如果有颜色贴图可加上
// metalness: 0.3,
// roughness: 0.7,
// });
// const mesh = new THREE.Mesh(tubeGeometry, material);
// mesh.renderOrder = 11;
// lineWaterGroup.add(mesh);
// });
});
return {
lineWaterGroup,
};
}
// createLineWater() { // createLineWater() {
// // 获取水的GeoJSON线数据 // // 获取水的GeoJSON线数据
// let mapJsonData = this.assets.instance.getResource("linewater"); // let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson; // let lineWaterJson;
// try { // try {
// lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData; // lineWaterJson =
// typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
// } catch (e) { // } catch (e) {
// console.error("linewater 解析失败", e); // console.error("linewater 解析失败", e);
// return { lineWaterGroup: null }; // return { lineWaterGroup: null };
...@@ -1803,21 +1725,28 @@ export class World extends Mini3d { ...@@ -1803,21 +1725,28 @@ export class World extends Mini3d {
// // 加载法线贴图 // // 加载法线贴图
// const textureLoader = new THREE.TextureLoader(); // const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/"; // let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg"); // const normalMap = textureLoader.load(
// base_url + "assets/json/waternormals.jpg"
// );
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping; // normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png"); // 你需要准备一张水波纹PNG // // 可选:加载一张水面颜色贴图
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping; // // const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
// // waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// // 动画流动 // // 动画流动
// this.time.on("tick", () => { // this.time.on("tick", () => {
// normalMap.offset.x += 0.002; // normalMap.offset.x += 0.002; // 控制流动速度和方向
// normalMap.offset.y += 0.001; // normalMap.offset.y += 0.001;
// waterMap.offset.x += 0.002; // 让颜色贴图也流动 // // 如果有颜色贴图,也可以流动
// // waterMap.offset.x += 0.001;
// }); // });
// // 创建线水组 // // 创建线水组
// const lineWaterGroup = new Group(); // const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]); // const projection = geoMercator()
// .center(this.geoProjectionCenter)
// .scale(this.geoProjectionScale)
// .translate([0, 0]);
// (lineWaterJson.features || []).forEach((feature) => { // (lineWaterJson.features || []).forEach((feature) => {
// const geometry = feature.geometry; // const geometry = feature.geometry;
// if (!geometry) return; // if (!geometry) return;
...@@ -1828,31 +1757,52 @@ export class World extends Mini3d { ...@@ -1828,31 +1757,52 @@ export class World extends Mini3d {
// lines = geometry.coordinates; // lines = geometry.coordinates;
// } // }
// lines.forEach((line) => { // lines.forEach((line) => {
// // 生成带宽度的水带
// const points = line.map(([lng, lat]) => { // const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]); // const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表 // return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表
// }); // });
// if (points.length < 2) return; // const geometryLine = new THREE.BufferGeometry().setFromPoints(points);
// // 用TubeGeometry生成带宽度的水带 // const material = new THREE.LineBasicMaterial({
// const curve = new THREE.CatmullRomCurve3(points); // color: 0x3bb9ff,
// const tubeGeometry = new THREE.TubeGeometry(curve, Math.max(32, points.length * 2), 0.01, 16); // linewidth: 2,
// const material = new THREE.MeshStandardMaterial({
// color: 0x4fc3ff,
// transparent: true, // transparent: true,
// opacity: 0.35, // opacity: 0.8,
// side: DoubleSide,
// depthWrite: false, // depthWrite: false,
// normalMap: normalMap,
// normalScale: new THREE.Vector2(2, 2),
// map: waterMap, // 使用颜色贴图
// metalness: 0.3,
// roughness: 0.7,
// }); // });
// const mesh = new Mesh(tubeGeometry, material); // const lineObj = new THREE.Line(geometryLine, material);
// mesh.renderOrder = 11; // lineObj.renderOrder = 11;
// lineWaterGroup.add(mesh); // lineWaterGroup.add(lineObj);
// }); // });
// // lines.forEach((line) => {
// // const points = line.map(([lng, lat]) => {
// // const [x, y] = projection([lng, lat]);
// // return new THREE.Vector3(x, -y, this.depth + 0.26);
// // });
// // if (points.length < 2) return;
// // const curve = new THREE.CatmullRomCurve3(points);
// // const tubeGeometry = new THREE.TubeGeometry(curve, 64, 0.05, 8); // 0.05为线粗
// // // const material = new THREE.MeshBasicMaterial({
// // // color: 0x3bb9ff,
// // // transparent: true,
// // // opacity: 0.8,
// // // depthWrite: false,
// // // });
// // const material = new THREE.MeshStandardMaterial({
// // color: 0x153e7e,
// // transparent: true,
// // opacity: 0.5,
// // side: DoubleSide,
// // depthWrite: false,
// // normalMap: normalMap,
// // normalScale: new THREE.Vector2(1, 1), // 可调节凹凸强度
// // // map: waterMap, // 如果有颜色贴图可加上
// // metalness: 0.3,
// // roughness: 0.7,
// // });
// // const mesh = new THREE.Mesh(tubeGeometry, material);
// // mesh.renderOrder = 11;
// // lineWaterGroup.add(mesh);
// // });
// }); // });
// return { // return {
// lineWaterGroup, // lineWaterGroup,
...@@ -1860,6 +1810,7 @@ export class World extends Mini3d { ...@@ -1860,6 +1810,7 @@ export class World extends Mini3d {
// } // }
// createLineWater() { // createLineWater() {
// // 获取水的GeoJSON线数据
// let mapJsonData = this.assets.instance.getResource("linewater"); // let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson; // let lineWaterJson;
// try { // try {
...@@ -1869,21 +1820,21 @@ export class World extends Mini3d { ...@@ -1869,21 +1820,21 @@ export class World extends Mini3d {
// return { lineWaterGroup: null }; // return { lineWaterGroup: null };
// } // }
// // 加载法线贴图
// const textureLoader = new THREE.TextureLoader(); // const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/"; // let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg"); // const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping; // normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png"); // const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png"); // 你需要准备一张水波纹PNG
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping; // waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// // 动画流动
// // 流动速度更快
// this.time.on("tick", () => { // this.time.on("tick", () => {
// normalMap.offset.x += 0.03; // normalMap.offset.x += 0.002;
// normalMap.offset.y += 0.015; // normalMap.offset.y += 0.001;
// waterMap.offset.x += 0.03; // waterMap.offset.x += 0.002; // 让颜色贴图也流动
// waterMap.offset.y += 0.015;
// }); // });
// // 创建线水组
// const lineWaterGroup = new Group(); // const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]); // const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
...@@ -1897,109 +1848,28 @@ export class World extends Mini3d { ...@@ -1897,109 +1848,28 @@ export class World extends Mini3d {
// lines = geometry.coordinates; // lines = geometry.coordinates;
// } // }
// lines.forEach((line) => { // lines.forEach((line) => {
// // 生成带宽度的水带
// const points = line.map(([lng, lat]) => { // const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]); // const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26); // return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表
// }); // });
// if (points.length < 2) return; // if (points.length < 2) return;
// // 用TubeGeometry生成带宽度的水带
// // 宽度渐变:首尾变窄 // const curve = new THREE.CatmullRomCurve3(points);
// const riverWidthMax = 0.08, riverWidthMin = 0.02; // const tubeGeometry = new THREE.TubeGeometry(curve, Math.max(32, points.length * 2), 0.01, 16);
// const lefts = [], rights = []; // const material = new THREE.MeshStandardMaterial({
// for (let i = 0; i < points.length; i++) { // color: 0x4fc3ff,
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let width = riverWidthMin + (1 - Math.abs(t * 2 - 1)) * (riverWidthMax - riverWidthMin);
// let dir;
// if (i === 0) {
// dir = points[1].clone().sub(points[0]);
// } else if (i === points.length - 1) {
// dir = points[i].clone().sub(points[i - 1]);
// } else {
// dir = points[i + 1].clone().sub(points[i - 1]);
// }
// dir.z = 0;
// dir.normalize();
// const normal = new THREE.Vector3(-dir.y, dir.x, 0);
// lefts.push(points[i].clone().add(normal.clone().multiplyScalar(width / 2)));
// rights.push(points[i].clone().add(normal.clone().multiplyScalar(-width / 2)));
// }
// // 顶点、uv、透明度
// const vertices = [];
// const uvs = [];
// const alphas = [];
// let totalLen = 0;
// for (let i = 0; i < points.length; i++) {
// if (i > 0) totalLen += points[i].distanceTo(points[i - 1]);
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let edgeAlpha = 0.7 + 0.3 * (1 - Math.abs(t * 2 - 1));
// // 左点
// vertices.push(lefts[i]);
// uvs.push(totalLen * 2, 0); // UV缩放更密集
// alphas.push(edgeAlpha);
// // 右点
// vertices.push(rights[i]);
// uvs.push(totalLen * 2, 1);
// alphas.push(edgeAlpha);
// }
// const indices = [];
// for (let i = 0; i < points.length - 1; i++) {
// const a = i * 2, b = i * 2 + 1, c = i * 2 + 2, d = i * 2 + 3;
// indices.push(a, b, c, b, d, c);
// }
// const geometry = new THREE.BufferGeometry();
// const posArr = new Float32Array(vertices.length * 3);
// for (let i = 0; i < vertices.length; i++) {
// posArr[i * 3] = vertices[i].x;
// posArr[i * 3 + 1] = vertices[i].y;
// posArr[i * 3 + 2] = vertices[i].z;
// }
// geometry.setAttribute('position', new THREE.BufferAttribute(posArr, 3));
// geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));
// geometry.setAttribute('alpha', new THREE.BufferAttribute(new Float32Array(alphas), 1));
// geometry.setIndex(indices);
// // ShaderMaterial实现边缘羽化和流动水波
// const material = new THREE.ShaderMaterial({
// uniforms: {
// map: { value: waterMap },
// normalMap: { value: normalMap },
// color: { value: new THREE.Color(0x4fc3ff) },
// opacity: { value: 0.5 },
// },
// vertexShader: `
// attribute float alpha;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vUv = uv;
// vAlpha = alpha;
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform sampler2D map;
// uniform sampler2D normalMap;
// uniform vec3 color;
// uniform float opacity;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vec4 texColor = texture2D(map, vUv);
// float alpha = texColor.a * opacity * vAlpha;
// vec3 finalColor = mix(color, texColor.rgb, 0.8); // 贴图主导
// if(alpha < 0.05) discard;
// gl_FragColor = vec4(finalColor, alpha);
// }
// `,
// transparent: true, // transparent: true,
// opacity: 0.35,
// side: DoubleSide, // side: DoubleSide,
// depthWrite: false, // depthWrite: false,
// normalMap: normalMap,
// normalScale: new THREE.Vector2(2, 2),
// map: waterMap, // 使用颜色贴图
// metalness: 0.3,
// roughness: 0.7,
// }); // });
// const mesh = new Mesh(tubeGeometry, material);
// const mesh = new Mesh(geometry, material);
// mesh.renderOrder = 11; // mesh.renderOrder = 11;
// lineWaterGroup.add(mesh); // lineWaterGroup.add(mesh);
// }); // });
...@@ -2008,6 +1878,181 @@ export class World extends Mini3d { ...@@ -2008,6 +1878,181 @@ export class World extends Mini3d {
// lineWaterGroup, // lineWaterGroup,
// }; // };
// } // }
createLineWater() {
let mapJsonData = this.assets.instance.getResource("linewater");
let lineWaterJson;
try {
lineWaterJson =
typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
} catch (e) {
console.error("linewater 解析失败", e);
return { lineWaterGroup: null };
}
const textureLoader = new THREE.TextureLoader();
let base_url = import.meta.env.BASE_URL || "/";
const normalMap = textureLoader.load(
base_url + "assets/json/waternormals.jpg"
);
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
const waterMap = textureLoader.load(
base_url + "assets/json/watercolor.png"
);
waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// 流动速度更快
this.time.on("tick", () => {
normalMap.offset.x += 0.03;
normalMap.offset.y += 0.015;
waterMap.offset.x += 0.03;
waterMap.offset.y += 0.015;
});
const lineWaterGroup = new Group();
const projection = geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0]);
(lineWaterJson.features || []).forEach((feature) => {
const geometry = feature.geometry;
if (!geometry) return;
let lines = [];
if (geometry.type === "LineString") {
lines = [geometry.coordinates];
} else if (geometry.type === "MultiLineString") {
lines = geometry.coordinates;
}
lines.forEach((line) => {
const points = line.map(([lng, lat]) => {
const [x, y] = projection([lng, lat]);
return new THREE.Vector3(x, -y, this.depth + 0.26);
});
if (points.length < 2) return;
// 宽度渐变:首尾变窄
const riverWidthMax = 0.08,
riverWidthMin = 0.02;
const lefts = [],
rights = [];
for (let i = 0; i < points.length; i++) {
let t = points.length === 1 ? 0 : i / (points.length - 1);
let width =
riverWidthMin +
(1 - Math.abs(t * 2 - 1)) * (riverWidthMax - riverWidthMin);
let dir;
if (i === 0) {
dir = points[1].clone().sub(points[0]);
} else if (i === points.length - 1) {
dir = points[i].clone().sub(points[i - 1]);
} else {
dir = points[i + 1].clone().sub(points[i - 1]);
}
dir.z = 0;
dir.normalize();
const normal = new THREE.Vector3(-dir.y, dir.x, 0);
lefts.push(
points[i].clone().add(normal.clone().multiplyScalar(width / 2))
);
rights.push(
points[i].clone().add(normal.clone().multiplyScalar(-width / 2))
);
}
// 顶点、uv、透明度
const vertices = [];
const uvs = [];
const alphas = [];
let totalLen = 0;
for (let i = 0; i < points.length; i++) {
if (i > 0) totalLen += points[i].distanceTo(points[i - 1]);
let t = points.length === 1 ? 0 : i / (points.length - 1);
let edgeAlpha = 0.7 + 0.3 * (1 - Math.abs(t * 2 - 1));
// 左点
vertices.push(lefts[i]);
uvs.push(totalLen * 2, 0); // UV缩放更密集
alphas.push(edgeAlpha);
// 右点
vertices.push(rights[i]);
uvs.push(totalLen * 2, 1);
alphas.push(edgeAlpha);
}
const indices = [];
for (let i = 0; i < points.length - 1; i++) {
const a = i * 2,
b = i * 2 + 1,
c = i * 2 + 2,
d = i * 2 + 3;
indices.push(a, b, c, b, d, c);
}
const geometry = new THREE.BufferGeometry();
const posArr = new Float32Array(vertices.length * 3);
for (let i = 0; i < vertices.length; i++) {
posArr[i * 3] = vertices[i].x;
posArr[i * 3 + 1] = vertices[i].y;
posArr[i * 3 + 2] = vertices[i].z;
}
geometry.setAttribute("position", new THREE.BufferAttribute(posArr, 3));
geometry.setAttribute(
"uv",
new THREE.BufferAttribute(new Float32Array(uvs), 2)
);
geometry.setAttribute(
"alpha",
new THREE.BufferAttribute(new Float32Array(alphas), 1)
);
geometry.setIndex(indices);
// ShaderMaterial实现边缘羽化和流动水波
const material = new THREE.ShaderMaterial({
uniforms: {
map: { value: waterMap },
normalMap: { value: normalMap },
color: { value: new THREE.Color(0x4fc3ff) },
opacity: { value: 0.5 },
},
vertexShader: `
attribute float alpha;
varying vec2 vUv;
varying float vAlpha;
void main() {
vUv = uv;
vAlpha = alpha;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D map;
uniform sampler2D normalMap;
uniform vec3 color;
uniform float opacity;
varying vec2 vUv;
varying float vAlpha;
void main() {
vec4 texColor = texture2D(map, vUv);
float alpha = texColor.a * opacity * vAlpha;
vec3 finalColor = mix(color, texColor.rgb, 0.8); // 贴图主导
if(alpha < 0.05) discard;
gl_FragColor = vec4(finalColor, alpha);
}
`,
transparent: true,
side: DoubleSide,
depthWrite: false,
});
const mesh = new Mesh(geometry, material);
mesh.renderOrder = 11;
lineWaterGroup.add(mesh);
});
});
return {
lineWaterGroup,
};
}
// 加载3d模型 // 加载3d模型
showDroneAtLngLat(url, lng, lat, height, scale) { showDroneAtLngLat(url, lng, lat, height, scale) {
// 经纬度转平面坐标 // 经纬度转平面坐标
...@@ -2036,8 +2081,6 @@ export class World extends Mini3d { ...@@ -2036,8 +2081,6 @@ export class World extends Mini3d {
drone.position.copy(position); drone.position.copy(position);
drone.scale.set(scale, scale, scale); drone.scale.set(scale, scale, scale);
// 可根据需要调整旋转 // 可根据需要调整旋转
// drone.rotation.set(0, Math.PI, 0);
// let propeller1 = drone.getObjectByName("phase8_Master25");
let propeller1 = drone.getObjectByName("prop_1_jnt34"); let propeller1 = drone.getObjectByName("prop_1_jnt34");
let propeller2 = drone.getObjectByName("prop_2_jnt35"); let propeller2 = drone.getObjectByName("prop_2_jnt35");
let propeller3 = drone.getObjectByName("prop_3_jnt36"); let propeller3 = drone.getObjectByName("prop_3_jnt36");
...@@ -2060,6 +2103,15 @@ export class World extends Mini3d { ...@@ -2060,6 +2103,15 @@ export class World extends Mini3d {
drone.addEventListener("mousedown", (event) => { drone.addEventListener("mousedown", (event) => {
this.showDronePopup(drone); this.showDronePopup(drone);
}); });
this.drone = drone; // 保存无人机实例
this.time.on("tick", () => {
if (!drone) return;
const speed = 0.1; // 控制移动速度
if (this.droneMoveState.w) this.drone.position.z -= speed;
if (this.droneMoveState.s) this.drone.position.z += speed;
if (this.droneMoveState.a) this.drone.position.x -= speed;
if (this.droneMoveState.d) this.drone.position.x += speed;
});
this.moveDroneAlongPath( this.moveDroneAlongPath(
drone, drone,
[ [
...@@ -2149,6 +2201,11 @@ export class World extends Mini3d { ...@@ -2149,6 +2201,11 @@ export class World extends Mini3d {
<video src="https://media.w3.org/2010/05/sintel/trailer.mp4" controls poster="" preload="metadata" custom-cache="false" ></video> <video src="https://media.w3.org/2010/05/sintel/trailer.mp4" controls poster="" preload="metadata" custom-cache="false" ></video>
</div> </div>
`; `;
let lnglatPossition = this.worldToLngLat(
drone.position.x,
drone.position.z
);
console.log("无人机经纬度位置:", lnglatPossition);
document.body.appendChild(popup); document.body.appendChild(popup);
this.dronePopup = popup; this.dronePopup = popup;
// 优化全屏性能卡顿 // 优化全屏性能卡顿
...@@ -2269,6 +2326,98 @@ export class World extends Mini3d { ...@@ -2269,6 +2326,98 @@ export class World extends Mini3d {
if (drone._moveReq) cancelAnimationFrame(drone._moveReq); if (drone._moveReq) cancelAnimationFrame(drone._moveReq);
drone._moveReq = requestAnimationFrame(animate); drone._moveReq = requestAnimationFrame(animate);
} }
onKeyDown(e) {
if (!this.drone) return;
if (e.key === "w") this.droneMoveState.w = true;
if (e.key === "a") this.droneMoveState.a = true;
if (e.key === "s") this.droneMoveState.s = true;
if (e.key === "d") this.droneMoveState.d = true;
}
onKeyUp(e) {
if (!this.drone) return;
if (e.key === "w") this.droneMoveState.w = false;
if (e.key === "a") this.droneMoveState.a = false;
if (e.key === "s") this.droneMoveState.s = false;
if (e.key === "d") this.droneMoveState.d = false;
}
worldToLngLat(x, y, z = 0) {
const projection = geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0]);
// 反向投影
return projection.invert([x, -y]);
}
/**
* 在指定经纬度数组生成着火点和烟雾效果
* @param {Array} lngLatArr [[lng,lat], ...]
*/
createFireWithSmoke(lngLatArr) {
const fireGroup = new THREE.Group();
this.scene.add(fireGroup);
// 加载火焰和烟雾贴图
// 建议准备 fire.png 贴图
// const fireTexture = this.assets.instance.getResource("fire");
const smokeTexture = this.assets.instance.getResource("smoke");
// 存储所有烟雾sprite
const smokeSprites = [];
lngLatArr.forEach(([lng, lat]) => {
const [x, y] = this.geoProjection([lng, lat]);
const z = this.depth;
// 火焰Sprite(如有火焰贴图可解开注释)
// if (fireTexture) {
// const fireMaterial = new THREE.SpriteMaterial({
// map: fireTexture,
// color: 0xff6600,
// transparent: true,
// opacity: 0.85,
// blending: THREE.AdditiveBlending,
// depthWrite: false,
// });
// const fireSprite = new THREE.Sprite(fireMaterial);
// fireSprite.position.set(x, -y, z);
// fireSprite.scale.set(1, 1.5, 1); // 可调大
// fireGroup.add(fireSprite);
// }
// 烟雾Sprite
const smokeMaterial = new THREE.SpriteMaterial({
map: smokeTexture,
color: 0xffffff,
transparent: true,
opacity: 1,
blending: THREE.NormalBlending,
depthWrite: false,
depthTest: false,
});
const smokeSprite = new THREE.Sprite(smokeMaterial);
smokeSprite.position.set(x, z, -y); // y轴为“上”
smokeSprite.scale.set(0.5, 1, 0.5);
smokeSprite.renderOrder = 99;
fireGroup.add(smokeSprite);
smokeSprites.push({ sprite: smokeSprite, baseY: z + 1 });
});
// 只注册一次动画
this.time.on("tick", () => {
const t = Date.now() * 0.001;
smokeSprites.forEach(({ sprite, baseY }, i) => {
sprite.position.y += 0.01;
if (sprite.position.y > baseY + 1) {
sprite.position.y = baseY;
}
sprite.material.opacity = 0.4 + 0.3 * Math.abs(Math.sin(t + i));
sprite.rotation.z += 0.002;
});
});
}
// 跳转到指定group // 跳转到指定group
zoomToFocusMapGroup(group) { zoomToFocusMapGroup(group) {
// 创建一个 Box3 来计算 focusMapGroup 的边界盒 // 创建一个 Box3 来计算 focusMapGroup 的边界盒
...@@ -2308,6 +2457,7 @@ export class World extends Mini3d { ...@@ -2308,6 +2457,7 @@ export class World extends Mini3d {
} }
update() { update() {
super.update(); super.update();
this.controls && this.controls.update(); // 每帧更新 controls
this.interactionManager && this.interactionManager.update(); this.interactionManager && this.interactionManager.update();
} }
destroy() { destroy() {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论