import * as mars3d from "mars3d" export let map // mars3d.Map三维地图对象 // 需要覆盖config.json中地图属性参数(当前示例框架中自动处理合并) export const mapOptions = { scene: { center: { lat: 31.834535, lng: 117.21992, alt: 80, heading: 38, pitch: -34 }, fxaa: true } } /** * 初始化地图业务,生命周期钩子函数(必须) * 框架在地图初始化完成后自动调用该函数 * @param {mars3d.Map} mapInstance 地图对象 * @returns {void} 无 */ export function onMounted(mapInstance) { map = mapInstance // 记录map globalNotify("操作提示", `Q 逆时针摆动、 A 顺时针摆动`) creatDemo() } /** * 释放当前地图业务的生命周期函数 * @returns {void} 无 */ export function onUnmounted() { map = null } function creatDemo() { const MeshVisualizer = Cesium.MeshVisualizer const Mesh = Cesium.Mesh const MeshMaterial = Cesium.MeshMaterial const GeometryUtils = Cesium.GeometryUtils const PlaneBufferGeometry = Cesium.PlaneBufferGeometry const MeshPhongMaterial = Cesium.MeshPhongMaterial const center = Cesium.Cartesian3.fromDegrees(117.220206, 31.834866, 50) const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center) const meshVisualizer = new 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 // 显示坐标轴 Ammo().then(function () { // Physics variables const gravityConstant = -9.8 let collisionConfiguration let dispatcher let broadphase let solver let physicsWorld const rigidBodies = [] const margin = 0.05 let hinge let cloth const transformAux1 = new Ammo.btTransform() let armMovement = 0 let softBodySolver function initPhysics() { // Physics configuration collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration() dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration) broadphase = new Ammo.btDbvtBroadphase() solver = new Ammo.btSequentialImpulseConstraintSolver() softBodySolver = new Ammo.btDefaultSoftBodySolver() physicsWorld = new Ammo.btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration, softBodySolver) physicsWorld.setGravity(new Ammo.btVector3(0, gravityConstant, 0)) physicsWorld.getWorldInfo().set_m_gravity(new Ammo.btVector3(0, gravityConstant, 0)) } function createRandomColor() { return Cesium.Color.fromRandom({ alpha: 1 }) // fromRgba(Math.floor(Math.random() * (1 << 24))); } function createMaterial() { return new MeshPhongMaterial({ defaultColor: createRandomColor(), side: MeshMaterial.Sides.DOUBLE, translucent: false }) } function createObjects() { const pos = new Cesium.Cartesian3() const quat = new Cesium.Quaternion() // Ground pos.x = 0 pos.y = -0.5 pos.z = 0 quat.x = 0 quat.y = 0 quat.z = 0 quat.w = 1 const ground = createParalellepiped( 40, 1, 40, 0, pos, quat, new MeshPhongMaterial({ defaultColor: "rgb(125,125,125)", side: MeshMaterial.Sides.DOUBLE, translucent: false }) ) // Wall const brickMass = 0.5 const brickLength = 1.2 const brickDepth = 0.6 const brickHeight = brickLength * 0.5 const numBricksLength = 6 const numBricksHeight = 8 const z0 = -numBricksLength * brickLength * 0.5 pos.x = 0 pos.y = brickHeight * 0.5 pos.z = z0 quat.x = 0 quat.y = 0 quat.z = 0 quat.w = 1 for (let j = 0; j < numBricksHeight; j++) { const oddRow = j % 2 === 1 pos.z = z0 if (oddRow) { pos.z -= 0.25 * brickLength } const nRow = oddRow ? numBricksLength + 1 : numBricksLength for (let i = 0; i < nRow; i++) { let brickLengthCurrent = brickLength let brickMassCurrent = brickMass if (oddRow && (i === 0 || i === nRow - 1)) { brickLengthCurrent *= 0.5 brickMassCurrent *= 0.5 } const brick = createParalellepiped(brickDepth, brickHeight, brickLengthCurrent, brickMassCurrent, pos, quat, createMaterial()) if (oddRow && (i === 0 || i === nRow - 2)) { pos.z += 0.75 * brickLength } else { pos.z += brickLength } } pos.y += brickHeight } // The cloth // Cloth graphic object const clothWidth = 4 const clothHeight = 3 const clothNumSegmentsZ = clothWidth * 5 const clothNumSegmentsY = clothHeight * 5 const clothSegmentLengthZ = clothWidth / clothNumSegmentsZ const clothSegmentLengthY = clothHeight / clothNumSegmentsY const clothPos = new Cesium.Cartesian3(-3, 3, 2) const clothGeometry = new PlaneBufferGeometry(clothWidth, clothHeight, clothNumSegmentsZ, clothNumSegmentsY) const clothMaterial = new MeshPhongMaterial({ defaultColor: "rgb(255,255,255)", side: MeshMaterial.Sides.DOUBLE, translucent: false }) cloth = new Mesh(clothGeometry, clothMaterial) GeometryUtils.rotateY(cloth.geometry, Math.PI * 0.5) GeometryUtils.translate(cloth.geometry, clothPos.x, clothPos.y + clothHeight * 0.5, clothPos.z - clothWidth * 0.5) GeometryUtils.computeVertexNormals(cloth.geometry) meshVisualizer.add(cloth) // Cloth physic object const softBodyHelpers = new Ammo.btSoftBodyHelpers() const clothCorner00 = new Ammo.btVector3(clothPos.x, clothPos.y + clothHeight, clothPos.z) const clothCorner01 = new Ammo.btVector3(clothPos.x, clothPos.y + clothHeight, clothPos.z - clothWidth) const clothCorner10 = new Ammo.btVector3(clothPos.x, clothPos.y, clothPos.z) const clothCorner11 = new Ammo.btVector3(clothPos.x, clothPos.y, clothPos.z - clothWidth) const clothSoftBody = softBodyHelpers.CreatePatch( physicsWorld.getWorldInfo(), clothCorner00, clothCorner01, clothCorner10, clothCorner11, clothNumSegmentsZ + 1, clothNumSegmentsY + 1, 0, true ) const sbConfig = clothSoftBody.get_m_cfg() sbConfig.set_viterations(10) sbConfig.set_piterations(10) clothSoftBody.setTotalMass(0.9, false) Ammo.castObject(clothSoftBody, Ammo.btCollisionObject) .getCollisionShape() .setMargin(margin * 3) physicsWorld.addSoftBody(clothSoftBody, 1, -1) cloth.physicsBody = clothSoftBody // Disable deactivation clothSoftBody.setActivationState(4) // The base const armMass = 2 const armLength = 3 + clothWidth const pylonHeight = clothPos.y + clothHeight const baseMaterial = new MeshPhongMaterial({ defaultColor: "rgb(255,255,0)", side: MeshMaterial.Sides.DOUBLE, translucent: false }) pos.x = clothPos.x pos.y = 0.1 pos.z = clothPos.z - armLength quat.x = 0 quat.y = 0 quat.z = 0 quat.w = 1 const base = createParalellepiped(1, 0.2, 1, 0, pos, quat, baseMaterial) pos.x = clothPos.x pos.y = 0.5 * pylonHeight pos.z = clothPos.z - armLength const pylon = createParalellepiped(0.4, pylonHeight, 0.4, 0, pos, quat, baseMaterial) pos.x = clothPos.x pos.y = pylonHeight + 0.2 pos.z = clothPos.z - 0.5 * armLength const arm = createParalellepiped(0.4, 0.4, armLength + 0.4, armMass, pos, quat, baseMaterial) // Glue the cloth to the arm const influence = 0.5 clothSoftBody.appendAnchor(0, arm.physicsBody, false, influence) clothSoftBody.appendAnchor(clothNumSegmentsZ, arm.physicsBody, false, influence) // Hinge constraint to move the arm const pivotA = new Ammo.btVector3(0, pylonHeight * 0.5, 0) const pivotB = new Ammo.btVector3(0, -0.2, -armLength * 0.5) const axis = new Ammo.btVector3(0, 1, 0) hinge = new Ammo.btHingeConstraint(pylon.physicsBody, arm.physicsBody, pivotA, pivotB, axis, axis, true) physicsWorld.addConstraint(hinge, true) } function createParalellepiped(sx, sy, sz, mass, pos, quat, material) { const threeObject = new Mesh( Cesium.BoxGeometry.fromDimensions({ dimensions: new Cesium.Cartesian3(sx, sy, sz), vertexFormat: new Cesium.VertexFormat({ position: true, st: true, normal: true }) }), material ) threeObject.quaternion = new Cesium.Quaternion() threeObject.geometry.attributes.uv = threeObject.geometry.attributes.st threeObject.geometry.attributes.st = undefined const shape = new Ammo.btBoxShape(new Ammo.btVector3(sx * 0.5, sy * 0.5, sz * 0.5)) shape.setMargin(margin) createRigidBody(threeObject, shape, mass, pos, quat) return threeObject } function createRigidBody(threeObject, physicsShape, mass, pos, quat) { Cesium.Cartesian3.clone(pos, threeObject.position) Cesium.Quaternion.clone(quat, threeObject.quaternion) 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) physicsShape.calculateLocalInertia(mass, localInertia) const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, physicsShape, localInertia) const body = new Ammo.btRigidBody(rbInfo) threeObject.physicsBody = body meshVisualizer.add(threeObject) if (mass > 0) { rigidBodies.push(threeObject) // Disable deactivation body.setActivationState(4) } physicsWorld.addRigidBody(body) } // deltaTime单位是:秒/s function updatePhysics(deltaTime) { // Hinge control hinge.enableAngularMotor(true, 0.8 * armMovement, 50) // Step world physicsWorld.stepSimulation(deltaTime, 10) // Update cloth const softBody = cloth.physicsBody const clothPositions = cloth.geometry.attributes.position.values const numVerts = clothPositions.length / 3 const nodes = softBody.get_m_nodes() let indexFloat = 0 for (let i = 0; i < numVerts; i++) { const node = nodes.at(i) const nodePos = node.get_m_x() clothPositions[indexFloat++] = nodePos.x() clothPositions[indexFloat++] = nodePos.y() clothPositions[indexFloat++] = nodePos.z() } cloth.geometry.attributes.position.needsUpdate = true if (cloth.geometry.primitiveType === Cesium.PrimitiveType.TRIANGLES) { // Cesium.GeometryPipeline.computeNormal(cloth.geometry); GeometryUtils.computeVertexNormals(cloth.geometry) } // Update rigid bodies for (let i = 0, il = rigidBodies.length; i < il; i++) { const objGraph = rigidBodies[i] const objPhys = objGraph.physicsBody const ms = objPhys.getMotionState() if (ms) { ms.getWorldTransform(transformAux1) const p = transformAux1.getOrigin() const q = transformAux1.getRotation() objGraph.position.x = p.x() objGraph.position.y = p.y() objGraph.position.z = p.z() objGraph.quaternion.x = q.x() objGraph.quaternion.y = q.y() objGraph.quaternion.z = q.z() objGraph.quaternion.w = q.w() // objGraph.needsUpdate = true; objGraph.modelMatrixNeedsUpdate = true } } } let start = false function initInput() { window.addEventListener( "keydown", function (event) { if (!start) { return } switch (event.keyCode) { // Q case 81: armMovement = 1 break // A case 65: armMovement = -1 break } }, false ) window.addEventListener( "keyup", function (event) { armMovement = 0 }, false ) } let startTime = new Date() function update(frameState) { const deltaTime = (new Date() - startTime) / 1000.0 updatePhysics(deltaTime) startTime = new Date() } let init = false setTimeout(function () { if (!init) { initPhysics() createObjects() initInput() init = true } if (!start) { meshVisualizer.beforeUpdate.addEventListener(update) start = true } else { meshVisualizer.beforeUpdate.removeEventListener(update) start = false } }, 1000 * 3) }) // }); }