one
场景(scene), 相机(camera), 渲染器(renderer)。
Scene-场景
camera-相机
//创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
- fov — 摄像机视锥体垂直视野角度
- aspect — 摄像机视锥体长宽比
- near — 摄像机视锥体近端面
- far — 摄像机视锥体远端面
- 这些参数一起定义了摄像机的 viewing frustum(视锥体)
透视图中,灰色的部分是视锥体,是可能被渲染的物体所在的区域。
fov 是视锥体竖直方向上的张角(是角度制而非弧度制),如侧视图所示。
aspect 等于 width / height,是照相机水平方向和竖直方向长度的比值,通常设为 Canvas 的横纵比例。
near 和 far 分别是照相机到视锥体最近、最远的距离,均为正值,且 fa r应大于 near。
但请注意,不要将 near 和 far 设置为比较极端的数值,如 0.0001 和 99999,这可能引起 bug,让 threejs 无法分辨物体的前后,导致闪动
Three.js的架构支持多种camera,这里使用最常见的远景相机(PerspectiveCamera),也就是类似于人眼观察的方式。第一个属性75设置的是视角(field of view)。
第二个属性设置的是相机拍摄面的长宽比(aspect ratio)。
我们几乎总是会使用元素的宽除以高,否则会出现挤压变形。
Geometry-几何
注意:Geometry自从r125版本后已废弃,请使用BufferGeometry。BufferGeometry的性能更好。
缓存几何模型(BufferGeometry)
该类是一个 几何模型(Geometry) 的高效替代,因为它使用缓存(buffer)来保存所有数据,包括顶点位置、面索引、法向量、颜色、UVs以及自定义属性。 这节约了向GPU传递全部这些数据的成本。但同时也使得BufferGeometry要比 几何模型(Geometry) 更难以处理,不是以对象的方式来访问,比如使用Vector3来访问位置数据, 以Color对象来访问颜色数据,你得从相应的attribute缓存中访问原始数据。 这使得BufferGeometry很适合用来存储静态对象,也就是当我们创建完模型实例后不太需要去操作它。
Three.js 中文教程 | 参考手册 | 使用指南 | 动画特效实例 | 踏得网
//创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
three自带几何缓冲模型
var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
构造器(Constructor)
BoxBufferGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
width — X轴上的面的宽度 (左右)
height — Y轴上的面的高度 (上下)
depth — Z轴上的面的深度 (前后)
widthSegments — 可选参数. 沿宽度面的分割面数量. 默认值为1.
heightSegments — 可选参数. 沿高度面的分割面数量. 默认值为1.
depthSegments — 可选参数. 沿深度面的分割面数量. 默认值为1.
Material-材质
//材质,颜色
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
构造器(Constructor)
MeshBasicMaterial( parameters )
参数是一个使用一个或多个属性定义材料外观的对象。
color — 线条的十六进制颜色。缺省值为 0xffffff。
map — 设置纹理贴图。缺省为null。
aoMap — 设置环境遮挡贴图(ao = ambient occlusion)。缺省为null。
aoMapIntensity — 设置环境遮挡贴图强度。缺省为1。
specularMap — 设置高光贴图。默认为null。
alphaMap — 设置阿尔法贴图。默认为null。
阿尔法贴图是一个灰度纹理,控制整个表面的不透明度(黑色:完全透明;白色:完全不透明)。默认为空。
envMap — 设置环境贴图。默认为null。
combine — 设置组合操作。默认值是THREE.MultiplyOperation.
reflectivity — 设置反射率。默认值是 1.
refractionRatio — 设置折射率。默认值是 0.98.
fog — 定义材质颜色是否受全局雾设置的影响。默认是true。
shading — 定义着色类型。缺省为 THREE.SmoothShading。
wireframe — 渲染模型为线框。默认是false。
wireframeLinewidth — 线框线宽。默认是1。
wireframeLinecap — 定义线端的外观。默认值是 'round'.
wireframeLinejoin — 定义线连接节点的外观。默认值是 'round'.
vertexColors — 定义顶点如何着色。默认值是 THREE.NoColors.
skinning — 定义材料是否使用皮肤。默认值是false.
morphTargets — 定义材料是否使用 morphTargets。默认值是 false。
Mesh创建物体
//根据几何体和材质创建物体
const cube = new THREE.Mesh(geometry, material);
WebGLRenderer-渲染器
WebGL渲染器使用WebGL来绘制您的场景,如果您的设备支持的话。使用WebGL将能够利用GPU硬件加速从而提高渲染性能。
//初始化渲染器
const renderer = new THREE.WebGLRenderer();
//设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
//将webgl渲染的canvas 渲染到body上
document.body.appendChild(renderer.domElement);
//渲染
// renderer.render(scene, camera);
构造器(Constructor)
WebGLRenderer( parameters )
parameters 是一个可选对象,包含用来定义渲染器行为的属性。当没有设置该参数时,将使用默认值。
canvas — 一个用来绘制输出的 Canvas 对象。
context — 所用的 渲染上下文(RenderingContext) 对象。
precision — 着色器的精度。可以是"highp", "mediump" 或 "lowp". 默认为"highp",如果设备支持的话。
alpha — Boolean, 默认为 false.
premultipliedAlpha — Boolean, 默认为 true.
antialias — Boolean, 默认为 false.
stencil — Boolean, 默认为 true.
preserveDrawingBuffer — Boolean, 默认为 false.
depth — Boolean, 默认为 true.
logarithmicDepthBuffer — Boolean, 默认为 false.
.setSize ( width, height, updateStyle )
调整输出canvas尺寸(宽度,高度),要考虑设备像素比,并且设置视口(viewport)以匹配该尺寸。如果设置 updateStyle 为true,则显式添加像素到输出canvas的样式中。
AxesHelper-坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
用于简单模拟3个坐标轴的对象.
红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
构造函数
AxesHelper( size : Number )
size -- (可选的) 表示代表轴的线段长度. 默认为 1.
OrbitControls-控制器
const controls = new OrbitControls(camera, renderer.domElement);
Orbit controls(轨道控制器)可以使得相机围绕目标进行轨道运动。
要使用这一功能,就像在/examples(示例)目录中的所有文件一样, 您必须在HTML中包含这个文件。
Clock-时钟
跟踪时间的对象
const clock=new THREE.Clock()
Three.js 中文教程 | 参考手册 | 使用指南 | 动画特效实例 | 踏得网
requestAnimationFrame --浏览器自带
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
重绘(Repaint)
在浏览器中,重绘指的是改变样式不影响它在文档流中的位置(不影响元素布局,例如,修改颜等..)
重排(回流)(ReFlow)
重排意味着,因为某个元素的布局改变,导致其他元素的位置改变,所以其他元素也要重新绘制
动画为什么会卡?
理想总是很丰满,但现实很残酷。
我们知道,在同一个渲染进程中,存在JS线程
和GUI线程
,JS线程负责执行JS代码,GUI线程负责渲染页面(这里是渲染而不是绘制,绘制由浏览器进程完成)。
因为JS
是可以操作DOM
的,如果JS
线程和GUI
线程同时执行,那么渲染线程前后获得的元素可能就不一致了
所以JS
执行和页面渲染是互斥的,如果JS
执行时间过长,就会导致页面动画卡顿。
试想一下,假如我用js改变某一个DOM元素的高度,我希望每100ms增加1px
let count = 100
setInterval(() => {
app.style.height = (count++) + 'px'
},100)
有两个问题产生:
JS
有可能长时间占据主线程(还有其它事要做),假设JS
一直占据500ms
,那么就意味着JS
操作元素增加10px
才渲染新的一帧,那么页面动画看起来就卡卡的,感觉元素在瞬间移动,而不是慢慢过渡- 定时器不准确,导致
JS
没有在合适的时间内改变元素属性
第一个问题可以通过Web Workers
解决,把无关Dom
操作的耗时操作放到Web Workers
中
第二个问题,就可以通过requestAnimationFrame
解决
requestAnimationFrame()
里面的回调函数不是立即执行,而是绘制的前一时刻由浏览器调用执行,因为实际上requestAnimationFrame
是一个宏任务。此外次API专属于浏览器,不能在NodeJs环境运行(Node没有GUI,也就不会有此API)。
和定时器一样,因为调用完了就销毁,所以只调用一次requestAnimationFrame
就只执行一次
所以该函数一般来说最多每秒执行60次(如果屏幕刷新率是60HZ)
渲染下一帧就会调用animate函数 类似setTimeout定时器
//---------------------------------浏览器没刷新一帧就执行渲染一次---------------------------------------
function render() {
//获取时钟运行总时长 获取的单位都是秒
let time=clock.getElapsedTime()
//两次获取时间的间隔查,两帧之前的差
// let delta=clock.getDelta()
console.log('获取时钟运行总时长:',time)
//console.log('两次获取时间(time)间隔:',delta)
let t = time % 5
cube.position.x = t * 1
renderer.render(scene, camera);
//--------------------浏览器自带,渲染下一帧就会调用animate函数 类似setTimeout定时器--------------------------------
//此方法会默认传一个时间参数
requestAnimationFrame(render);
}
//---------------------------------浏览器没刷新一帧就执行渲染一次---------------------------------------
// function render(time) {
// //console.log(time)
// //===================时间=================
// //利用余数做循环
// let t = (time / 1000) % 5
// //------------动画效果 保持均速 路程=速度x时间-----------------
// cube.position.x = t * 1
// // if (cube.position.x > 5) {
// // cube.position.x = 0
// // }
// //---------------旋转动画------------------------------
// cube.rotation.x += 0.01
// //------------通过相机将场景渲染进来---------------------
// renderer.render(scene, camera);
// //--------------------浏览器自带,渲染下一帧就会调用animate函数 类似setTimeout定时器--------------------------------
// //此方法会默认传一个时间参数
// requestAnimationFrame(render);
// }
render();
demo01
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
//创建场景
const scene = new THREE.Scene();
console.log("hello");
console.log(scene);
//创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
//相机位置 xyz坐标
camera.position.set(0, 0, 10);
//相机添加到场景当中
scene.add(camera);
//添加物体到场景
//创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//材质,颜色
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
//根据几何体和材质创建物体
const cube = new THREE.Mesh(geometry, material);
//---------------------物体移动 三维向量(Vector3)-------------------------------
//修改物体位置方法
//cube.position.set(5,0,0)
//直接修改属性
cube.position.x = 3
//---------------------------------设置物体缩放-------------------------------
//改变物体形态,x轴变长3倍,y轴2倍,x轴1倍,由正方体变成长方体 x-长,y-高,z-宽
//cube.scale.set(3,2,1)
//cube.scale.x=5
//-------------------rotation 旋转------------------------------------
//Math.PI=180度,最后一个参数旋转顺序
cube.rotation.set(Math.PI / 4, 0, 0, "XZY")
//添加场景当中
scene.add(cube);
//初始化渲染器
const renderer = new THREE.WebGLRenderer();
//设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
//将webgl渲染的canvas 渲染到body上
document.body.appendChild(renderer.domElement);
//------------------------------------------使用渲染器,通过相机将场景渲染进来---------------------------
//renderer.render(scene,camera);
//--------------------------------------添加坐标轴辅助器----------------------------------
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
//----------------------------创建轨道控制器,相机围绕物体转动----------------------------------------
const controls = new OrbitControls(camera, renderer.domElement);
//使用three.js的clock时钟处理动画
const clock=new THREE.Clock()
//---------------------------------浏览器没刷新一帧就执行渲染一次---------------------------------------
function render() {
//获取时钟运行总时长 获取的单位都是秒
let time=clock.getElapsedTime()
//两次获取时间的间隔查,两帧之前的差
// let delta=clock.getDelta()
console.log('获取时钟运行总时长:',time)
//console.log('两次获取时间(time)间隔:',delta)
let t = time % 5
cube.position.x = t * 1
renderer.render(scene, camera);
//--------------------浏览器自带,渲染下一帧就会调用animate函数 类似setTimeout定时器--------------------------------
//此方法会默认传一个时间参数
requestAnimationFrame(render);
}
//---------------------------------浏览器没刷新一帧就执行渲染一次---------------------------------------
// function render(time) {
// //console.log(time)
// //===================时间=================
// //利用余数做循环
// let t = (time / 1000) % 5
// //------------动画效果 保持均速 路程=速度x时间-----------------
// cube.position.x = t * 1
// // if (cube.position.x > 5) {
// // cube.position.x = 0
// // }
// //---------------旋转动画------------------------------
// cube.rotation.x += 0.01
// //------------通过相机将场景渲染进来---------------------
// renderer.render(scene, camera);
// //--------------------浏览器自带,渲染下一帧就会调用animate函数 类似setTimeout定时器--------------------------------
// //此方法会默认传一个时间参数
// requestAnimationFrame(render);
// }
render();
Demo2 使用gsap动画库
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
//导入动画库gsap
import gsap from 'gsap'
//创建场景
const scene = new THREE.Scene();
//创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
//相机位置 xyz坐标
camera.position.set(0, 0, 10);
//相机添加到场景当中
scene.add(camera);
//添加物体到场景
//创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//材质,颜色
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
//根据几何体和材质创建物体
const cube = new THREE.Mesh(geometry, material);
//---------------------物体移动 三维向量(Vector3)-------------------------------
//修改物体位置方法
//cube.position.set(5,0,0)
//---------------------------------设置物体缩放-------------------------------
//改变物体形态,x轴变长3倍,y轴2倍,x轴1倍,由正方体变成长方体 x-长,y-高,z-宽
//cube.scale.set(3,2,1)
//cube.scale.x=5
//-------------------rotation 旋转------------------------------------
//Math.PI=180度,最后一个参数旋转顺序
cube.rotation.set(Math.PI / 4, 0, 0, "XZY")
//添加场景当中
scene.add(cube);
//初始化渲染器
const renderer = new THREE.WebGLRenderer();
//设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
//将webgl渲染的canvas 渲染到body上
document.body.appendChild(renderer.domElement);
//------------------------------------------使用渲染器,通过相机将场景渲染进来---------------------------
//renderer.render(scene,camera);
//--------------------------------------添加坐标轴辅助器----------------------------------
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
//----------------------------创建轨道控制器,相机围绕物体转动----------------------------------------
const controls = new OrbitControls(camera, renderer.domElement);
//=================设置控制器阻尼(惯性),让控制器有更真实的效果, 必须在动画循环调用.update()==========