腾讯UP2017 3D 粒子效果在网页端demo分享
https://github.com/liunnn1994/TencentUp2017.git
这段时间加班累成狗,终于尾声了,水一篇提升一下百度活跃度。
点击 预览 先看一下效果。
使用常规的3D建模软件即可。拿到3D模型之后再进行处理,处理的软件使用的是Blender兼容性比较好的是fbx格式,然后通过给Blender安装插件之后,将模型转换为便于three.js读取的JSON格式。当然我并不会建模,所以直接从UP2017腾讯互动娱乐年度发布会 - 腾讯互动娱乐 上直接把粒子模型“偷”下来:
首先,初始化 threejs 三大元素:场景,相机,渲染器。我们需要一个用于切换的载体粒子体系和多个环境粒子体系(为了简单,在这只初始化了一个上下转动的环境粒子体系)。
camera = new THREE.PerspectiveCamera(105, window.innerWidth / window.innerHeight, 300, 10000);
camera.position.z = 750;
// 初始化场景
scene = new THREE.Scene();
//雾化
scene.fog = new THREE.FogExp2(0x05050c, 0.0005);
//初始化renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
// 初始化geometry
geometry = new THREE.Geometry();
around = new THREE.Geometry();
// 初始化贴图
const textureLoader = new THREE.TextureLoader();
// 圆点
const mapDot = textureLoader.load('assets/gradient.png');
初始化载体粒子体系:载体粒子体系的粒子数量要比所有模型的顶点数量的最大值还要大,这样才能保证切换到每一个模型,都不会出现缺失的情况,而多余的点呢就让他们从头开始重叠好了。当然不是越多越好,我的电脑是MBP2018,20000的时候就开始力不从心了,30000直接无响应
for (let i = 0; i < 15000; i++) {
const vertex = new THREE.Vector3();
vertex.x = 800 * Math.random() - 400;
vertex.y = 800 * Math.random() - 400;
vertex.z = 800 * Math.random() - 400;
geometry.vertices.push(vertex);
geometry.colors.push(new THREE.Color(255, 255, 255));
}
material = new THREE.PointsMaterial({ size: 4, sizeAttenuation: true, color: 0xffffff, transparent: true, opacity: 1, map: mapDot });
material.vertexColors = THREE.VertexColors;
particles = new THREE.Points(geometry, material);
scene.add(particles);
将获取到的 3D 模型,通过 JSONLoader 加载后,得到的 geometry 对象放入一个数组 glist 中,用于模型切换。
加载模型 loadObject:
新版的threejs在r98 → r99的时候废弃了JSONLoader,模型在网站也比较久了,ObjectLoader也不能加载,所以要么使用旧版的,要么单独下载JSONLoader。
WebGLRenderTarget.texture.generateMipmaps is now set to false by default.SSAOShader and SSAOPass.JSONLoader has been removed from core. It is now located in examples/js/loaders/deprecated/LegacyJSONLoader.js.Geometry support from ObjectLoader. You have to include LegacyJSONLoader if you still want to load geometry data of type Geometry.Geometry support from SkinnedMesh. Use BufferGeometry instead.SkinnedMesh.initBones(). The SkinnedMesh constructor does not build the bone hierarchy anymore. You have to do this by yourself and then call SkinnedMesh.bind() in order to bind the prepared skeleton.three.min.js和LegacyJSONLoader:
<script src="./js/three.min.js"></script>
<script src="./js/LegacyJSONLoader.js"></script>
加载模型 loadObject:
const loader = new THREE.LegacyJSONLoader();
loader.load('assets/qr.json', function (geo, materials) {
geo.center();
geo.normalize();
geo.scale(800, 800, 800);
glist.push(geo);
});
function onDocumentMouseMove(event) {
if (!canMouseMove) {
return false;
};
geometry.rotateY((event.pageX - mouseX) / 2000 * 2 * Math.PI);
geometry.rotateX((event.pageY - mouseY) / 2000 * 2 * Math.PI);
event.preventDefault();
mouseX = event.pageX;
mouseY = event.pageY;
};
function onDocumentMouseWheel(e) {
canMouseMove = false;
if (flag) {
return false;
};
e.deltaY > 0 ? objIndex++ : objIndex--;
if (objIndex > 4) {
objIndex = 0;
} else if (objIndex < 0) {
objIndex = 4;
};
tweenObj(objIndex);
flag = true;
};
function onDocumentTouchStart() {
canMouseMove = false;
if (flag) {
return false;
};
objIndex++;
if (objIndex > 4) {
objIndex = 0;
};
tweenObj(objIndex);
flag = true;
};
使用的tweenjs
function tweenObj(index) {
let ani = null;
geometry.vertices.forEach(function (e, i, arr) {
ani = new TWEEN.Tween(e);
const length = glist[index].vertices.length;
const o = glist[index].vertices[i % length];
ani.to({
x: o.x,
y: o.y,
z: o.z
}, 1000).easing(TWEEN.Easing.Exponential.In).delay(400 * Math.random()).start();
});
//动画完成时的回调
ani.onComplete(function (params) {
canMouseMove = true;
flag = false;
});
};
使用tween.delay(animationDuration*Math.random());是动画不那么生硬。
渲染整个画面:
%%CODEBLOCK6%%
TWEEN.update()和 geometry.verticesNeedUpdate = true 共同决定了粒子体系切换动画可以展示出来。
还有很多地方不完善:
composer,这里用的是alteredq的一系列EffectComposer,包括过亮效果、暗角、电视效果等。KV的动画没有实现裙边的效果。map设置为null即可是方形(没有纹理默认方形)。new THREE.PointsMaterial({
...
map: null, //texture
...
});
vertex shader性能可能更好,感觉好高深,等大神踩踩坑。参考链接:
> 1. threejs+tweenjs实现3D粒子模型切换。
2. 3D粒子效果在网页端实现分享。