查看原文
其他

《Web 3D来了!体验不一样的春节活动》——技术篇

腾讯P&Pdesign 腾讯PPdesign 2020-08-24

在2020年春节来临之际,我们WeGame推出春节促销活动。随着 CINEMA 4D 越来越被设计师普及,3D逐渐成为了当前的一种设计趋势,相比于平面页面,3D能给用户带来更真实的交互场景从而获得更好的体验。最近我们也有了一定的3D技术储备,因此将Web 3D技术应用到了在此次春节活动中。



  项目展示  

Web 3D相比传统2D展示氛围及带入感更强。我们使用的是threeJS库,完成threejs 3D微场景搭建的同时丰富页面中的交互,增强场景春节氛围感。

项目体验地址(PC端):

https://test.mwegame.qq.com/ui/act/wegame/act-pc/wegame-20191224-newyear/server/



  关键技术  
在进入场景时我们需要控制摄像机的轨迹来达到环视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主要攻克技能点

1、根据rgb主站场景进行点击曲线路径控制

2、3D雪花氛围效果

3、模型效果测试反馈

4、根据实际3D场景效果进行交互优化

5、物体的圆形运动轨迹

6、模型贴图与模型动画控制

7、将雪花效果改成漂浮动画z

8、云动画 + 简单漂浮动画


后期功能完善

1、模型还原、交互还原

2、入场动画

3、场景增加文字信息

4、模型加载与引导动画

5、性能测试准备


参考文档

1、模型外发光及模型禁止反光材质(外发光效果):
https://segmentfault.com/a/1190000019449497
2、实现出光源效果:
https://threejs.org/examples/?q=light#webgl_lights_spotlights
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/#webgl_points_sprites

(对Web3D技术感兴趣欢迎留言探讨~)
⬆️

——扫码关注P&P Design,看更多设计分享——

Modified on

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存