关于Three.js
-
Three.js是基于原生WebGL封装运行的三维引擎,WebGL只能绘制点、线和三角形;Three.js封装了诸如场景、灯光、阴影、材质、贴图、空间运算等一系列功能,相对于WebGL方便简单了不少。 -
建立基本场景 在Three.js中有三要素:场景、摄像机和渲染器,我们创建好场景(Scene )和一个摄像机(Camera )到渲染器(Renderer )中就可以渲染三维维场景渲染成一个二维图片显示在画布上。
相关文档
- THREE.JS 教程:https://threejsfundamentals.org/threejs/lessons/zh_cn/
- 官方文档 https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
- 郭隆邦技术博客 http://www.yanhuangxueyuan.com/
创建一个简单的场景
下载three.js
npm i three
<template>
<canvas width="500" height="500" ref="threeCanvas" ></canvas>
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue';
import * as THREE from 'three';
export default defineComponent({
setup() {
let threeCanvas = ref(null);
let renderer,
scene,
camera,
mesh;
function init() {
renderer = new THREE.WebGLRenderer({
canvas: threeCanvas.value
});
renderer.setClearColor('#fff');
scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
color: 0x0000ff
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
let point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300);
scene.add(point);
let ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
camera = new THREE.PerspectiveCamera(60, 500 / 500, 1, 1000);
camera.position.set(200, 300, 200);
camera.lookAt(scene.position);
render();
}
function render() {
renderer.render(scene, camera);
}
onMounted(() => {
init();
});
return {
threeCanvas
};
}
});
</script>
<style lang="scss" scoped>
</style>
绘制出一个立方体
几何体的本质
几何体本质上就是一系列的顶点构成的,每三个点构成一个三角形平面
几何变换(缩放、平移、旋转)
缩放
立方体网格模型x轴方向放大2倍,如果连续执行两次该语句,相等于比原来方法4倍
mesh.scale.x 设置轴方向的缩放 ;y轴和z轴的缩放类似
mesh.scale.x = 2.0;
立方体网格模型整体缩小0.5倍,相当于xyz三个方向分别缩小0.5倍
mesh.scale.set(0.5,0.5,0.5);
平移
立方体网格模型沿着x轴正方向平移100,可以多次执行该语句,每次执行都是相对上一次的位置进行平移变换
mesh.translateX(100);
网格模型沿着向量(0,1,0)表示的方向平移100
const axis = new THREE.Vector3(0,1,0);
mesh.translateOnAxis(axis,100);
旋转
立方体网格模型绕立方体的x轴旋转π/4,可以多次执行该语句,每次执行都是相对上一次的角度进行旋转变化
mesh.rotateX(Math.PI/4);
网格模型绕(0,1,0)向量表示的轴旋转π/8
var axis = new THREE.Vector3(0,1,0);
mesh.rotateOnAxis(axis,Math.PI/8);
旋转动画
设置一个定时器 去一直旋转集合体,如果要实现一个60帧的动画,时间间隔应为1000/60
修改渲染方法使用定时器进行旋转
function render() {
renderer.render(scene, camera);
setInterval(() => {
mesh.rotateY(Math.PI / 100);
}, 1000 / 60);
}
由于画面一直停留在第一帧所以我们正方体并没有旋转,我们需要在旋转后重新渲染
setInterval(() => {
mesh.rotateY(Math.PI/ 100);*
renderer.render(scene, camera);
}, 1000 / 60);
requestAnimationFrame
-
requestAnimationFrame() 调用一个函数一般默认保持60FPS的频率无限执行 -
requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。 -
在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。 requestAnimationFrame比setInterval更好,所以可以使用requestAnimationFrame实现60帧渲染 function render() {
renderer.render(scene, camera);
mesh.rotateY(Math.PI / 100);
requestAnimationFrame(render);
}
坐标
世界坐标系和本地坐标
-
世界坐标系就是整个场景的坐标系 -
本地坐标系是物体的坐标,在物体中心点。
辅助坐标
创建一个辅助坐标添加到场景中,会在场景中显示世界坐标系以共开发时使用
let axisHelper = new THREE.AxesHelper(2000);
scene.add(axisHelper);
鼠标操作三维场景
OrbitControls.js 控件支持鼠标左中右键操作和键盘方向键操作
场景操作
- 缩放:滚动—鼠标中键
- 旋转:拖动—鼠标左键
- 平移:拖动—鼠标右键
使用
引入
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
在render最后加上
new OrbitControls(camera, renderer.domElement);
OrbitControls会根据鼠标的动作对相机的参数进行改变
如果要键盘操作只需要定义键盘监听事件然后操作三维场景
window.addEventListener('keydown',function(e){
console.log(e);
});
材质
在创建立方体是我们创建的Lambert网格材质 只设置了颜色
const material = new THREE.MeshLambertMaterial({
color: 0x0000ff
});
当然还有其他设置项
材质常见属性
材质属性 | 简介 |
---|
color | 材质颜色,比如蓝色0x0000ff | wireframe | 将几何图形渲染为线框。 默认值为false | opacity | 透明度设置,0表示完全透明,1表示完全不透明 | transparent | 是否开启透明,默认false | map | 贴图 |
three.js提供的材质
纹理贴图
three.js可以使用**图片 、Canvas画布 、视频 **作为贴图
图片作为贴图
通过纹理贴图加载器TextureLoader的load() 方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture 可以作为模型材质颜色贴图.map 属性的值。
修改创建几何体的代码创建一个球体并使用一张世界地图作为贴图
行星素材 http://planetpixelemporium.com/mercury.html
const geometry = new THREE.SphereGeometry(50, 100, 100);
const textureLoader = new THREE.TextureLoader();
textureLoader.load(require('@/assets/image/world_500x250.jpg'), (texture) => {
const material = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
opacity: 1
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
render();
});
球体表面使用世界地图作为贴图可以实现一个地球
Canvas画布作为贴图
创建canvas并绘制文字使用THREE.CanvasTexture转为贴图
function canvasText(text) {
let canvas = document.createElement('canvas');
canvas.style = 'z-index:99';
canvas.width = 50;
canvas.height = 30;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(255, 255, 255, 255)';
ctx.fillRect(0, 0, 50, 30);
ctx.beginPath();
ctx.translate(25, 5);
ctx.fillStyle = '#3387DB';
ctx.font = '900 12px impact';
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(text, 0, 0);
let texture = new THREE.CanvasTexture(canvas);
return texture;
}
将材质 map设置为Canvas 在代码最后执行render();
const geometry = new THREE.SphereGeometry(50, 100, 100);
const textureLoader = new THREE.TextureLoader();
let texture = canvasText('我是地球');
const material = new THREE.MeshLambertMaterial({
map: texture,
transparent: true,
opacity: 1
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
视频作为贴图
let video = document.createElement('video');
video.src = "视频.mp4";
video.autoplay = "autoplay";
let texture = new THREE.VideoTexture(video)
将 texture 给材质的map
精灵模型
精灵模型相当于一个平面矩形几何体,同时精灵模型的矩形平面会始终平行于Canvas画布。
创建一个精灵模型并且添加到地球中
let spriteMaterial = new THREE.SpriteMaterial({
color: 0xff00ff,
rotation: Math.PI / 4,
map: texture
});
let sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(30, 30, 1);
sprite.position.set(100, 100, 100);
mesh.add(sprite);
精灵模型跟随地球转动,且精灵模型始终平行于Canvas平面
导出模型
直接将几何体转化为JSON
const geometry = new THREE.SphereGeometry(50, 100, 100);
console.log(JSON.stringify(geometry));
导入导出的json
let loader = new THREE.FileLoader();
loader.load('material.json', function (elem) {
console.log(elem);
let obj = JSON.parse(elem);
});
加载外部模型
three.js可任意导入3D使用3D软件建好的模型(包括模型,贴图和动画) (stl、obj、fbx等文件)
-
OBJ是一种3D模型文件,因此不包含动画、材质特性、贴图路径、动力学、粒子等信息。 -
MTL文件则是 obj附属文件,用以描述几何体的表面描影属性,obj的贴图 -
stl、obj都是静态模型,不可以包含动画, -
fbx除了包含几何、材质信息,可以存储骨骼动画等数据。
3D素材 https://free3d.com/zh/3d-models/obj
vue项目中obj等3D文件必须放在静态资源(static)要不然加载不出来
- 在vue中存放obj模型必须要放在静态资源(static)文件下,否则会出错。
- 由于4.x版本的vue没有static这个文件夹,但是他的静态资源文件夹是叫public,这样我在public下面创建一个文件夹叫static,再在static文件夹下存放的我的obj模型文件以及mtl文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DO5RAwbR-1637063124419)(image-20211116165705395.png)]
引入 加载器
加载器在three/examples/jsm/loaders目录下
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
使用 OBJLoader 加载obj模型文件添加到场景中
const objLoader = new OBJLoader();
const mtlLoader = new MTLLoader();
mtlLoader.load('/static/low_poly_tree/Lowpoly_tree_sample.mtl', (materials) => {
objLoader.setMaterials(materials);
objLoader.load('/static/low_poly_tree/Lowpoly_tree_sample.obj', (obj) => {
mesh = obj;
scene.add(obj);
render();
});
});
雾化效果
场景scene对象的fog属性用于设置雾化效果
雾有两种 分别是:线性雾(Fog()),和指数雾(FogExp2()).
线性雾(Fog())
雾化效果成线性增长
new THREE.Fog( hex, near, far);
参数:hex:雾的颜色,near:场景添加雾的最小距离,far:雾化效果的截止距离。
定义0xffffff颜色的雾 设置雾的最小距离120 雾化效果的截止距离 150
scene.fog = new THREE.Fog(0xffffff, 120, 150);
指数雾(FogExp2()).
雾随着距离呈指数增长的雾化效果,只需要设置雾的颜色和浓度即可
scene.fog = new THREE.FogExp2(0xffffff,0.02);
|