【第1879期】《Web 3D来了!体验不一样的春节活动》技术篇
前言
Web 3D有点打开另一扇门了。今日早读文章由@腾讯PPdesign授权分享。
@P&PDesign全称Platform & Publish Design,隶属于腾讯互动娱乐发行线下的设计中心,团队由视觉、交互、多媒体、UI开发人才构成,负责为腾讯游戏平台体系和发行业务提供体验和服务设计,包括WeGame平台、QQ游戏平台、游戏本地化设计、端游手游助手、移动社区等业务;致力于游戏平台、UI、社区设计领域的研究和沉淀
正文从这开始~~
在2020年春节来临之际,我们WeGame推出春节促销活动。随着 CINEMA 4D 越来越被设计师普及,3D逐渐成为了当前的一种设计趋势,相比于平面页面,3D能给用户带来更真实的交互场景从而获得更好的体验。最近我们也有了一定的3D技术储备,因此将Web 3D技术应用到了在此次春节活动中。
项目展示
Web 3D相比传统2D展示氛围及带入感更强。我们使用的是threeJS库,完成threejs 3D微场景搭建的同时丰富页面中的交互,增强场景春节氛围感。
体验活动,请到文末通过“阅读原文”查看
关键技术
在进入场景时我们需要控制摄像机的轨迹来达到环视3D模型的效果,这一效果需要通过弧度算取欧拉角旋转来实现的。(如下图摄像机运动轨迹的曲线绘制方法,坐标v0为3D模型)
1、如何通过两点计算出运动轨迹
计算三维向量中心点坐标:
代码
/**
* @desc 获取两个向量之间的中心点坐标
* @param {Object} v1 向量1
* @param {Object} v2 向量2
*/
getVectorCenter: function(v1, v2){
/**
* [add] [divideScalar] 均为Vector3自带方法函数
*
* 公式:
* x = (x1 + x2) / 2
* y = (y1 + y2) / 2
*/
var v1c = v1.clone();
var v2c = v2.clone();
return v1c.add(v2c).divideScalar(2);
}
其中Vector3中提供基础方法
根据圆心和中心点坐标,得到一个点的射线:
代码
// 通过Ray,得到射线段
var rayLine = new THREE.Ray(new THREE.Vector3(0,0,0), vectorCenter)
// 在射线段先随意定义一个射线顶点
// at可以设置射线的距离,并且返回Vector3坐标
// rayLine.at(1) == vectorCenter, 将向量中心点距离圆心长度 * n
var vtop = rayLine.at(10)
根据射线顶点 + 起始点与终点坐标,可以随意选取线段内的控制点坐标:
根据起始点+终点+控制点坐标,可以绘制贝塞尔曲线,仍然存在几个优化点:
当起点与终点象限重合时,仍然会被绘制曲线
即使通过两点获得出一条曲线后,会发现相机在位置1时,移动的路径可能不会出现问题,但是相机在位置2的时候,此时相机2距离视点位置较近,不需要作曲线。
解决方法
获得相机位置点到视点的直线距离,再减去半径获得差值,当差值小于0时,代表相机位置距离视点小于半径则直接做直线运动,再用差值除以直径就获得出比例。
var len = starPos.distanceTo(endPos) - three3D.radius <= 0 ? 0 : starPos.distanceTo(endPos) - three3D.radius;
var ratio = len / ( three3D.radius * 2 ) <= 1 ? len / ( three3D.radius * 2 ) : 1;
2、雪花效果
春节活动在冬天,因此我们需要雪花来衬托冬天的氛围。制作3D下雪场景需要如下几个步骤:
2.1 首先需要制作一个雪花的3D模型
使用的图片材质:
制作一个雪花3D模型代码:
var texture = new THREE.TextureLoader().load("./images/snow0.png");
//样式化粒子的THREE.PointCloudMaterial材质
var material = new THREE.PointsMaterial({
size: size,
transparent: transparent,
opacity: opacity,
vertexColors: vertexColors,
sizeAttenuation: sizeAttenuation,
color: color,
map: texture,
depthTest: false //设置解决透明度有问题的情况
});
2.2 随机生成多个雪花的坐标
var cloud;
var geom = new THREE.Geometry(); //存放粒子数据的网格
var range = 2400; //生成雪花的坐标范围
for (var i = 0; i < 700; i++) { //生成700个雪花
//添加顶点的坐标
var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2);
particle.velocityY = (0.1 + Math.random() / 5) * 20;
particle.velocityX = ((Math.random() - 0.5) / 3) * 10;
particle.velocityZ = ((Math.random() - 0.5) * 3) * 10;
geom.vertices.push(particle);
var color = new THREE.Color(0xffffff);
geom.colors.push(color);
}
//生成模型,添加到场景当中
cloud = new THREE.Points(geom, material);
cloud.verticesNeedUpdate = true;
scene.add(cloud);
2.3 雪花飘落动画
Snow.prototype.snowRender = function () {
//产生雪动画效果
var vertices = cloud.geometry.vertices;
vertices.forEach(function (v, index) {
v.y = v.y - (v.velocityY) * .3;
v.x = v.x - (v.velocityX) * .05;
v.z = v.z - (v.velocityZ) * .05;
if (v.y <= -1200) v.y = 1200;
if (v.x <= -400 || v.x >= 400) v.velocityX = v.velocityX * -0.1;
if (v.z <= -400 || v.z >= 400) v.velocityZ = v.velocityZ * -0.1;
});
//设置实时更新网格的顶点信息
cloud.geometry.verticesNeedUpdate = true;
}
3、音乐动画
通过用欢快的音乐衬托出春节喜气洋洋的节日氛围。
代码
// 音符从小变大
var scaleSize,
endScale = 0.015;
if (obj.position.y > endCoord.y) {
scaleSize = 0;
} else if (obj.position.y < endCoord.y) {
scaleSize = ((obj.position.y - startCoord.y) / (endCoord.y - startCoord.y)) * endScale;
}
// 控制透明度
var opacityVal;
if (obj.position.y < startCoord.y + 3 || obj.position.y > endCoord.y) {
opacityVal = 0;
} else if (((startCoord.y + 3) <= obj.position.y) && (obj.position.y < (startCoord.y + 25))) {
opacityVal = 1;
}else {
opacityVal = 1 - ((obj.position.y - (startCoord.y + 25)) / (endCoord.y - startCoord.y - 25));
}
opacityVal = opacityVal > 0 ? opacityVal : 0
// 如果音符飘到顶,则重置回到初始值
if (obj.position.y > endCoord.y) {
obj.position.y = startCoord.y;
obj.position.z = startCoord.z;
obj.material.opacity = 0
}
4、全屏幕适配
设计稿为标准的1920px*1080px尺寸,但在小屏幕或笔记本下会出现内容显示不全的问题,给用户带来了不友好的体验。
以宽度1920px,高度1080px为参考基准,我们进行了全设备的兼容,步骤如下:
4.1、分析屏幕尺寸,以参考基础为标准,一共有五种情况:
A情况:“宽等于1920px,高等于1080px”,
B情况:“宽大于1920px,高大于1080px”
C情况:“宽小于1920px,高小于1080px”
D情况:“宽大于1920px,高小于1080px”
E情况:“宽小于1920px,高大于1080px”
核心点:获取当前浏览器尺寸。
4.2、根据不同屏幕尺寸情况进行整体缩放。
我们获取到此时浏览器实际宽高后,需要分辨出此时浏览器尺寸是“扁的”还是“高的”。
设置一个基准比例:
BaseRate = 1920/1080 = 1.777;
设置一个实时比例:
Rate = PageWidth/PageHeight;
所以,“扁的”情况为Rate > BaseRate,“高的”情况为 Rate < BaseRate。
核心点:获取出当前浏览器是“扁的”还是“高的”情况,并计算缩放比例系数。
4.3、通过比例系数进行缩放和内容重新定位。
当宽高都大于1920px*1080px时:不进行放大缩放,但要对内容进行垂直和水平居中定位。
当宽高都小于1920px*1080px时:
若为“扁的”情况:则需要对高度进行缩放,并且垂直居中。
若为“高的”情况:则需要对宽度进行缩放,并且水平居中。
同理,在各种情况下,我们需要对其缩放系数进行计算后进行缩放,同时还需要对内容进行垂直或水平方向的重新定位。
同时我们还需要使用window.onresize函数进行实时监听,保证用户在手动缩放浏览器大小的时候也能进行适配。
核心点:缩放后内容的重新定位,window.onresize函数的实时监听。
这样我们在各种屏幕大小下,都能满足非常好的用户阅读体验,保证用户在浏览页面的过程中全部信息的获取。
后期性能测试
测试目的:了解实际项目在Web3D中的性能影响,将数据提供给开发进行兼容处理。
测试机型:
根据测试提供的wegame用户机型配置数据来对比,此次测试主要分为三种机型配置 4G显存(中高配)、2G显存(中配)、1G显存(中低配)。
测试点:FPS、CPU、GPU与体验感受。
测试方向:1、页面首次载入数据。2、页面3D交互数据。
测试结果:
1、低配机器测试过程中GPU使用率在95%+,但是页面浏览流畅,并无明显卡顿感,FPS总体维持在35以上。在中配机器测试过程中GPU使用率平均在32%左右,页面流畅无卡顿,FPS维持在55左右。
2、通过3D场景的体验中发现,低配机器CPU平均占用在25%左右,在页面首次载入的时候,CPU占用会有2-3秒左右飙升到40%。中低配机器CPU平均占用在16%左右,首次载入时会有2-3秒飙升到37%。
测试总结:项目在测试过程中发现,在非客户端内嵌的情况下,基本都可以流畅的体验web3d,因此我们也放弃2d兼容方案。
项目优化
项目后期因增加了设计师提供的模型,使得项目资源大小增加了10M,因此采用Draco 压缩方案进行优化3d模型的资源大小。Draco是一个用于压缩、解压缩 3D 几何网格和点云的开源库,为改善 3D 图形存储和传输而设计。
使用draco可以对 glTF 格式进一步的压缩,原本10M的GLTF文件被压缩到1M。
以往使用视频方式做kv,通常会准备一个入场资格,循环视频,大小往往超过5m,此次春节活动仅仅只需要加载1M的模型即可。同时视频仅仅只能展示,而web3D方案交互性更加丰富。
项目总结
Web 3D主要攻克技能点
根据rgb主站场景进行点击曲线路径控制
3D雪花氛围效果
模型效果测试反馈
根据实际3D场景效果进行交互优化
物体的圆形运动轨迹
模型贴图与模型动画控制
将雪花效果改成漂浮动画z
云动画 + 简单漂浮动画
后期功能完善
模型还原、交互还原
入场动画
场景增加文字信息
模型加载与引导动画
性能测试准备
参考文档
1、模型外发光及模型禁止反光材质(外发光效果):https://segmentfault.com/a/1190000019449497 2、实现出光源效果:https://threejs.org/examples/?q=light#webgllightsspotlights 3、模型优化方案(使用draco方案进行压缩):https://threejs.org/docs/index.html#examples/zh/loaders/DRACOLoader 4、模型材质发光设置:https://segmentfault.com/a/1190000019449497 http://www.yanhuangxueyuan.com/doc/Three.js/MeshStandardMaterial.html https://threejs.org/docs/index.html#api/zh/materials/MeshStandardMaterial 5、雪花参考demo:https://threejs.org/examples/#webglpointssprites
关于本文 作者:@腾讯P&Pdesign 原文:https://mp.weixin.qq.com/s/AuM5naNxxYk1ko-SxJafSw
@腾讯PPdesign曾分享过
【第1800期】利用过渡动效打造沉浸式的体验 —【Web篇】
为你推荐
【第1876期】从构建进程间缓存设计 谈 Webpack5 优化和工作原理
体验活动,通过“阅读原文”查看