three.js中的geometry为三维空间中的点集同点集闭合后的各个面的集合。比如一个方块:
- 一个方块8个角,每个角为一个包含x、y、z坐标的点
*每4个角围成一个面
代码如下:
var vertices = [
new THREE.Vector3(1, 3, 1),
new THREE.Vector3(1, 3, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(-1, 3, -1),
new THREE.Vector3(-1, 3, 1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1)
];
var faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
new THREE.Face3(7, 6, 2),
new THREE.Face3(6, 3, 2),
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
];
var geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;
geom.computeFaceNormals();
如上,先创立一个由点阵组成点数组vertices,付值给geom实例,然后faces表示各个面的集合,new THREE.Faces()中的三个值表示点阵vertices中的哪个点,索引从0开始,每个Face为一个三角形(之所以用三角形是因为三角形可以比较容易组成其他形状),两个三角形构成方块点一个面,共12个三角形,6个面。computeFaceNormals()即完成构建
创建一个可变更各顶点位置的控制器
首先我们将这个面创建为一个带网格且透明有阴影带mesh
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),// 透明的绿色材质
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}) // 网格
];
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);// 这个方法支持多种材质组合
mesh.children.forEach(function (e) {
e.castShadow = true // 阴影
});
scene.add(mesh);
结合之前的文字three.js 手动添加元素,利用gui库建立一个控制器来控制各个顶点的位置
var gui = new dat.GUI();
function addControl(x, y, z) {
var controls = new function () {
this.x = x;
this.y = y;
this.z = z;
};
return controls;
}
var controlPoints = [];
controlPoints.push(addControl(3, 5, 3));
controlPoints.push(addControl(3, 5, 0));
controlPoints.push(addControl(3, 0, 3));
controlPoints.push(addControl(3, 0, 0));
controlPoints.push(addControl(0, 5, 0));
controlPoints.push(addControl(0, 5, 3));
controlPoints.push(addControl(0, 0, 0));
controlPoints.push(addControl(0, 0, 3));
gui.add(new function () {
this.clone = function () {
var clonedGeometry = mesh.children[0].geometry.clone();
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
];
var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
mesh2.children.forEach(function (e) {
e.castShadow = true
});
mesh2.translateX(5);//x轴偏移
mesh2.translateZ(5); // z轴偏移
mesh2.name = "clone";
scene.remove(scene.getChildByName("clone"));// 防止重复克隆
scene.add(mesh2);
}
}, 'clone');
for (var i = 0; i < 8; i++) {
f1 = gui.addFolder('Vertices ' + (i + 1));
f1.add(controlPoints[i], 'x', -10, 10);
f1.add(controlPoints[i], 'y', -10, 10);
f1.add(controlPoints[i], 'z', -10, 10);
}
上述我们使用了克隆函数clone
render函数中,我们将方块的顶点集合变为控制器变更后的值:
function render() {
stats.update();
var vertices = [];
for (var i = 0; i < 8; i++) {
vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));
}
mesh.children.forEach(function (e) {
e.geometry.vertices = vertices;
e.geometry.verticesNeedUpdate = true;
e.geometry.computeFaceNormals();
});
// render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
}
完成了,结果如图:
完整代码:
<!DOCTYPE html>
<html>
<head>
<title>Example 02.05 - Custom geometry</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
// once everything is loaded, we run our Three.js stuff.
function init() {
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
// create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true;
// rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0;
// add the plane to the scene
scene.add(plane);
// position and point the camera to the center of the scene
camera.position.x = -20;
camera.position.y = 25;
camera.position.z = 20;
camera.lookAt(new THREE.Vector3(5, 0, 0));
// add subtle ambient lighting
// var ambientLight = new THREE.AmbientLight(0x494949);
// scene.add(ambientLight);
// add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, 10);
spotLight.castShadow = true;
scene.add(spotLight);
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
// call the render function
var step = 0;
var vertices = [
new THREE.Vector3(1, 3, 1),
new THREE.Vector3(1, 3, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(-1, 3, -1),
new THREE.Vector3(-1, 3, 1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1)
];
var faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
new THREE.Face3(7, 6, 2),
new THREE.Face3(6, 3, 2),
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
];
var geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;
geom.computeFaceNormals();
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0x44ff44, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
];
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
mesh.children.forEach(function (e) {
e.castShadow = true
});
scene.add(mesh);
function addControl(x, y, z) {
var controls = new function () {
this.x = x;
this.y = y;
this.z = z;
};
return controls;
}
var controlPoints = [];
controlPoints.push(addControl(3, 5, 3));
controlPoints.push(addControl(3, 5, 0));
controlPoints.push(addControl(3, 0, 3));
controlPoints.push(addControl(3, 0, 0));
controlPoints.push(addControl(0, 5, 0));
controlPoints.push(addControl(0, 5, 3));
controlPoints.push(addControl(0, 0, 0));
controlPoints.push(addControl(0, 0, 3));
var gui = new dat.GUI();
gui.add(new function () {
this.clone = function () {
var clonedGeometry = mesh.children[0].geometry.clone();
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true})
];
var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
mesh2.children.forEach(function (e) {
e.castShadow = true
});
mesh2.translateX(5);//x轴偏移
mesh2.translateZ(5); // z轴偏移
mesh2.name = "clone";
scene.remove(scene.getChildByName("clone"));// 防止重复克隆
scene.add(mesh2);
}
}, 'clone');
for (var i = 0; i < 8; i++) {
f1 = gui.addFolder('Vertices ' + (i + 1));
f1.add(controlPoints[i], 'x', -10, 10);
f1.add(controlPoints[i], 'y', -10, 10);
f1.add(controlPoints[i], 'z', -10, 10);
}
render();
function addCube() {
}
function render() {
stats.update();
var vertices = [];
for (var i = 0; i < 8; i++) {
vertices.push(new THREE.Vector3(controlPoints[i].x, controlPoints[i].y, controlPoints[i].z));
}
mesh.children.forEach(function (e) {
e.geometry.vertices = vertices;
e.geometry.verticesNeedUpdate = true;
e.geometry.computeFaceNormals();
});
// render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init
</script>
</body>
</html>
网友评论