如何解决aframe-physics-extras:动态实体与静态gltf模型的碰撞
我正在尝试捕捉动态球体和静态gltf模型之间的碰撞事件。我正在通过以下方式构建gltf实体:
const template = document.createElement('a-entity');
template.setAttribute('physics-collider','ignoreSleep: false');
template.setAttribute('collision-filter','collisionForces: false');
template.setAttribute('body','type:static; shape:hull');
// add position,scale,url etc
// ...
template.addEventListener('collisions',e => {
// debugger;
})
此代码创建一个实体,但是在调试模式下它周围没有电线网,并且未触发collisions
事件。
为了调试,我尝试了不同的形状。这会在实体周围创建一个圆柱体,但看起来太大了。动态形状横穿圆柱,但是collisions
事件并非总是触发,而很少发生。
template.setAttribute('body','type:static; shape:cylinder');
然后我尝试手动构建形状:
template.setAttribute('body','type:static; shape:none');
template.setAttribute('shape','shape: cylinder; height: 5;');
Cannot read property 'bodyOverlapKeeper' of null at NewComponent.<anonymous> (physics-collider.js:34)
所以现在我被卡住了。有人可以建议我在做什么错。我想使用gltf模型本身的形状。我在搅拌机中将其打开,但似乎还可以,我不明白为什么shape:hull
不起作用。
P。 S .:如果有关系,我正在使用webpack
解决方法
0。使用setAttribute
setAttribute
将不会处理以下列表:
template.setAttribute('body','type:static; shape:none');
Rather提供具有新属性的对象:
element.setAttribute("name",{
"property 1": "value 1","property 2": "value 2"
});
1。动态的身体/形状设置
话虽如此,您可以创建一个自定义静态圆柱,如下所示:
element.setAttribute("body",{
"type": "static","shape": "none"
})
element.setAttribute("shape__cylinder",{
'shape': 'cylinder',"height": 1.5,"radiusTop": 0.1,"radiusBottom": 0.2
})
在此fiddle
中查看2。模型的动态形状
关于为gltf模型创建动态形状。就个人而言,尽管使用cannon
驱动程序效果很好,但我使用ammo
并没有运气。另一方面,(在较旧的移动设备上)FPS下降很大,因此,如果可能,请尝试使用简单的碰撞网格以提高性能。
您可以使用简单的功能I made获得带有外观的模型的边界框:
let box = new THREE.Box3()
THREE.Box3Utils.fromSkinnedMesh(skinnedMesh,box);
// box should be the bounding box of the skinned mesh
3。动画模型
我强烈建议创建简单的碰撞形状并将其附加到模型中的特定骨骼上。起点可以是this component:
<a-gltf-model bone-collider="bone: boneName; halfExtents: 0.15 0.15 0.15">
边界框方法将非常复杂,因为:
- 您必须为非旋转网格计算边界框
- 将旋转应用于结果(边界框与世界对齐)
- 在每个刻度上更新身体,甚至删除形状并将其重新添加(source)
您可以在this example
中看到两种方法 ,同时,我能够为gltf模型实现动画碰撞网格。 我使用了@Piotr Adam Milewski here实现的辅助函数。在this答案中查看有关该功能的更多详细信息。 任何其他可以改善性能的建议都值得赞赏。
AFRAME.registerComponent('animated-collision-shape',{
init: function () {
this.nodeMap = {};
this.el.setAttribute('body','type: static; shape: none;')
this.el.addEventListener('model-loaded',() => {
const size = new THREE.Vector3();
let box = new THREE.Box3().setFromObject(this.el.object3D);
box.getSize(size);
this.offset = new CANNON.Vec3(0,size.y / 2,0);
let mesh = this.el.getObject3D("mesh");
mesh.traverse(node => {
if (node.isSkinnedMesh) {
this.skinnedMesh = node;
this.nodeMap[node.uuid] = {
mesh: node,box: new THREE.Box3()
}
}
});
if (!Object.keys(this.nodeMap).length) {
this.nodeMap[0] = {
mesh: this.el.object3D,box: new THREE.Box3()
};
}
this.el.components["body"].shouldUpdateBody = true;
})
},remove: function () {
this.removeBoxes();
},tick: (function () {
const size = new THREE.Vector3();
let common_box_uuid = null;
return function tick() {
if (
!Object.keys(this.nodeMap).length ||
!this.el.body) {
return;
}
let combine = this.data.combine === true
let i = 0;
for (let uuid in this.nodeMap) {
// Non - skinned case
if (!this.nodeMap[uuid].mesh.isSkinnedMesh) {
this.nodeMap[uuid].box.setFromObject(this.el.object3D);
return;
}
// skinned model. Either separate boxes,or combined
if (common_box_uuid && combine) {
utils.SkinnedMeshBBox.expandAABB(this.nodeMap[uuid].mesh,this.nodeMap[common_box_uuid].box);
} else {
utils.SkinnedMeshBBox.getAABB(this.nodeMap[uuid].mesh,this.nodeMap[uuid].box);
common_box_uuid = uuid
}
if (isFinite(this.nodeMap[common_box_uuid].box.max.x)) {
this.nodeMap[common_box_uuid].box.getSize(size);
if (this.el.body.shapes[i]) {
this.el.body.shapes[i].halfExtents = new CANNON.Vec3(size.x / 2,size.z / 2);
this.el.body.shapes[i].updateConvexPolyhedronRepresentation();
} else {
let shape = new CANNON.Box(new CANNON.Vec3(size.x / 2,size.z / 2))
this.el.body.addShape(shape,this.offset,shape.orientation);
}
i++;
}
}
this.el.components["body"].shouldUpdateWireframe = true;
};
})()
})
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。