three是一个功能非常强大的3D类库,只要理解了它内部的规则,可以很轻松的创建出各种炫酷的场景。
通过本文你可以了解到:
- three的几个核心(场景、相机、渲染器、物体)
- 三维坐标系在three中的应用
- 绘制一个带网格面的三维坐标系
一、Three几大核心简述
1.1、场景:
- 场景是Three中的载体,基本上所有元素都必须添加到场景中才能显示出来;
- 场景是一个理论上无限的三维空间;
- 在场景中的中心位置的坐标值(0,0,0)
1.2、相机
- 相机是让整个three动起来的方式之一
- 相机必须加入到场景中,才能操作它的位置,或旋转角度,从而改变相机所拍摄到的画面,实现动画的效果
- 相机种类有多重,可以根据需求选择对应的相机,正常情况下我们都用的是透视相机
// 创建一个新的相机
var camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);- three官网封装了非常好用的轨道控制器,我们只需要实例化就可以实现平移、旋转、缩放等操作
// 定义控制器
ar controls = new THREE.OrbitControls(camera, renderer.domElement);
// camera : 实例化的相机
// renderer : 实例化的渲染器1.3 渲染器
- 渲染器的唯一作用就是将相机拍摄到的场景渲染到画布中
- 可以通过设置定时器的方式来制作动画,在定时器中调整相机的位置,或者更改物体的位置都能实现动画的效果
// 通过定时器,来让three动起来
function animate() {
// 定时执行动画
requestAnimationFrame(animate);
// 旋转正方体
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
// 更新渲染器,播放正方体旋转后的画面
renderer.render(scene, camera);
} 1.4、物体
- 一个物体由几何体、材质、纹理组成
// 加载纹理。 在three中有多种加载器,用于加载各种元素,可以直接加载模型,纹理,字体等;
// 纹理的主要作用是,在几何体表面附着一层皮肤,让物体具有真实世界中的样子
// 纹理只能应用在材质上,
var texture = new THREE.TextureLoader().load('./img/crate.gif');
// 创建一个正方形的几何体, 注:可以通过不同的方法创建不通过的几何体
var geometry = new THREE.BoxBufferGeometry(200, 200, 200);
// 创建基础材质,并将上面创建好的纹理应用在材质上
var material = new THREE.MeshBasicMaterial({ map: texture });
// 创建网格, 将几何体和材质传入网格函数,生成能够显示的three模型, 在three中的所有可见的模型都是通过Mesh以及其的衍生类创建出来的,
// 一个可见的模型,需要有几何体以及材质才能被看见,
mesh = new THREE.Mesh(geometry, material);
// 将模型添加到场景中, 如果没有指定位置,那么就从three坐标系中的0,0,0 开始
scene.add(mesh);- 物体实例化以后,可以更改其位置相关属性和材质相关属性达到动画的效果。
二、三维坐标系在three中的应用
- 在three中的坐标系是三维的,也就是每个点的位置由(x, y, z)组成
- 我们需要自己定义一个基准数值,这样方便所有物体的定位,例如,我我们将坐标轴每一段定义为1,那么X轴可以这样设定,从中心点开始(0,0,0)向右为正(1,0,0),向左为负(-1,0,0)
- 了解了坐标系的概念,我们就设置相机和物体的位置,从而构建一个丰富的3D场景
三、绘制一个带网格的三维坐标系
直接上代码
<html>
<head>
<title>My first Three.js app</title>
<style>
body {
margin: 0;
background: #fff;
}
canvas {
width: 100%;
height: 100%
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/OrbitControls.js"></script>
<script>
var lines = [];
var xAxis = ['X轴测试1', 'X轴测试2', 'X轴测试3', 'X轴测试4',]
var yAxis = ['Y轴测试1', 'Y轴测试2', 'Y轴测试3', 'Y轴测试4', 'Y轴测试5',]
var zAxis = ['Z轴测试1', 'Z轴测试2', 'Z轴测试3', 'Z轴测试4', 'Z轴测试5', 'Z轴测试6',]
// 创建场景
var scene = new THREE.Scene();
// 创建透视相机
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// 设置相机的位置
camera.position.set(6, 4, 11)
var renderer = new THREE.WebGLRenderer({
precision: 'highp',
alpha: true,
antialias: true,
powerPreference: 'high-performance'
});
// 设置渲染器的清除颜色
renderer.setClearColor(0xffffff, 0);
// 是指渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 定义控制器
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.maxDistance = 40; // 最大缩放值
controls.minDistance = 2; // 最小缩放值
// 给控制器添加事件,不要通过定时器来实现交互,可以极大的优化性能
controls.addEventListener('change', () => {
renderer.render(scene, camera);
});
// 定义环境光
var ambientLight = new THREE.AmbientLight(0xffffff);
// 将光源添加到场景中 -- 所有事物都需要添加到场景中才能发生作用
scene.add(ambientLight);
// 创建大立方体
function creatRect(){
// 创建一个面的网格
const creatFace = (width, height) => {
// 创建面的模型组
let face = new THREE.Group();
// 定义网格材质
let material = new THREE.LineBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.35
});
// 绘制纵线
for (let i = 0; i <= width; i++) {
// 定义几何形状
let geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(i, 0, 0),
new THREE.Vector3(i, height, 0),
)
// 定义线段
let _line = new THREE.LineSegments(geometry, material);
// 将线段添加至线框组中
lines.push(_line)
// 将线段加入到面模型组
face.add(_line);
}
// 绘制横线
for (let i = 0; i <= height; i++) {
// 定义几何形状
let geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, i, 0),
new THREE.Vector3(width, i, 0),
)
// 定义线段
let _line = new THREE.LineSegments(geometry, material);
// 将线段添加至线框组中
lines.push(_line)
// 将线段加入到面模型组
face.add(_line);
}
return face
}
// 立方体的容器盒子
let box = new THREE.Group();
let _nNum = xAxis.length; // x轴 或 n轴
let _vNum = yAxis.length; // y轴 或 v轴
let _uNum = zAxis.length;// z轴 或 u轴
// 获取相对中心的偏移量
let offsetX = xAxis.length / 2; // X轴的偏移值
let offsetY = yAxis.length / 2; // Y轴的偏移值
let offsetZ = zAxis.length / 2; // Z轴的偏移值
/**
* 创建左面和右面
*/
let left = creatFace(_uNum, _vNum); // Z决定宽度, Y决定高度
left.position.set(-offsetX, -offsetY, offsetZ)
left.rotation.set(0, Math.PI / 2, 0)
let right = creatFace(_uNum, _vNum);
right.position.set(_nNum - offsetX, -offsetY, offsetZ)
right.rotation.set(0, Math.PI / 2, 0)
/**
* 创建上面和下面
*/
let top = creatFace(_nNum, _vNum);
top.position.set(-offsetX, -offsetY, offsetZ)
top.rotation.set(Math.PI * 2, 0, 0)
let bottom = creatFace(_nNum, _vNum);
bottom.position.set(-offsetX, -offsetY, -_uNum + offsetZ);
bottom.rotation.set(Math.PI * 2, 0, 0);
/**
* 创建前面和后面
*/
let before = creatFace(_nNum, _uNum);
before.position.set(-offsetX, -offsetY, offsetZ)
before.rotation.set(-Math.PI / 2, 0, 0);
let after = creatFace(_nNum, _uNum);
after.position.set(-offsetX, _vNum - offsetY, offsetZ)
after.rotation.set(-Math.PI / 2, 0, 0);
box.add(left);
box.add(right);
box.add(top);
box.add(bottom);
box.add(before);
box.add(after);
box.position.set(0, 0, 0);
scene.add(box)
}
creatRect()
renderer.render(scene, camera);
</script>
</body>
</html>
作者:汽车之家-前端体验部-罗龙