Cesium-Examples/examples/cesiumEx/6.1.4、撞击(软体).html
2025-06-12 14:10:21 +08:00

508 lines
19 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--********************************************************************
* by jiawanlong
*********************************************************************-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="./../../libs/cesium/Cesium1.72/Widgets/widgets.css" />
<script type="text/javascript" src="./../../libs/cesium/Cesium1.72/Cesium.js"></script>
<script src="./ammolibs/ammo/ammo.js"></script>
</head>
<body style="
margin: 0;
overflow: hidden;
background: #fff;
width: 100%;
height: 100%;
position: absolute;
top: 0;
">
<div id="cesiumContainer" style="margin: 0 auto; width: 100%; height: 100%"></div>
<div class="infoview">
操作提示:鼠标左键单击进行发射
</div>
<script src="./ammolibs/three/three.min.js"></script>
<script src="./ammolibs/ammo/ex/ConvexObjectBreaker.js"></script>
<script src="./ammolibs/ammo/ex/QuickHull.js"></script>
<script src="./ammolibs/ammo/ex/geometries/ConvexGeometry.js"></script>
<script src="./ammolibs/meshVisualizer/CesiumMeshVisualizer.js"></script>
<script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyMjBhMzcxMC0wNjBiLTRmYjItYjY1MC0wMzAwMzMyMGUyMmEiLCJpZCI6MzAzNzc3LCJpYXQiOjE3NDc2Mzk0NTV9.E_90aKtVdzRGlU2z48VwJ4mWvl-uuDkfQBCOO6zbzn4'
const viewer = new Cesium.Viewer('cesiumContainer', {});
var homePosition = [114.40184, 30.46331, 50]; //初始位置
look(homePosition[0], homePosition[1], homePosition[2]);
viewer.scene.debugShowFramesPerSecond = true; //查看帧率
MeshVisualizer = Cesium.MeshVisualizer;
Mesh = Cesium.Mesh;
MeshMaterial = Cesium.MeshMaterial;
FramebufferTexture = Cesium.FramebufferTexture;
GeometryUtils = Cesium.GeometryUtils;
MeshPhongMaterial = Cesium.MeshPhongMaterial;
BasicMeshMaterial = Cesium.BasicMeshMaterial;
LOD = Cesium.LOD;
var center = Cesium.Cartesian3.fromDegrees(homePosition[0], homePosition[1], 10);
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
var meshVisualizer = new MeshVisualizer({
modelMatrix: modelMatrix,
up: {
y: 1
},
referenceAxisParameter: {
length: 100,
width: 0.05,
headLength: 2,
headWidth: 0.1
}
});
viewer.scene.primitives.add(meshVisualizer);
meshVisualizer.showReference = true; //显示坐标轴
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
});
}
Cesium.Cartesian3.prototype.set = function (x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Cesium.Cartesian2.prototype.set = function (x, y) {
this.x = x;
this.y = y;
}
Cesium.Quaternion.prototype.set = function (x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
Ammo().then(function () {
// Graphics variables
var clickRequest = false;
var mouseCoords = new Cesium.Cartesian2();
var ballMaterial = createMaterial();
var pos = new Cesium.Cartesian3();
var quat = new Cesium.Quaternion();
// Physics variables
var gravityConstant = -9.8;
var collisionConfiguration;
var dispatcher;
var broadphase;
var solver;
var physicsWorld;
var rigidBodies = [];
var softBodies = [];
var margin = 0.05;
var hinge;
var transformAux1 = new Ammo.btTransform();
var softBodyHelpers = new Ammo.btSoftBodyHelpers();
var armMovement = 0;
var ray = new Cesium.Ray();
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 createObjects() {
// Ground
pos.set(0, -0.5, 0);
quat.set(0, 0, 0, 1);
var ground = createParalellepiped(40, 1, 40, 0, pos, quat,
new MeshPhongMaterial({
defaultColor: "rgb(200,200,200)",
side: MeshMaterial.Sides.DOUBLE,
translucent: false
}));
GeometryUtils.computeVertexNormals(ground.geometry);
// Create soft volumes
var volumeMass = 15;
var sphereGeometry = new THREE.SphereBufferGeometry(1.5, 40, 25);
sphereGeometry.translate(5, 5, 0);
createSoftVolume(sphereGeometry, volumeMass, 250);
var boxGeometry = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(1, 1, 5, 4, 4, 20));
boxGeometry.translate(-2, 5, 0);
createSoftVolume(boxGeometry, volumeMass, 120);
// Ramp
pos.set(3, 1, 0);
Cesium.Quaternion.fromAxisAngle(new Cesium.Cartesian3(0, 0, 1), 30 * Math.PI / 180, quat);
var obstacle = createParalellepiped(10, 1, 4, 0, pos, quat, new MeshPhongMaterial({
defaultColor: "rgb(28,28,28)",
side: MeshMaterial.Sides.DOUBLE,
translucent: false
}));
GeometryUtils.computeVertexNormals(obstacle.geometry);
}
function processGeometry(bufGeometry) {
// Obtain a Geometry
var geometry = new THREE.Geometry().fromBufferGeometry(bufGeometry);
// Merge the vertices so the triangle soup is converted to indexed triangles
var vertsDiff = geometry.mergeVertices();
// Convert again to BufferGeometry, indexed
var indexedBufferGeom = createIndexedBufferGeometryFromGeometry(geometry);
// Create index arrays mapping the indexed vertices to bufGeometry vertices
mapIndices(bufGeometry, indexedBufferGeom);
}
function createIndexedBufferGeometryFromGeometry(geometry) {
var numVertices = geometry.vertices.length;
var numFaces = geometry.faces.length;
var bufferGeom = new THREE.BufferGeometry();
var vertices = new Float32Array(numVertices * 3);
var indices = new(numFaces * 3 > 65535 ? Uint32Array : Uint16Array)(numFaces * 3);
for (var i = 0; i < numVertices; i++) {
var p = geometry.vertices[i];
var i3 = i * 3;
vertices[i3] = p.x;
vertices[i3 + 1] = p.y;
vertices[i3 + 2] = p.z;
}
for (var i = 0; i < numFaces; i++) {
var f = geometry.faces[i];
var i3 = i * 3;
indices[i3] = f.a;
indices[i3 + 1] = f.b;
indices[i3 + 2] = f.c;
}
bufferGeom.setIndex(new THREE.BufferAttribute(indices, 1));
bufferGeom.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
return bufferGeom;
}
function isEqual(x1, y1, z1, x2, y2, z2) {
var delta = 0.000001;
return Math.abs(x2 - x1) < delta &&
Math.abs(y2 - y1) < delta &&
Math.abs(z2 - z1) < delta;
}
function mapIndices(bufGeometry, indexedBufferGeom) {
// Creates ammoVertices, ammoIndices and ammoIndexAssociation in bufGeometry
var vertices = bufGeometry.attributes.position.array;
var idxVertices = indexedBufferGeom.attributes.position.array;
var indices = indexedBufferGeom.index.array;
var numIdxVertices = idxVertices.length / 3;
var numVertices = vertices.length / 3;
bufGeometry.ammoVertices = idxVertices;
bufGeometry.ammoIndices = indices;
bufGeometry.ammoIndexAssociation = [];
for (var i = 0; i < numIdxVertices; i++) {
var association = [];
bufGeometry.ammoIndexAssociation.push(association);
var i3 = i * 3;
for (var j = 0; j < numVertices; j++) {
var j3 = j * 3;
if (isEqual(idxVertices[i3], idxVertices[i3 + 1], idxVertices[i3 + 2],
vertices[j3], vertices[j3 + 1], vertices[j3 + 2])) {
association.push(j3);
}
}
}
}
function createSoftVolume(bufferGeom, mass, pressure) {
processGeometry(bufferGeom);
var volume = new Mesh(bufferGeom, new BasicMeshMaterial({
uniforms: {
diffuseColorMap: "images/visualization/ammo/colors.png"
},
translucent: false
}));
volume.geometry.ammoIndexAssociation = bufferGeom.ammoIndexAssociation;
meshVisualizer.add(volume);
// Volume physic object
var volumeSoftBody = softBodyHelpers.CreateFromTriMesh(
physicsWorld.getWorldInfo(),
bufferGeom.ammoVertices,
bufferGeom.ammoIndices,
bufferGeom.ammoIndices.length / 3,
true);
var sbConfig = volumeSoftBody.get_m_cfg();
sbConfig.set_viterations(40);
sbConfig.set_piterations(40);
// Soft-soft and soft-rigid collisions
sbConfig.set_collisions(0x11);
// Friction
sbConfig.set_kDF(0.1);
// Damping
sbConfig.set_kDP(0.01);
// Pressure
sbConfig.set_kPR(pressure);
// Stiffness
volumeSoftBody.get_m_materials().at(0).set_m_kLST(0.9);
volumeSoftBody.get_m_materials().at(0).set_m_kAST(0.9);
volumeSoftBody.setTotalMass(mass, false)
Ammo.castObject(volumeSoftBody, Ammo.btCollisionObject).getCollisionShape().setMargin(margin);
physicsWorld.addSoftBody(volumeSoftBody, 1, -1);
volume.physicsBody = volumeSoftBody;
// Disable deactivation
volumeSoftBody.setActivationState(4);
softBodies.push(volume);
}
function createParalellepiped(sx, sy, sz, mass, pos, quat, material) {
var box = Cesium.BoxGeometry.fromDimensions({
dimensions: new Cesium.Cartesian3(sx, sy, sz),
vertexFormat: new Cesium.VertexFormat({
position: true,
normal: true
})
});
var threeObject = new Mesh(box, material);
var 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);
if (!threeObject.quaternion) threeObject.quaternion = new Cesium.Quaternion();
Cesium.Quaternion.clone(quat, threeObject.quaternion);
var 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));
var motionState = new Ammo.btDefaultMotionState(transform);
var localInertia = new Ammo.btVector3(0, 0, 0);
physicsShape.calculateLocalInertia(mass, localInertia);
var rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, physicsShape, localInertia);
var 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);
return body;
}
function updatePhysics(deltaTime) {
try {
// Step world
physicsWorld.stepSimulation(deltaTime, 10);
// Update soft volumes
for (var i = 0, il = softBodies.length; i < il; i++) {
var volume = softBodies[i];
var geometry = volume.geometry;
var softBody = volume.physicsBody;
var volumePositions = geometry.attributes.position.values;
var volumeNormals = geometry.attributes.normal.values;
var association = geometry.ammoIndexAssociation;
var numVerts = association.length;
var nodes = softBody.get_m_nodes();
for (var j = 0; j < numVerts; j++) {
var node = nodes.at(j);
var nodePos = node.get_m_x();
var x = nodePos.x();
var y = nodePos.y();
var z = nodePos.z();
var nodeNormal = node.get_m_n();
var nx = nodeNormal.x();
var ny = nodeNormal.y();
var nz = nodeNormal.z();
var assocVertex = association[j];
for (var k = 0, kl = assocVertex.length; k < kl; k++) {
var indexVertex = assocVertex[k];
volumePositions[indexVertex] = x;
volumeNormals[indexVertex] = nx;
indexVertex++;
volumePositions[indexVertex] = y;
volumeNormals[indexVertex] = ny;
indexVertex++;
volumePositions[indexVertex] = z;
volumeNormals[indexVertex] = nz;
}
}
geometry.attributes.position.needsUpdate = true;
geometry.attributes.normal.needsUpdate = true;
volume.modelMatrixNeedsUpdate = true;
}
// Update rigid bodies
for (var i = 0, il = rigidBodies.length; i < il; i++) {
var objThree = rigidBodies[i];
var objPhys = objThree.physicsBody;
var ms = objPhys.getMotionState();
if (ms) {
ms.getWorldTransform(transformAux1);
var p = transformAux1.getOrigin();
var q = transformAux1.getRotation();
objThree.position.set(p.x(), p.y(), p.z());
objThree.quaternion.set(q.x(), q.y(), q.z(), q.w());
objThree.modelMatrixNeedsUpdate = true;
}
}
} catch (e) {
meshVisualizer.beforeUpdate.removeEventListener(update);
console.log("崩溃了兄弟,你这是神马操作");
}
}
var start = false;
var init = false;
var startTime = new Date();
var rayDir = new Cesium.Cartesian3();
var maxDistance = 100; //发射点与射线和局部场景的交点的距离不能太远过远会撕碎软体进而碎片过多时导致ammo物理引擎崩溃
function initInput() {
var scene = viewer.scene;
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
var lastMesh = null;
handler.setInputAction(function (movement) {
if (!clickRequest) {
Cesium.Cartesian2.clone(movement.position, mouseCoords);
clickRequest = true;
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
}
function processClick() {
if (clickRequest) {
meshVisualizer.getPickRay(mouseCoords, ray);
if (!ray) {
clickRequest = false;
return;
}
// Creates a ball
var ballMass = 3;
var ballRadius = 0.4;
var ball = new Mesh(new THREE.SphereGeometry(ballRadius, 18, 16), ballMaterial);
var ballShape = new Ammo.btSphereShape(ballRadius);
ballShape.setMargin(margin);
Cesium.Cartesian3.clone(ray.direction, rayDir);
Cesium.Cartesian3.subtract(ray.origin, ray.direction, pos);
quat.set(0, 0, 0, 1);
var ballBody = createRigidBody(ball, ballShape, ballMass, pos, quat);
ballBody.setFriction(0.5);
Cesium.Cartesian3.normalize(rayDir, rayDir);
Cesium.Cartesian3.multiplyByScalar(rayDir, 30, rayDir);
console.log(rayDir);
ballBody.setLinearVelocity(new Ammo.btVector3(rayDir.x, rayDir.y, rayDir.z));
clickRequest = false;
}
}
function update(frameState) {
var deltaTime = (new Date() - startTime) / 1000.0;
updatePhysics(deltaTime);
processClick();
startTime = new Date();
}
setTimeout(function () {
if (!init) {
// - Init -
initPhysics();
createObjects();
initInput();
init = true;
}
if (!start) {
meshVisualizer.beforeUpdate.addEventListener(update);
start = true;
} else {
meshVisualizer.beforeUpdate.removeEventListener(update);
start = false;
}
}, 1000 * 3);
});
function look(lon, lat, offset) {
var center = Cesium.Cartesian3.fromDegrees(lon, lat);
var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
// View in east-north-up frame
var camera = viewer.camera;
camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;
camera.lookAtTransform(transform, new Cesium.Cartesian3(-offset, -offset, offset));
setTimeout(function () {
camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}, 100)
}
</script>
</body>
</html>