1.render loop中使场景产生动画
可以在循环中使用 requestAnimationFrame
函数,这样如果场景发生变化这会立即生效
// render 循环
function render() {
requestAnimationFrame(render);
// 渲染场景
renderer.render(scene, camera);
}
2.插入动画库
实例:多面体顶点动画
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
const colors = [0x05A8AA, 0xB8D5B8, 0xD7B49E, 0xDC602E,
0xBC412B, 0xF19C79, 0xCBDFBD, 0xF6F4D2, 0xD4E09B, 0xFFA8A9,
0xF786AA, 0xA14A76, 0xBC412B, 0x63A375, 0xD57A66, 0x731A33,
0xCBD2DC, 0xDBD48E, 0x5E5E5E];
let scene,
camera,
renderer,
geometry,
mesh;
let verticePositions = [];
// 初始化场景
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(30, WIDTH/HEIGHT, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
camera.position.z = 100;
}
// 初始化灯光
function initLight() {
// 很多光源
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 0, 1, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( 0, -1, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 1, 0, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( 0, 0, 1 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 0, 0, -1 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( -1, 0, 0 );
scene.add( light );
}
// 初始化模型
function initGeometry() {
// 添加多面体
// icosahedron 二十面体的意思 当实际表示多面体
geometry = new THREE.IcosahedronGeometry(20);
geometry.faces.forEach((face, i) => {
face.color.setHex(colors[i]);
});
mesh = new THREE.Mesh(
geometry,
new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors })
);
scene.add(mesh);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
// 自适应屏幕resize
function resize() {
camera.aspect = WIDTH/HEIGHT;
// 更新投射矩阵
camera.updateProjectionMatrix();
renderer.setSize(WIDTH, HEIGHT);
}
initScene();
initLight();
initGeometry();
render();
window.addEventListener('resize', resize);
新的知识点:
-
geometry.faces
属性 -
face.color.setHex(colors[i])
设置面颜色 new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors })
-
camera.updateProjectionMatrix()
更新投影矩阵
现在我们有了模型的顶点list,接着我们将随机的改变这些顶点和原始位置的距离。首先我们先将原来多面体的位置存储下来:
function getOriginalVerticePosition() {
geometry.vertices((vertice, i) => {
verticePositions.push({
x: vertice.x,
y: vertice.y
});
})
}
获取模型顶点信息:
geometry.vertices[i].x
gemotry.vertices[i].y
现在可以改变顶点位置,现在使用 GSAP
动画库:
function getNewVertices() {
// 这个函数返回一个相对原顶点数据的随机顶点位置的数组
let newVertices = []
geometry.vertices.forEach((vertice, i) => {
newVertices[i] = {
x: verticePositions[i].x - 5 + Math.random()*10,
y: verticePositions[i].y - 5 + Math.random()*10,
}
});
return newVertices;
}
function tweenVertice(i, newVerticePositions) {
// 设置动画
TweenLite.to(geometry.vertices[i], 1, {
x: newVerticePositions[i].x,
y: newVerticePositions[i].y,
ease: Back.easeInOut,
onComplete: function() {
if (i === 0) {
// 当动画完成时 再次开始动画
tweenIcosohedron();
}
}
})
}
// 开始多面体动画
function tweenIcosohedron() {
let newVerticePositions = getNewVertices();
geometry.vertices.forEach((vertice, i) => {
tweenVertice(i, newVerticePositions);
});
}
initScene();
initLight();
initGeometry();
resize();
getOriginalVerticePositions(); // 获取原始模型顶点信息
// console.log('current',verticePositions )
render();
window.addEventListener('resize', resize);
// 开始动画
tweenIcosohedron();
需要注意的是,上面的动画使用了动画库:
另外还可以将模型进行旋转:
function tweenIcosohedron() {
// 创建一个随机的旋转量
let rotation = {
x: Math.random() * 3,
y: Math.random() * 3,
z: Math.random() * 3
};
TweenLite.to(
mesh.rotation,
1,
{
x: rotation.x,
y: rotation.y,
z: rotation.z,
ease: Back.easeInOut,
onComplete: tweenIcosohedron
},
);
let newVerticePositions = getNewVertices();
geometry.vertices.forEach((vertice, i) => {
tweenVertice(i, newVerticePositions);
})
}
完整代码:
const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;
const colors = [0x05A8AA, 0xB8D5B8, 0xD7B49E, 0xDC602E,
0xBC412B, 0xF19C79, 0xCBDFBD, 0xF6F4D2, 0xD4E09B, 0xFFA8A9,
0xF786AA, 0xA14A76, 0xBC412B, 0x63A375, 0xD57A66, 0x731A33,
0xCBD2DC, 0xDBD48E, 0x5E5E5E];
let scene,
camera,
renderer,
geometry,
mesh;
// 用于存储模型顶点信息
let verticePositions = [];
// 初始化场景
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(30, WIDTH/HEIGHT, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
camera.position.z = 100;
}
// 初始化灯光
function initLight() {
// 很多光源
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 0, 1, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( 0, -1, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 1, 0, 0 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( 0, 0, 1 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 0, 0, -1 );
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff, 0.5 );
light.position.set( -1, 0, 0 );
scene.add( light );
}
// 初始化模型
function initGeometry() {
// 添加多面体
// icosahedron 二十面体的意思 当实际表示多面体
geometry = new THREE.IcosahedronGeometry(20);
geometry.faces.forEach((face, i) => {
face.color.setHex(colors[i]);
});
mesh = new THREE.Mesh(
geometry,
new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors })
);
scene.add(mesh);
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
geometry.verticesNeedUpdate = true;
}
// 自适应屏幕resize
function resize() {
camera.aspect = WIDTH/HEIGHT;
// 更新投射矩阵
camera.updateProjectionMatrix();
renderer.setSize(WIDTH, HEIGHT);
}
// 获取模型原来的顶点信息
function getOriginalVerticePositions() {
geometry.vertices.forEach((vertice, i) => {
verticePositions.push({
x: vertice.x,
y: vertice.y
});
})
}
// 创建新的顶点信息
function getNewVertices() {
// 这个函数返回一个相对原顶点数据的随机顶点位置的数组
let newVertices = []
geometry.vertices.forEach((vertice, i) => {
newVertices[i] = {
x: verticePositions[i].x - 5 + Math.random()*10,
y: verticePositions[i].y - 5 + Math.random()*10,
}
});
return newVertices;
}
// function tweenIcosohedron() {
// let newVerticePositions = getNewVertices();
// geometry.vertices.forEach((vertice, i) => {
// tweenVertice(i, newVerticePositions);
// });
// }
function tweenIcosohedron() {
// 创建一个随机的旋转量
let rotation = {
x: Math.random() * 3,
y: Math.random() * 3,
z: Math.random() * 3
};
TweenLite.to(
mesh.rotation,
1,
{
x: rotation.x,
y: rotation.y,
z: rotation.z,
ease: Back.easeInOut,
onComplete: tweenIcosohedron
},
);
let newVerticePositions = getNewVertices();
geometry.vertices.forEach((vertice, i) => {
tweenVertice(i, newVerticePositions);
})
}
// 开始动画
function tweenVertice(i, newVerticePositions) {
// 设置动画
// console.log('hh', geometry.vertices[i])
TweenLite.to(
geometry.vertices[i],
1,
{
x: newVerticePositions[i].x,
y: newVerticePositions[i].y,
ease: Back.easeInOut,
onComplete: function() {
if (i === 0) {
// 当动画完成时 再次开始动画
tweenIcosohedron();
}
}
}
)
}
initScene();
initLight();
initGeometry();
resize();
getOriginalVerticePositions(); // 获取原始模型顶点信息
// console.log('current',verticePositions )
render();
window.addEventListener('resize', resize);
// 开始动画
tweenIcosohedron();