Mesh 渲染对象
要渲染的主要对象,如方块,球体等几何体
arduino
new THREE.Mesh(geometry,material)
mesh对象常用的属性和方法如下:
- position 决定该对象相对于父对象的位置,通常父对象是THREE.Scene或者THREE.Object3D对象.
js
mesh.position.x = 10
mesh.position.y = 3
mesh.position.z = 1
// 一次性设置
mesh.position.set(10,3,1)
mesh.position = new THREE.Vector3(10,3,1)
- rotation 设置对象绕每个轴的旋转弧度。在数学上,物体旋转一周的弧度值为PI(圆周率即3.14159...)的两倍
js
mesh.rotation.x = 0.5 * Math.PI
mesh.roration.set(0.5 * Math.PI, 0, 0)
mesh.rotation = new THREE.vector3(0.5 * Math.PI, 0, 0)
如果使用度数0-360来设置旋转,需要做如下转换
js
const degrees = 45;
const inRadians = degrees * (Math.PI / 180);
- scale 设置对象沿着x,y,z轴缩放,如果缩放值大于1,物体就会放大,反之就会缩小 设置方法跟position类似
js
mesh.scale.set(controls.scaleX, controls.scaleY, controls.scaleZ);
mesh.scale.x = controls.scaleX;
mesh.scale.y = controls.scaleY;
mesh.scale.z = controls.scaleZ;
-
translate 改变对象相对于当前位置的平移距离。 假设有一个球体,位置为(1,2,3), translateX(4) 代表着该球体相对于x轴平移4个单位,位置变为了(5,2,3),如果想让该球体回到之前的位置,需要使用translateX(-4)。 translateY,translateZ同理。
-
visible 设置mesh是否渲染到scene中
inimesh.visible = true
可以通过Three.js中的射线选中Mesh对象
js
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects([sphere, cylinder, cube]);
if (intersects.length > 0) {
console.log(intersects[0]);
intersects[0].object.material.transparent = true;
intersects[0].object.material.opacity = 0.1;
}
}
- 首先基于屏幕上的点击位置,创建一个THREE.Vector3向量。
- 使用vector.unproject方法将屏幕上的点击位置转换成Three.js场景中的坐标。换句话来说,就是把屏幕坐标转换为三维场景中的坐标。
- 然后创建THREE.Raycaster。使用THREE.Raycaster 可以向场景中发射光线。上例中是向鼠标点击位置发射
- 最后使用ray,caster.intersectObjects判断指定的对象中哪些被该光线照射到了。
上面例子里log出来的intersects[0].object就是选中的mesh对象。 如果要多选的话,可以考虑记录选中的mesh对象,用数组存储。
Geometry 几何体
three.js中的几何体基本是三维空间中的点集(也被称为顶点)以及这些点连接起来的面
以立方体为例:
- 一个立方体有8个角,每个角都可以用下x,y,z坐标点来定义,所以每个立方体在三维空间都有8个点,也就是顶点
- 一个立方体有6个面,在three.js中,立方体的每个面都是由两个三角形面组成的,每个三角形面都由三个点构成。
内置的几何体
二维几何体
PlaneGeometry 二维矩形
PlaneGeometry对象可以创建一个非常简单的二维矩形。
js
const plane = new THREE.PlaneGeometry(width, height, wightSegments, heighSegments);
scene.add(plane);
后两个参数是非必填的,分别代表矩形的宽度/高度应该划分为几段,默认值为1。
如果你想要创建一个躺下的二维矩形(地面),最简单的办法是将mesh对象沿x轴向后旋转四分之一圈(-PI/2)。
js
mesh.rotation.x = - Math.PI/2;
CircleGeometry 二维圆
js
const plane = new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength);
scene.add(plane);
- radius 表示圆的半径,决定了圆的大小。
- segments 该属性定义了创建圆所用面的数量,最小为3个,默认值为8。该值越大,创建出来的圆越光滑。
- thetaStart 定义从哪里开始画圆。值的范围是0-2*PI。
- thetaLength 定义圆要画多大。默认值为2*PI(整圆)
js
// 完整的圆
new THREE.CircleGeometry(3,12);
// 半圆
new THREE.CircleGeometry(3, 12, 0, Math.PI);
三维几何体
BoxGeometry 立方体
SphereGeometry 三维球体
CylinderGeometry 圆柱体
自定义几何体
在three.js中,可以通过定义顶点和面来创建自定义几何体
ConvexGeometry 围绕一组点创建几何体
创建一个围绕一组点的最小图形
示例:
js
// add 10 random spheres
var points = [];
for (var i = 0; i < 20; i++) {
var randomX = -15 + Math.round(Math.random() * 30);
var randomY = -15 + Math.round(Math.random() * 30);
var randomZ = -15 + Math.round(Math.random() * 30);
points.push(new THREE.Vector3(randomX, randomY, randomZ));
}
spGroup = new THREE.Object3D();
var material = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: false});
points.forEach(function (point) {
var spGeom = new THREE.SphereGeometry(0.2);
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.copy(point);
spGroup.add(spMesh);
});
// add the points as a group to the scene
scene.add(spGroup);
// use the same points to create a convexgeometry
var hullGeometry = new THREE.ConvexGeometry(points);
hullMesh = createMesh(hullGeometry);
scene.add(hullMesh);
LatheGeometry 从光滑曲线创建
允许从一条光滑曲线创建图形。
-
point 指定构成曲线的点。
-
segments 创建图形时所用到的分段数目
-
phiStart 该属性指定创建图形时,从圆的何处开始。取值范围为0-2*PI,默认为0
-
phiLength 指定创建的圆形有多完整。 默认值为360°或2PI。例如四分之一就是0.5PI
示例:
js
var points = [];
var height = 5;
var count = 30;
for (var i = 0; i < count; i++) {
points.push(new THREE.Vector3((Math.sin(i * 0.2) + Math.cos(i * 0.3)) * height + 12, 0, ( i - count ) + count / 2));
}
spGroup = new THREE.Object3D();
var material = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: false});
points.forEach(function (point) {
var spGeom = new THREE.SphereGeometry(0.2);
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.copy(point);
spGroup.add(spMesh);
});
// add the points as a group to the scene
scene.add(spGroup);
// use the same points to create a LatheGeometry
var latheGeometry = new THREE.LatheGeometry(points, segments, phiStart, phiLength);
latheMesh = createMesh(latheGeometry);
scene.add(latheMesh);
ExtrudeGeometry 二维图形转三维图形
从一个二维图形创建出一个三维图形。即从一条路径拉伸二维图形。
甚至可以通过github上一个d3-threeD的库,把SVG拉伸成三维图形。
示例:
ini
shape = createMesh(new THREE.ExtrudeGeometry(一个或多个THREE.shape对象, options));
TextGeometry 三维文本
js
var options = {
size: controls.size,
height: controls.height,
weight: controls.weight,
font: controls.font,
bevelThickness: controls.bevelThickness,
bevelSize: controls.bevelSize,
bevelSegments: controls.bevelSegments,
bevelEnabled: controls.bevelEnabled,
curveSegments: controls.curveSegments,
steps: controls.steps
};
text1 = createMesh(new THREE.TextGeometry("Learning", options));
text1.position.z = -100;
text1.position.y = 200;
text1.position.x = 200
scene.add(text1);
text2 = createMesh(new THREE.TextGeometry("Three.js", options));
scene.add(text2);
属性:
- size 该属性指定文本的大小。默认值为100。
- height 该属性指定拉伸的长度(深度)。默认值为50。
- weight 指定字体的粗细。可选值包括normal和bold。默认为normal。
- font 指定要用的字体名。默认值为helvetiker。
- style 指定样式。可选值包括normal和italic。默认值为normal。
- bevelThickness 指定斜角的深度。斜角是前后面和拉深体之间的倒角。该值定义斜角进入图形的深度。默认值为10。
- bevelSize 该属性指定斜角的高度,默认值为8。
- bevelSegments 该属性指定斜角的分段数。分段越多,斜角越平滑。默认为3。
- bevelEnable 指定是否有斜角 true、false
- curveSegments 指定拉伸时,曲线分为多少段。分段数越多,曲线越平滑。默认值为4
- extrudePath 指定图形沿什么路径拉伸。默认为Z轴。
- material 定义前后面所用材质的索引
- extrudeMaterial 指定斜角和拉伸体所用材质的索引。
可以通过 typeface.neocracy.org:81/fonts.html 把字体转换成js。使用时,把该字体加入到html页面顶部,即可使用该字体。
对象组合 THREE.Group
js
sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));
cube = createMesh(new THREE.BoxGeometry(6, 6, 6));
sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
// add it to the scene.
// also create a group, only used for rotating
group = new THREE.Group();
group.add(sphere);
group.add(cube);
scene.add(group);
通过new一个THREE.Group对象来创建一个组,然后通过add方法向组内添加元素。
group移动、缩放、旋转和变形时,内部的元素都会受到影响。
但这里要注意一点,旋转时,组内的对象并不是分别旋转组内的每一个对象,而是绕着组的中心进行旋转。
使用组时,依然可以引用,修改和定位每一个单独的几何体。唯一需要注意的是,所有的定位、旋转、和变形都是相对于父对象的。
对象合并 geometry.merge
当对象的数量非常多时,性能会成为瓶颈。我们可以通过THREE.Geometry.merge把多个几何体合并成一个,解决这种性能瓶颈。
js
var geometry = new THREE.Geometry();
for (var i = 0; i < controls.numberOfObjects; i++) {
var cubeMesh = addcube();
cubeMesh.updateMatrix();
geometry.merge(cubeMesh.geometry, cubeMesh.matrix);
}
scene.add(new THREE.Mesh(geometry, cubeMaterial));
但这种模式也有缺陷,由于最终得到的是一个几何体,所以不能为每个几何体单独添加材质,而且不能对每个几何体进行单独控制。
从外部资源中加载
Three.js加载外部资源,一般都需要先引入对应的loader加载器,然后new一个loader的实例,指定要加载的资源路径,然后传入一个在资源加载完成后会被调用的回调函数。
在回调函数中可以对加载完成的资源做一些调整,另外需要在回调中把模型添加到场景中。
对资源进行调整的原因是,在外部应用程序中创建模型的方式,会给出不同于我们在Three.js中使用的尺寸和组。
如果模型不能正常显示,一般是材质设置导致的,可能是用了不兼容的纹理格式,透明度不正确,或者是该格式文件中指向纹理的连接有错误。
JSON
一般在保存和加载单个THREE.Mesh,或者保存和加载整个场景的时候,使用THREE.js的JSON文件格式。
保存Mesh
ini
var knot = createMesh(new THREE.TorusKnotGeometry(10, 1, 64, 8, 2, 3, 1));
var result = knot.toJSON();
把MeshJson重新转换为Mesh
ini
var loadedGeometry = JSON.parse(json);
var loader = new THREE.ObjectLoader();
loadedMesh = loader.parse(loadedGeometry);
loadedMesh.position.x -= 50;
scene.add(loadedMesh);
只保存Mesh的话,Light和Camera都会丢失,所以如果想保存整个场景,可以使用THREE.SceneExporter
需要先在threejs的包里找到并引入导入导出器。
xml
<script type="text/javascript" src="../libs/SceneLoader.js"></script>
<script type="text/javascript" src="../libs/SceneExporter.js"></script>
导出
ini
var exporter = new THREE.SceneExporter();
var sceneJson = JSON.stringify(exporter.parse(scene));
导入
ini
var sceneLoader = new THREE.SceneLoader();
sceneLoader.parse(JSON.parse(json), function (e) {
scene = e.scene;
}, '.');
OBJ和MTL
OBJ和MTL是相互配合的两种格式,OBJ定义几何体,而MTL文件定义所用的材质。它们都是基于文本的格式。
js
var loader = new THREE.OBJMTLLoader();
loader.load('../assets/models/butterfly.obj', '../assets/models/butterfly.mtl', function (object) {
console.log(object)
// configure the wings
var wing2 = object.children[5].children[0];
var wing1 = object.children[4].children[0];
wing1.material.opacity = 0.6;
wing1.material.transparent = true;
wing1.material.depthTest = false;
wing1.material.side = THREE.DoubleSide;
wing2.material.opacity = 0.6;
wing2.material.depthTest = false;
wing2.material.transparent = true;
wing2.material.side = THREE.DoubleSide;
object.scale.set(140, 140, 140);
mesh = object;
scene.add(mesh);
object.rotation.x = 0.2;
object.rotation.y = -1.3;
});
Collada
一种基于XML格式定义数字内容的格式。 基本所有的三维软件和渲染引擎都支持这种格式。
Collada模型(扩展名为.dae)是一种非常通用的,用来定义场景和模型(以及动画)的文件格式。它不仅定义了几何体,也定义了材质,甚至可以定义光源。
加载Colllada模型:
ini
var loader = new THREE.ColladaLoader();
var mesh;
loader.load("../assets/models/dae/Truck_dae.dae", function (result) {
mesh = result.scene.children[0].children[0].clone();
mesh.scale.set(4, 4, 4);
scene.add(mesh);
});