Three.js 笔记 - 渲染对象和几何体

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中

    ini 复制代码
      mesh.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;
    }
}
  1. 首先基于屏幕上的点击位置,创建一个THREE.Vector3向量。
  2. 使用vector.unproject方法将屏幕上的点击位置转换成Three.js场景中的坐标。换句话来说,就是把屏幕坐标转换为三维场景中的坐标。
  3. 然后创建THREE.Raycaster。使用THREE.Raycaster 可以向场景中发射光线。上例中是向鼠标点击位置发射
  4. 最后使用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);
 });

Blender 加载和导出模型

相关推荐
GIS程序媛—椰子15 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00121 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端24 分钟前
Content Security Policy (CSP)
前端·javascript·面试
木舟100928 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤439138 分钟前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习
半开半落1 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt