首先,如果想要学习threejs,先去看看 官方基础教程 ,里面阐述了threejs的核心概念和一些重要的对象。这边文章就是具体使用threejs加入3D图形的一个水文,看了自由添加其他物体有个参照。
使用threejs绘制3D图形,一般绘制的结果都是通过canvas元素生成,对于平面、3D效果、视角变化和交互、动画这一块,使用threejs可以快速便捷地帮助我们完成工作,而不必一步一步创建canvas,获取context再逐条绘制。threejs有一些基本概念在使用之前必须要了解。
核心三大块:场景、相机、渲染器。作用分别为:在canvas中展示所有内容的3D容器、显示3D容器中可见区域的投影框、画面选定后进行拍照展示的渲染器。所有渲染器渲染时需要确定场景和相机。
在实际进行绘制更加丰富的内容时,threejs提供了许多对象可以很快的完成一个复杂的3D图形,并且对于3D图像的灵活多变的调整。这些对象包括有几何形状、材料、光线、计时器、射线、辅助线、动画、音频、模型加载器、控制器等,除此之外还有例如矩阵、四元数等等一些进阶的运算,简单应用都不会涉及。
首先创建三大核心对象:
场景
对于一个3D应用,场景应当是唯一的,所有相关的内容都应当添加到唯一的场景中,不管是要显示还是不显示的,显示的画面是通过调整相机角度决定的。所有场景就是所有具体内容的容器。
const scene = new THREE.Scene();
场景的初始化可以自定义其中一些内容,Scene接收对象形式的参数,比较有用属性的包括:
* fog: 表示是否在场景中添加雾气效果,在3D空间中会变成一个有可见度的空间,默认值为null,可以设置一个Fog对象
* overrideMaterial:默认值是null,可以设定一个Material对象,这样场景中所有的物体被渲染出来就会是设定的材料
相机
相机用于控制3D空间显示的区域,通常会采用显示距离的透视相机和显示投影的正交相机,当然以可以直接使用相机,并配置合适的参数来实现相应的相机。透视相机会根据场景中物体默认Z轴的深度进行近大远小的显示,而正交投影相机则会将远近不同的物体按正常的比例进行显示。
普通相机直接使用:const camera = new THREE.Camera();
3D场景汇总常用透视相机, 如果是生成一个透视相机,那么对于3D空间内同样大小但是Z轴距离不容的两个物体在相机中同时显示,更远的物体显示更小。
const camera = new THREE.PerspectiveCamera(45, 1, 1, 100);
透视相机默认接受4个参数,分别表示视角、截面纵横比, 近截面距离,远截面距离(具体参数解释看上面那个链接,还有模型可看)
渲染器
浏览器中3D效果展示是基于webGL的API,使用渲染器从名字上能够体现这一点
const renderer = new THREE.WebGLRenderer();
初始化是可以配备参数的:
* canvas:传递一个canvas的dom元素,如果不传入,那么会新增画布,通过renderer.domElement来获取,画布用于展示绘制的内容
* alpha: 画布默认是黑色背景,有时候我们只想要显示的内容有颜色,那么这一项就要设置为true
* antialias:抗锯齿效果,顾名思义,默认为false
* logarithmicDepthBuffer:这个值默认为false,是采用对数深度检测的内容,场景中物体离视野的距离不一,一般情况下在物体重叠时显示近的物体,特殊情况有可能深度判定有问题,前后材料有重叠破损的表现,此时就需要设置为true
三个核心对象确定完毕,那么就和页面直接关联起来,设置画布大小并添加到body中:
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
下面就粗暴地添加一组物体:
所谓组的概念,是由于场景中3D图形是一个一个的,多个3D图形就可以组成一组,一个或者一组图形都可以通过name属性命名,并通过name找到对应的3D对象。对于一个场景中有多个模型,分组是十分必要的。
添加一组物体,首先要有一个物体,物体有形状,有材料,要想显示材料就需要有光,更多地还需要确定物体的位置、旋转角度、缩放比例。想要显示还需要添加到场景中,相机正确就位,渲染器将相机定住的视野进行拍照渲染。
let group = new THREE.Group(); scene.add(group); // 添加两个物体 let cube = new THREE.BoxGeometry( 10, 10, 10 ); let boxMaterial = new THREE.MeshBasicMaterial( {color: 0x00ff00, wireframe: true} ); let box = new THREE.Mesh( cube, boxMaterial ); box.position.x = 10; group.add( box );
let sphere = new THREE.SphereGeometry( 5, 32, 32 ); let sphereMaterial = new THREE.MeshNormalMaterial({ wireframe: true, transparent: true} ); let blet = new THREE.Mesh( sphere, sphereMaterial ); blet.position.x = -10; group.add( blet ); // 添加光 let light = new THREE.AmbientLight( 0x404040 ); scene.add( light ); // 想要看到空间内的物体,需要调整一下距离和方位 camera.position.z = 100; // 更新空间需要重新渲染 renderer.render(scene, camera);
Geometry对应有许多几何形状,大部分都进行封装,规则图形很好进行绘制,独特的图形也需要自己描点传入数据绘制,比如shape。
材料又分许多种,这里材料都用到wireframe,便于观察我们添加的物体的确是3D结构。
场景中有一个组,那么组内所有显示的3D对象都是在场景中的。而想要显示必须要确保视野对着物体,也就是camera的位置、角度都合适,然后有光才能看见材料的颜色。最后别忘了render一下。
这时候场景中是这样的:
好像3D想过也不是很明显,那么加上动画转一转,将两个物体延自身中心旋转:
window.requestAnimationFrame(function animate() { requestAnimationFrame(animate); box.rotation.x += 0.01; box.rotation.y += 0.01; blet.rotation.x += 0.01; blet.rotation.y += 0.01; renderer.render(scene, camera) })
差不多这样吧:
更多用法参考:https://threejs.org/examples/
还是很有意思的。。