Cesium-Examples/examples/cesiumEx/6.1.3、转动(球).html
2025-06-12 14:10:21 +08:00

463 lines
17 KiB
HTML

<!--********************************************************************
* 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>
<!-- {/* 操作提示: Q 左摆动、 A 右摆动 */} -->
<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;
BasicGeometry = Cesium.BasicGeometry;
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.Cartesian3.prototype.copy = function (src) {
this.x = src.x;
this.y = src.y;
this.z = src.z;
}
Cesium.Cartesian2.prototype.set = function (x, y) {
this.x = x;
this.y = y;
}
Cesium.Cartesian2.prototype.copy = function (src) {
this.x = src.x;
this.y = src.y;
}
Cesium.Quaternion.prototype.set = function (x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
Cesium.Quaternion.prototype.copy = function (src) {
this.x = src.x;
this.y = src.y;
this.z = src.z;
this.w = src.w;
}
Ammo().then(function () {
// Physics variables
var gravityConstant = -9.8;
var collisionConfiguration;
var dispatcher;
var broadphase;
var solver;
var physicsWorld;
var rigidBodies = [];
var margin = 0.05;
var hinge;
var rope;
var transformAux1 = new Ammo.btTransform();
var time = 0;
var armMovement = 0;
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() {
var pos = new Cesium.Cartesian3();
var quat = new Cesium.Quaternion();
// 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: Cesium.Color.fromRgba(0xFFFFFF).withAlpha(1), //"rgb(200,200,200)",
side: MeshMaterial.Sides.DOUBLE,
translucent: false
}));
ground.quaternion = null;
// Ball
var ballMass = 1.2;
var ballRadius = 0.6;
var ball = new Mesh(new Cesium.SphereGeometry({
radius: ballRadius,
stackPartitions: 20,
slicePartitions: 20
}), new MeshPhongMaterial({
defaultColor: Cesium.Color.fromRgba(0x000000).withAlpha(1),
side: MeshMaterial.Sides.DOUBLE,
translucent: false
}));
var ballShape = new Ammo.btSphereShape(ballRadius);
ballShape.setMargin(margin);
pos.set(-3, 2, 0);
quat.set(0, 0, 0, 1);
createRigidBody(ball, ballShape, ballMass, pos, quat);
ball.physicsBody.setFriction(0.5);
// Wall
var brickMass = 0.5;
var brickLength = 1.2;
var brickDepth = 0.6;
var brickHeight = brickLength * 0.5;
var numBricksLength = 6;
var numBricksHeight = 8;
var z0 = -numBricksLength * brickLength * 0.5;
pos.set(0, brickHeight * 0.5, z0);
quat.set(0, 0, 0, 1);
for (var j = 0; j < numBricksHeight; j++) {
var oddRow = (j % 2) == 1;
pos.z = z0;
if (oddRow) {
pos.z -= 0.25 * brickLength;
}
var nRow = oddRow ? numBricksLength + 1 : numBricksLength;
for (var i = 0; i < nRow; i++) {
var brickLengthCurrent = brickLength;
var brickMassCurrent = brickMass;
if (oddRow && (i == 0 || i == nRow - 1)) {
brickLengthCurrent *= 0.5;
brickMassCurrent *= 0.5;
}
var 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 rope
// Rope graphic object
var ropeNumSegments = 10;
var ropeLength = 4;
var ropeMass = 3;
var ropePos = ball.position.clone();
ropePos.y += ballRadius;
var segmentLength = ropeLength / ropeNumSegments;
var ropeMaterial = new MeshMaterial({
defaultColor: Cesium.Color.fromRgba(0x000000).withAlpha(1),
side: MeshMaterial.Sides.DOUBLE,
translucent: false,
wireframe: true
});
var ropePositions = [];
var ropeIndices = [];
for (var i = 0; i < ropeNumSegments + 1; i++) {
ropePositions.push(ropePos.x, ropePos.y + i * segmentLength, ropePos.z);
}
for (var i = 0; i < ropeNumSegments; i++) {
ropeIndices.push(i, i + 1);
}
var ropeGeometry = new Cesium.Geometry({
attributes: {
position: new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.DOUBLE,
componentsPerAttribute: 3,
values: new Float32Array(ropePositions)
})
},
indices: new Uint16Array(ropeIndices),
primitiveType: Cesium.PrimitiveType.LINES,
boundingSphere: Cesium.BoundingSphere.fromVertices(ropePositions)
});
rope = new Mesh(ropeGeometry, ropeMaterial);
meshVisualizer.add(rope);
// Rope physic object
var softBodyHelpers = new Ammo.btSoftBodyHelpers();
var ropeStart = new Ammo.btVector3(ropePos.x, ropePos.y, ropePos.z);
var ropeEnd = new Ammo.btVector3(ropePos.x, ropePos.y + ropeLength, ropePos.z);
var ropeSoftBody = softBodyHelpers.CreateRope(physicsWorld.getWorldInfo(), ropeStart, ropeEnd,
ropeNumSegments - 1, 0);
var sbConfig = ropeSoftBody.get_m_cfg();
sbConfig.set_viterations(10);
sbConfig.set_piterations(10);
ropeSoftBody.setTotalMass(ropeMass, false)
Ammo.castObject(ropeSoftBody, Ammo.btCollisionObject).getCollisionShape().setMargin(margin * 3);
physicsWorld.addSoftBody(ropeSoftBody, 1, -1);
rope.physicsBody = ropeSoftBody;
// Disable deactivation
ropeSoftBody.setActivationState(4);
// The base
var armMass = 2;
var armLength = 3;
var pylonHeight = ropePos.y + ropeLength;
var baseMaterial = createMaterial();
pos.set(ropePos.x, 0.1, ropePos.z - armLength);
quat.set(0, 0, 0, 1);
var base = createParalellepiped(1, 0.2, 1, 0, pos, quat, baseMaterial);
base.quaternion = null;
pos.set(ropePos.x, 0.5 * pylonHeight, ropePos.z - armLength);
var pylon = createParalellepiped(0.4, pylonHeight, 0.4, 0, pos, quat, baseMaterial);
pylon.quaternion = null;
pos.set(ropePos.x, pylonHeight + 0.2, ropePos.z - 0.5 * armLength);
var arm = createParalellepiped(0.4, 0.4, armLength + 0.4, armMass, pos, quat, baseMaterial);
// Glue the rope extremes to the ball and the arm
var influence = 1;
ropeSoftBody.appendAnchor(0, ball.physicsBody, true, influence);
ropeSoftBody.appendAnchor(ropeNumSegments, arm.physicsBody, true, influence);
// Hinge constraint to move the arm
var pivotA = new Ammo.btVector3(0, pylonHeight * 0.5, 0);
var pivotB = new Ammo.btVector3(0, -0.2, -armLength * 0.5);
var 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) {
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) {
threeObject.position.copy(pos);
threeObject.quaternion = new Cesium.Quaternion(quat);
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);
}
function initInput() {
top.window.addEventListener('keydown', function (event) {
switch (event.keyCode) {
case 81: // Q
armMovement = 1;
break;
case 65: // A
armMovement = -1;
break;
}
}, false);
top.window.addEventListener('keyup', function (event) {
armMovement = 0;
}, false);
}
function updatePhysics(deltaTime) {
// Hinge control
hinge.enableAngularMotor(true, 1.5 * armMovement, 50);
// Step world
physicsWorld.stepSimulation(deltaTime, 10);
// Update rope
var softBody = rope.physicsBody;
var ropePositions = rope.geometry.attributes.position.values;
var numVerts = ropePositions.length / 3;
var nodes = softBody.get_m_nodes();
var indexFloat = 0;
for (var i = 0; i < numVerts; i++) {
var node = nodes.at(i);
var nodePos = node.get_m_x();
ropePositions[indexFloat++] = nodePos.x();
ropePositions[indexFloat++] = nodePos.y();
ropePositions[indexFloat++] = nodePos.z();
}
rope.geometry.attributes.position.needsUpdate = 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());
if (objThree.quaternion) {
objThree.quaternion.set(q.x(), q.y(), q.z(), q.w());
}
objThree.modelMatrixNeedsUpdate = true;
}
}
}
var init = false;
var start = false;
var startTime = new Date();
function update(frameState) {
var deltaTime = (new Date() - startTime) / 1000.0;
updatePhysics(deltaTime);
startTime = new Date();
}
setTimeout(function () {
if (!init) {
// - Init -
initPhysics();
createObjects();
initInput();
init = true;
}
if (!start) {
startTime = new Date();
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>