import * as mars3d from "mars3d" export let map // mars3d.Map三维地图对象 // 需要覆盖config.json中地图属性参数(当前示例框架中自动处理合并) export const mapOptions = { scene: { center: { lat: 31.835256, lng: 117.219292, alt: 128, heading: 120, pitch: -41 }, fxaa: true } } /** * 初始化地图业务,生命周期钩子函数(必须) * 框架在地图初始化完成后自动调用该函数 * @param {mars3d.Map} mapInstance 地图对象 * @returns {void} 无 */ export function onMounted(mapInstance) { map = mapInstance // 记录map globalNotify("操作提示", `W 前进、S 后退、 A 左转弯、D 右转弯`) creatDemo() } /** * 释放当前地图业务的生命周期函数 * @returns {void} 无 */ export function onUnmounted() { map = null } function creatDemo() { const center = Cesium.Cartesian3.fromDegrees(117.220206, 31.834866, 50) const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center) const meshVisualizer = new Cesium.MeshVisualizer({ modelMatrix: modelMatrix, up: { y: 1 }, referenceAxisParameter: { length: 100, width: 0.05, headLength: 2, headWidth: 0.1 } }) map.scene.primitives.add(meshVisualizer) meshVisualizer.showReference = true // 显示坐标轴 Cesium.Cartesian3.prototype.set = function (x, y, z) { this.x = x this.y = y this.z = z } Cesium.Quaternion.prototype.set = function (x, y, z, w) { this.x = x this.y = y this.z = z this.w = w } Ammo().then(function () { // - Global variables - const DISABLE_DEACTIVATION = 4 const TRANSFORM_AUX = new Ammo.btTransform() const ZERO_QUATERNION = new Cesium.Quaternion(0, 0, 0, 1) // Graphics variables let materialDynamic, materialStatic, materialInteractive // Physics variables let collisionConfiguration let dispatcher let broadphase let solver let physicsWorld const syncList = [] let time = 0 const objectTimePeriod = 3 const timeNextSpawn = time + objectTimePeriod const maxNumObjects = 30 // Keybord actions const actions = {} const keysActions = { KeyW: "acceleration", KeyS: "braking", KeyA: "left", KeyD: "right" } // - Functions - function initGraphics() { materialDynamic = createMaterial() materialStatic = createMaterial() materialInteractive = createMaterial() window.addEventListener("keydown", keydown) window.addEventListener("keyup", keyup) } function initPhysics() { // Physics configuration collisionConfiguration = new Ammo.btDefaultCollisionConfiguration() dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration) broadphase = new Ammo.btDbvtBroadphase() solver = new Ammo.btSequentialImpulseConstraintSolver() physicsWorld = new Ammo.btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration) physicsWorld.setGravity(new Ammo.btVector3(0, -9.82, 0)) } function updatePhysics(deltTime) { for (let i = 0; i < syncList.length; i++) { syncList[i](deltTime) } physicsWorld.stepSimulation(deltTime, 10) time += deltTime } function keyup(e) { if (keysActions[e.code]) { actions[keysActions[e.code]] = false e.preventDefault() e.stopPropagation() return false } } function keydown(e) { if (keysActions[e.code]) { actions[keysActions[e.code]] = true e.preventDefault() e.stopPropagation() return false } } function createBox(pos, quat, w, l, h, mass, friction) { const material = createMaterial() //= mass > 0 ? materialDynamic : materialStatic; const shape = Cesium.BoxGeometry.fromDimensions({ dimensions: new Cesium.Cartesian3(w, l, h), vertexFormat: new Cesium.VertexFormat({ position: true, normal: true }) }) const geometry = new Ammo.btBoxShape(new Ammo.btVector3(w * 0.5, l * 0.5, h * 0.5)) if (!mass) { mass = 0 } if (!friction) { friction = 1 } const mesh = new Cesium.Mesh(shape, material) Cesium.Cartesian3.clone(pos, mesh.position) mesh.quaternion = new Cesium.Quaternion(quat.x, quat.y, quat.z, quat.w) meshVisualizer.add(mesh) const transform = new Ammo.btTransform() transform.setIdentity() transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z)) transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w)) const motionState = new Ammo.btDefaultMotionState(transform) const localInertia = new Ammo.btVector3(0, 0, 0) geometry.calculateLocalInertia(mass, localInertia) const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, geometry, localInertia) const body = new Ammo.btRigidBody(rbInfo) body.setFriction(friction) // body.setRestitution(.9); // body.setDamping(0.2, 0.2); physicsWorld.addRigidBody(body) if (mass > 0) { body.setActivationState(DISABLE_DEACTIVATION) // Sync physics and graphics // eslint-disable-next-line no-inner-declarations function sync(dt) { const ms = body.getMotionState() if (ms) { ms.getWorldTransform(TRANSFORM_AUX) const p = TRANSFORM_AUX.getOrigin() const q = TRANSFORM_AUX.getRotation() mesh.position.set(p.x(), p.y(), p.z()) mesh.quaternion.set(q.x(), q.y(), q.z(), q.w()) mesh.modelMatrixNeedsUpdate = true } } syncList.push(sync) } } function createWheelMesh(radius, width) { const t = new Cesium.CylinderGeometry({ length: width, topRadius: radius, bottomRadius: radius, slices: 24 }) // let t = new THREE.CylinderGeometry(radius, radius, width, 24, 1); const mesh = new Cesium.Mesh(t, materialInteractive) Cesium.GeometryUtils.rotateY(mesh.geometry, Math.PI / 2) mesh.quaternion = new Cesium.Quaternion() // Cesium.Quaternion.fromAxisAngle(new Cesium.Cartesian3(0, 0, 1), Math.PI / 2); const shape = Cesium.BoxGeometry.fromDimensions({ dimensions: new Cesium.Cartesian3(width * 1.5, radius * 1.75, radius * 0.25), vertexFormat: new Cesium.VertexFormat({ position: true, normal: true }) }) const meshShape = new Cesium.Mesh(shape, materialInteractive) meshShape.quaternion = new Cesium.Quaternion() // .fromAxisAngle(new Cesium.Cartesian3(0, 0, 1), 0); mesh.add(meshShape) meshVisualizer.add(mesh) return mesh } function createChassisMesh(w, l, h) { const shape = Cesium.BoxGeometry.fromDimensions({ dimensions: new Cesium.Cartesian3(w, l, h), vertexFormat: new Cesium.VertexFormat({ position: true, normal: true }) }) const mesh = new Cesium.Mesh(shape, materialInteractive) mesh.quaternion = new Cesium.Quaternion(0, 0, 0, 1) meshVisualizer.add(mesh) return mesh } function createVehicle(pos, quat) { // Vehicle contants const chassisWidth = 1.8 const chassisHeight = 0.6 const chassisLength = 4 const massVehicle = 800 const wheelAxisPositionBack = -1 const wheelRadiusBack = 0.4 const wheelWidthBack = 0.3 const wheelHalfTrackBack = 1 const wheelAxisHeightBack = 0.3 const wheelAxisFrontPosition = 1.7 const wheelHalfTrackFront = 1 const wheelAxisHeightFront = 0.3 const wheelRadiusFront = 0.35 const wheelWidthFront = 0.2 const friction = 1000 const suspensionStiffness = 20.0 const suspensionDamping = 2.3 const suspensionCompression = 4.4 const suspensionRestLength = 0.6 const rollInfluence = 0.2 const steeringIncrement = 0.04 const steeringClamp = 0.5 const maxEngineForce = 2000 const maxBreakingForce = 100 // Chassis const geometry = new Ammo.btBoxShape(new Ammo.btVector3(chassisWidth * 0.5, chassisHeight * 0.5, chassisLength * 0.5)) const transform = new Ammo.btTransform() transform.setIdentity() transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z)) transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w)) const motionState = new Ammo.btDefaultMotionState(transform) const localInertia = new Ammo.btVector3(0, 0, 0) geometry.calculateLocalInertia(massVehicle, localInertia) const body = new Ammo.btRigidBody(new Ammo.btRigidBodyConstructionInfo(massVehicle, motionState, geometry, localInertia)) body.setActivationState(DISABLE_DEACTIVATION) physicsWorld.addRigidBody(body) const chassisMesh = createChassisMesh(chassisWidth, chassisHeight, chassisLength) // Raycast Vehicle let engineForce = 0 let vehicleSteering = 0 let breakingForce = 0 const tuning = new Ammo.btVehicleTuning() const rayCaster = new Ammo.btDefaultVehicleRaycaster(physicsWorld) const vehicle = new Ammo.btRaycastVehicle(tuning, body, rayCaster) vehicle.setCoordinateSystem(0, 1, 2) physicsWorld.addAction(vehicle) // Wheels const FRONT_LEFT = 0 const FRONT_RIGHT = 1 const BACK_LEFT = 2 const BACK_RIGHT = 3 const wheelMeshes = [] const wheelDirectionCS0 = new Ammo.btVector3(0, -1, 0) const wheelAxleCS = new Ammo.btVector3(-1, 0, 0) function addWheel(isFront, pos, radius, width, index) { const wheelInfo = vehicle.addWheel(pos, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, radius, tuning, isFront) wheelInfo.set_m_suspensionStiffness(suspensionStiffness) wheelInfo.set_m_wheelsDampingRelaxation(suspensionDamping) wheelInfo.set_m_wheelsDampingCompression(suspensionCompression) wheelInfo.set_m_frictionSlip(friction) wheelInfo.set_m_rollInfluence(rollInfluence) wheelMeshes[index] = createWheelMesh(radius, width) } addWheel( true, new Ammo.btVector3(wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_LEFT ) addWheel( true, new Ammo.btVector3(-wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_RIGHT ) addWheel(false, new Ammo.btVector3(-wheelHalfTrackBack, wheelAxisHeightBack, wheelAxisPositionBack), wheelRadiusBack, wheelWidthBack, BACK_LEFT) addWheel(false, new Ammo.btVector3(wheelHalfTrackBack, wheelAxisHeightBack, wheelAxisPositionBack), wheelRadiusBack, wheelWidthBack, BACK_RIGHT) // Sync keybord actions and physics and graphics function sync(dt) { const speed = vehicle.getCurrentSpeedKmHour() breakingForce = 0 engineForce = 0 if (actions.acceleration) { if (speed < -1) { breakingForce = maxBreakingForce } else { engineForce = maxEngineForce } } if (actions.braking) { if (speed > 1) { breakingForce = maxBreakingForce } else { engineForce = -maxEngineForce / 2 } } if (actions.left) { if (vehicleSteering < steeringClamp) { vehicleSteering += steeringIncrement } } else { if (actions.right) { if (vehicleSteering > -steeringClamp) { vehicleSteering -= steeringIncrement } } else { if (vehicleSteering < -steeringIncrement) { vehicleSteering += steeringIncrement } else { if (vehicleSteering > steeringIncrement) { vehicleSteering -= steeringIncrement } else { vehicleSteering = 0 } } } } vehicle.applyEngineForce(engineForce, BACK_LEFT) vehicle.applyEngineForce(engineForce, BACK_RIGHT) vehicle.setBrake(breakingForce / 2, FRONT_LEFT) vehicle.setBrake(breakingForce / 2, FRONT_RIGHT) vehicle.setBrake(breakingForce, BACK_LEFT) vehicle.setBrake(breakingForce, BACK_RIGHT) vehicle.setSteeringValue(vehicleSteering, FRONT_LEFT) vehicle.setSteeringValue(vehicleSteering, FRONT_RIGHT) let tm, p, q, i const n = vehicle.getNumWheels() for (i = 0; i < n; i++) { vehicle.updateWheelTransform(i, true) tm = vehicle.getWheelTransformWS(i) p = tm.getOrigin() q = tm.getRotation() wheelMeshes[i].position.set(p.x(), p.y(), p.z()) wheelMeshes[i].quaternion.set(q.x(), q.y(), q.z(), q.w()) wheelMeshes[i].modelMatrixNeedsUpdate = true } tm = vehicle.getChassisWorldTransform() p = tm.getOrigin() q = tm.getRotation() chassisMesh.position.set(p.x(), p.y(), p.z()) chassisMesh.quaternion.set(q.x(), q.y(), q.z(), q.w()) chassisMesh.modelMatrixNeedsUpdate = true } syncList.push(sync) } function createObjects() { createBox(new Cesium.Cartesian3(0, -0.5, 0), ZERO_QUATERNION, 75, 1, 75, 0, 2) const quaternion = new Cesium.Quaternion(0, 0, 0, 1) Cesium.Quaternion.fromAxisAngle(new Cesium.Cartesian3(1, 0, 0), -Math.PI / 18, quaternion) createBox(new Cesium.Cartesian3(0, -1.5, 0), quaternion, 8, 4, 10, 0) const size = 0.75 const nw = 8 const nh = 6 for (let j = 0; j < nw; j++) { for (let i = 0; i < nh; i++) { createBox(new Cesium.Cartesian3(size * j - (size * (nw - 1)) / 2, size * i, 10), ZERO_QUATERNION, size, size, size, 10) } } createVehicle(new Cesium.Cartesian3(0, 4, -20), ZERO_QUATERNION) } let start = false let init = false let startTime = new Date() function update(frameState) { const deltaTime = (new Date() - startTime) / 1000.0 updatePhysics(deltaTime) startTime = new Date() } setTimeout(function () { if (!init) { // - Init - initGraphics() initPhysics() createObjects() init = true } if (!start) { meshVisualizer.beforeUpdate.addEventListener(update) start = true } else { meshVisualizer.beforeUpdate.removeEventListener(update) start = false } }, 1000 * 3) }) } function createRandomColor() { return Cesium.Color.fromRandom({ alpha: 1 }) // fromRgba(Math.floor(Math.random() * (1 << 24))); } function createMaterial() { return new Cesium.MeshPhongMaterial({ defaultColor: createRandomColor(), side: Cesium.MeshMaterial.Sides.DOUBLE, translucent: false }) }