我正在学习 Three.js。我正在尝试使用 Cannon-es 将圆柱体连接到我在搅拌机中创建的玫瑰网格,使其落入花瓶中。我的问题是,当我尝试将玫瑰的位置更新为等于身体的位置时,它指出玫瑰没有位置元素,但我在用 gltf-loader 加载它后记录了它并且它有一个位置所以我想我只是没有正确编码。这是我尝试过的方法,谢谢您的帮助!
createRose 函数是从 dat.gui 按钮调用的,当底部的 tick 函数中的代码被注释时,玫瑰和大炮主体创建得很好。
const objectsToUpdate = []
const createRose = (px, py, pz, rx, ry, rz) =>{
gltfLoader.load('/models/pieces/Rose.glb',
(gltf) =>{
let rose = gltf.scene.children[0]
rose.position.set(px, py, pz)
rose.rotation.set(rx, ry, rz)
scene.add(rose)
})
// Cannon.js body
const shape = new CANNON.Cylinder(2, 1, 5, 20)
const body = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(0, 3, 0),
shape: shape,
material: defaultMaterial
})
world.addBody(body)
// Save in objects to update
objectsToUpdate.push({
roseAndBody:{
rose: rose,
body: body
}
})
}
这是在一个名为 tick 的函数中,该函数使用 window.requestAnimationFrame(tick) 更新
for(const object of objectsToUpdate){
object.roseAndBody.rose.position.copy(object.roseAndBody.body.position)
object.roseAndBody.rose.quaternion.copy(object.roseAndBody.body.quaternion)
}
有关更多信息,我正在关注 Bruno SIMON 的付费教程,很多代码都是从他的物理课中修改的,我正在努力为此工作。我完全可以使用不同的格式或其他附加组件而不是 Cannon.js,无论什么都能使它起作用!
问题是
gltfLoader
函数是异步的,当您尝试将 rose
对象添加到 objectsToUpdate
数组时,rose
对象尚未创建,因此是 undefined
.
在创建
gltfLoader
对象后,您应该在rose
的回调函数中移动Cannon.js 主体的创建。像这样的东西:
const createRose = (px, py, pz, rx, ry, rz) =>{
gltfLoader.load('/models/pieces/Rose.glb',
(gltf) =>{
let rose = gltf.scene.children[0]
rose.position.set(px, py, pz)
rose.rotation.set(rx, ry, rz)
scene.add(rose)
// Cannon.js body
const shape = new CANNON.Cylinder(2, 1, 5, 20)
const body = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(0, 3, 0),
shape: shape,
material: defaultMaterial
})
world.addBody(body)
// Save in objects to update
objectsToUpdate.push({
roseAndBody:{
rose: rose,
body: body
}
})
})
}
要在 Three.js 中使用导入模型的物理,您需要执行以下步骤:
使用加载器加载模型,例如 GLTFLoader 或 FBXLoader。这将创建一个包含模型的所有网格和节点的组对象。 创建一个 THREE.Object3D 作为模型的父对象。这是必需的,因为物理引擎需要一个根对象来附加物理体。 遍历组对象并将每个子网格添加到您的 Object3D。您可以使用 Object3D 的 add() 方法来完成此操作。 为模型中的每个网格创建一个物理体。您可以使用 Ammo.js 或 Cannon.js 等物理引擎来创建实体并设置它们的属性(例如质量、形状、位置、速度等)。 将每个物理体附加到模型中相应的网格。您可以使用网格的 userData 属性来存储对物理体的引用,然后根据物理体的位置和旋转更新网格的位置和旋转。 下面是使用 Ammo.js 演示这些步骤的示例代码:
// Load the model
const loader = new THREE.GLTFLoader();
loader.load('model.gltf', function(gltf) {
// Create a parent object for the model
const model = new THREE.Object3D();
// Add each mesh to the model
gltf.scene.traverse(function(child) {
if (child.isMesh) {
model.add(child);
}
});
// Create a physics body for each mesh
const physicsWorld = new Ammo.btDiscreteDynamicsWorld(/*...*/);
const bodies = [];
model.traverse(function(child) {
if (child.isMesh) {
const shape = /* create a shape for the mesh */;
const mass = /* set the mass of the body */;
const body = new Ammo.btRigidBody(/*...*/);
physicsWorld.addRigidBody(body);
bodies.push(body);
child.userData.physicsBody = body;
}
});
// Animate the model
function animate() {
requestAnimationFrame(animate);
// Update the physics simulation
physicsWorld.stepSimulation(/*...*/);
// Update the position and rotation of each mesh based on its physics body
model.traverse(function(child) {
if (child.isMesh) {
const body = child.userData.physicsBody;
const position = /* get the position of the body */;
const quaternion = /* get the quaternion of the body */;
child.position.copy(position);
child.quaternion.copy(quaternion);
}
});
renderer.render(scene, camera);
}
});
请注意,这只是一个基本示例,您可能需要调整物理参数并更频繁地更新模拟,具体取决于模型的复杂性和所需的精度水平。