上一文中提到了 Cannonjs 中的 Demo 框架,是否是必须的呢?
个人觉得它不是必须的,Demo 框架本身只是方便了使用者将Cannonjs应用于Threejs。
Demo 框架提供了 Scene
PerspectiveCamera
WebGLRenderer
TrackballControls
等一些列在Threejs中所需的基本配置,同时也包括 dat.GUI
和 Stats
个人认为Demo 框架中最重要的一部分是它能够为Cannonjs中的刚体进行可视化,方法包括 addVisual(body)
、addVisuals(bodies)
和 shape2mesh(body)
。其中 addVisual(body)
和 addVisuals(bodies)
都是对 shape2mesh(body)
的引用
.
.
.
CANNON.Demo.prototype.addVisual = function(body){
var s = this.settings;
// What geometry should be used?
var mesh;
if(body instanceof CANNON.Body){
mesh = this.shape2mesh(body); // 这里对 shape2mesh(body) 方法进行了使用
}
if(mesh) {
// Add body
this.bodies.push(body);
this.visuals.push(mesh);
body.visualref = mesh;
body.visualref.visualId = this.bodies.length - 1;
//mesh.useQuaternion = true;
this.scene.add(mesh);
}
};
CANNON.Demo.prototype.addVisuals = function(bodies){
for (var i = 0; i < bodies.length; i++) {
this.addVisual(bodies[i]);
}
};
.
.
.
所以这里着重介绍 shape2mesh(body)
。
该方法可以为
进行可视化
若想创建自己的 Threejs + Cannonjs 世界却苦于不知如何进行可视化,该方法进行必要修改后可直接在自己的程序中进行使用
此处查看源码
下面的 addVisual(body, material)
方法便是在 shape2mesh(body)
的基础上进行的一些修改
function addVisual(body, material) {
// Materials
var material = material || new THREE.MeshPhongMaterial({
color: 0xff0000
});
let shape = body.shapes[0];
// 注:这里默认body中只有一个shape,若body中有多个shape,请使用for循环进行遍历
let mesh;
switch (shape.type) {
case CANNON.Shape.types.SPHERE:
var sphere_geometry = new THREE.SphereGeometry(shape.radius, 30, 30);
mesh = new THREE.Mesh(sphere_geometry, material);
break;
case CANNON.Shape.types.PARTICLE:
mesh = new THREE.Mesh(this.particleGeo, this.particleMaterial);
var s = this.settings;
mesh.scale.set(s.particleSize, s.particleSize, s.particleSize);
break;
case CANNON.Shape.types.BOX:
var box_geometry = new THREE.BoxGeometry(shape.halfExtents.x * 2,
shape.halfExtents.y * 2,
shape.halfExtents.z * 2);
mesh = new THREE.Mesh(box_geometry, material);
break;
case CANNON.Shape.types.CONVEXPOLYHEDRON:
var geo = new THREE.Geometry();
// Add vertices
for (var i = 0; i < shape.vertices.length; i++) {
var v = shape.vertices[i];
geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z));
}
for (var i = 0; i < shape.faces.length; i++) {
var face = shape.faces[i];
// add triangles
var a = face[0];
for (var j = 1; j < face.length - 1; j++) {
var b = face[j];
var c = face[j + 1];
geo.faces.push(new THREE.Face3(a, b, c));
}
}
geo.computeBoundingSphere();
geo.computeFaceNormals();
mesh = new THREE.Mesh(geo, material);
break;
case CANNON.Shape.types.TRIMESH:
var geometry = new THREE.Geometry();
var v0 = new CANNON.Vec3();
var v1 = new CANNON.Vec3();
var v2 = new CANNON.Vec3();
for (var i = 0; i < shape.indices.length / 3; i++) {
shape.getTriangleVertices(i, v0, v1, v2);
geometry.vertices.push(
new THREE.Vector3(v0.x, v0.y, v0.z),
new THREE.Vector3(v1.x, v1.y, v1.z),
new THREE.Vector3(v2.x, v2.y, v2.z)
);
var j = geometry.vertices.length - 3;
geometry.faces.push(new THREE.Face3(j, j + 1, j + 2));
}
geometry.computeBoundingSphere();
geometry.computeFaceNormals();
mesh = new THREE.Mesh(geometry, material);
break;
default:
throw "Visual type not recognized: " + shape.type;
}
mesh.receiveShadow = true;
mesh.castShadow = true;
if (mesh.children) {
for (var i = 0; i < mesh.children.length; i++) {
mesh.children[i].castShadow = true;
mesh.children[i].receiveShadow = true;
if (mesh.children[i]) {
for (var j = 0; j < mesh.children[i].length; j++) {
mesh.children[i].children[j].castShadow = true;
mesh.children[i].children[j].receiveShadow = true;
}
}
}
}
mesh.receiveShadow = true;
mesh.castShadow = true;
scene.add(mesh);
return mesh;
}