我有一个 THREE.js 平面,使用 Perlin 噪声上下移动点来制作地形。现在我需要为相机添加物理特性以防止它从飞机上掉下来。
我希望创建一个函数,可以从网格中检索顶点和面,并将它们作为凸多面体复制到 CANNON 体上。这是我到目前为止所拥有的,但不起作用:
function setPhysicsGeometry(mesh, body) {
const vertices = mesh.geometry.vertices;
const shape = new CANNON.ConvexPolyhedron();
vertices.forEach(function(vertex) {
// Adjust vertex position based on the physics properties
vertex.z = 0; // Assuming initial z position is 0
// Add the vertex to the shape
shape.vertices.push(new CANNON.Vec3(vertex.x, vertex.y, vertex.z));
});
// Compute the faces of the shape
const faces = [];
for (let i = 0; i < mesh.geometry.faces.length; i++) {
const face = mesh.geometry.faces[i];
faces.push([face.a, face.b, face.c]);
}
shape.faces = faces;
// Update the shape's bounding box
shape.updateNormals();
shape.updateEdges();
// Assign the shape to the body
body.addShape(shape);
}
这是我收到的错误:
Uncaught TypeError: shape.updateNormals is not a function
shape.updateEdges() 也会发生同样的事情
这是这两个函数的问题还是我过度简化了困难/不可能的事情。
谢谢
更新: 我做了一个可以工作但速度超级慢的函数:
function createShape(geo) {
const bufferedGeo = new THREE.BufferGeometry().fromGeometry(geo); // Turn geometry into buffer geo
let position = bufferedGeo.attributes.position.array
const points = []
for (let i = 0; i < position.length; i += 3) {
points.push(new CANNON.Vec3(position[i], position[i + 1], position[i + 2]))
}
const faces = []
for (let i = 0; i < position.length / 3; i += 3) {
faces.push([i, i + 1, i + 2])
}
const shape = new CANNON.ConvexPolyhedron(points, faces)
return shape
}
这是我得到的一个错误,表明法线的排序顺序错误:
.faceNormals[1011] = Vec3(-0.38237948261368415,0.4673447646702331,-0.7971040096570934) looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.
我不知道如何修复它,因为它们只是从几何体中取出的
我解决了它(不完全,仍然存在物理问题,但这是一个不同的问题)。
感谢This Guy向我发送了一个令人惊奇的示例,说明我从哪里获得了解决方案。我试图使用凸多面体来获得我自己的身体形状。我认为仍然可以做到这一点,但是以正确的语法对面和法线进行排序确实很困难。相反,我使用了 Trimesh,这要简单得多。
但是,在示例中,他使用了
new THREE.TorusKnotGeometry()
,然后直接进入了createTrimesh()
。对我来说,这会返回错误,因为 THREE.js 几何图形不是缓冲区几何图形。所以我用一个简单的函数进行了更改,它没有返回任何错误。物理学仍然无法作用于该物体。因此,在感觉像是两个长的时间之后,我将位置和四分从 THREE.js 网格复制到 CANNON 主体,效果非常好。这是完整的代码:
复制位置和四分的代码
function copy(threeMesh, cannonBody) {
// Copy position
const position = new CANNON.Vec3(
threeMesh.position.x,
threeMesh.position.y,
threeMesh.position.z
);
cannonBody.position.copy(position);
// Copy rotation
const quaternion = new CANNON.Quaternion(
threeMesh.quaternion.x,
threeMesh.quaternion.y,
threeMesh.quaternion.z,
threeMesh.quaternion.w
);
cannonBody.quaternion.copy(quaternion);
}
创建 Trimesh 的代码:
function buffer(geo) {
const bufferedGeo = new THREE.BufferGeometry().fromGeometry(geo);
return bufferedGeo;
}
function CreateTrimesh(geometry) {
const vertices = buffer(geometry).attributes.position.array
const indices = Object.keys(vertices).map(Number)
return new CANNON.Trimesh(vertices, indices)
}
网格和主体代码:
var platformGeometry = createCustomGeometry(terrain, size + 1, size + 1)
var platformMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00, wireframe: false, side: THREE.DoubleSide});
var platform = new THREE.Mesh(platformGeometry, platformMaterial);
platform.receiveShadow = true;
platform.castShadow = true
platform.position.set(0, 0, 0)
platform.rotation.x = Math.PI / 2
scene.add(platform);
var platShape = CreateTrimesh(platformGeometry, platform)
var platBody = new CANNON.Body({ mass: 0, shape: platShape });
copy(platform, platBody)
world.addBody(platBody)