范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

还没抢到冰墩墩?没关系,教你用代码实现一个

  《开源精选》是我们分享Github、Gitee等开源社区中优质项目的栏目,包括技术、学习、实用与各种有趣的内容。本期推荐的是一个使用Three.js 实现的2022冬奥主题3D趣味页面——Olympic。
  本项目使用 Three.js + React  技术栈,实现冬日和奥运元素,制作了一个充满趣味和纪念意义的冬奥主题 3D 页面。本文涉及到的知识点主要包括: TorusGeometry  圆环面、 MeshLambertMaterial  非光泽表面材质、 MeshDepthMaterial  深度网格材质、 custromMaterial  自定义材质、 Points  粒子、 PointsMaterial  点材质等。
  效果
  实现效果如以下 动图所示,页面主要由 2022 冬奥会吉祥物 冰墩墩 、奥运五环、舞动的旗帜 、树木 以及下雪效果   等组成。按住鼠标左键移动可以改为相机位置,获得不同视图。
  在线预览地址:https://dragonir.github.io/3d/#/olympic(部署在 GitHub,加载速度可能会有点慢 )
  实现过程
  1 引入资源
  首先引入开发页面所需要的库和外部资源, OrbitControls  用于镜头轨道控制、 TWEEN  用于补间动画实现、 GLTFLoader  用于加载 glb  或 gltf  格式的3D模型、以及一些其他模型、贴图等资源。 import React from "react"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import bingdundunModel from "./models/bingdundun.glb"; // ...
  2 页面DOM结构
  页面 DOM  结构非常简单,只有渲染3D元素的 #container  容器和显示加载进度的 .olympic_loading  元素。       {this.state.loadingProcess === 100 ? "" : (            {this.state.loadingProcess} %        )}
  3 场景初始化
  初始化渲染容器、场景、相机。 container = document.getElementById("container"); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; container.appendChild(renderer.domElement); scene = new THREE.Scene(); scene.background = new THREE.TextureLoader().load(skyTexture); camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 30, 100); camera.lookAt(new THREE.Vector3(0, 0, 0));
  4 添加光源
  本示例中主要添加了两种光源: DirectionalLight  用于产生阴影,调节页面亮度、 AmbientLight  用于渲染环境氛围。 // 直射光 const light = new THREE.DirectionalLight(0xffffff, 1); light.intensity = 1; light.position.set(16, 16, 8); light.castShadow = true; light.shadow.mapSize.width = 512 * 12; light.shadow.mapSize.height = 512 * 12; light.shadow.camera.top = 40; light.shadow.camera.bottom = -40; light.shadow.camera.left = -40; light.shadow.camera.right = 40; scene.add(light); // 环境光 const ambientLight = new THREE.AmbientLight(0xcfffff); ambientLight.intensity = 1; scene.add(ambientLight);
  5 加载进度管理
  使用 THREE.LoadingManager  管理页面模型加载进度,在它的回调函数中执行一些与加载进度相关的方法。本例中的页面加载进度就是在 onProgress  中完成的,当页面加载进度为 100%  时,执行 TWEEN   镜头补间动画。 const manager = new THREE.LoadingManager(); manager.onStart = (url, loaded, total) => {}; manager.onLoad = () => { console.log("Loading complete!")}; manager.onProgress = (url, loaded, total) => {   if (Math.floor(loaded / total * 100) === 100) {     this.setState({ loadingProcess: Math.floor(loaded / total * 100) });     // 镜头补间动画     Animations.animateCamera(camera, controls, { x: 0, y: -1, z: 20 }, { x: 0, y: 0, z: 0 }, 3600, () => {});   } else {     this.setState({ loadingProcess: Math.floor(loaded / total * 100) });   } };
  6 创建地面
  本示例中凹凸起伏的地面是使用 Blender  构建模型,然后导出 glb  格式加载创建的。当然也可以直接使用 Three.js  自带平面网格加凹凸贴图也可以实现类似的效果。使用 Blender  自建模型的优点在于可以自由可视化地调整地面的起伏效果。 var loader = new THREE.GLTFLoader(manager); loader.load(landModel, function (mesh) {   mesh.scene.traverse(function (child) {     if (child.isMesh) {       child.material.metalness = .1;       child.material.roughness = .8;       // 地面       if (child.name === "Mesh_2") {         child.material.metalness = .5;         child.receiveShadow = true;       }   });   mesh.scene.rotation.y = Math.PI / 4;   mesh.scene.position.set(15, -20, 0);   mesh.scene.scale.set(.9, .9, .9);   land = mesh.scene;   scene.add(land); });
  7 创建冬奥吉祥物冰墩墩
  现在添加可爱的冬奥会吉祥物熊猫冰墩墩 ,冰墩墩同样是使用 glb  格式模型加载的。它的原始模型是使用 3D max  建的,但并不能直接用在网页中,需要在 Blender  中转换模型格式,还需要调整调整模型的贴图法线,才能还原渲染图效果。
  原模型:
  冰墩墩贴图:
  转换成Blender支持的模型,并在Blender中调整模型贴图法线、并添加贴图:
  导出glb格式:
  在 Blender 中给模型添加贴图教程传送门:https://jingyan.baidu.com/article/363872ecf6367f2f4ba16f95.html
  仔细观察冰墩墩 可以发现,它的外面有一层透明塑料或玻璃质感外壳,这个效果可以通过修改模型的透明度、金属度、粗糙度等材质参数实现,最后就可以渲染出如  banner图  所示的那种效果,具体如以下代码所示。 loader.load(bingdundunModel, mesh => {   mesh.scene.traverse(child => {     if (child.isMesh) {       // 内部       if (child.name === "oldtiger001") {         child.material.metalness = .5         child.material.roughness = .8       }       // 半透明外壳       if (child.name === "oldtiger002") {         child.material.transparent = true;         child.material.opacity = .5         child.material.metalness = .2         child.material.roughness = 0         child.material.refractionRatio = 1         child.castShadow = true;       }     }   });   mesh.scene.rotation.y = Math.PI / 24;   mesh.scene.position.set(-8, -12, 0);   mesh.scene.scale.set(24, 24, 24);   scene.add(mesh.scene); });
  8 创建奥运五环
  奥运五环由基础几何模型圆环面 TorusGeometry  来实现,创建五个圆环面,并调整它们的材质颜色和位置来构成 蓝黑红黄绿 顺序的五环结构。五环材质使用的是 MeshLambertMaterial   。 const fiveCycles = [   { key: "cycle_0", color: 0x0885c2, position: { x: -250, y: 0, z: 0 }},   { key: "cycle_1", color: 0x000000, position: { x: -10, y: 0, z: 5 }},   { key: "cycle_2", color: 0xed334e, position: { x: 230, y: 0, z: 0 }},   { key: "cycle_3", color: 0xfbb132, position: { x: -125, y: -100, z: -5 }},   { key: "cycle_4", color: 0x1c8b3c, position: { x: 115, y: -100, z: 10 }} ]; fiveCycles.map(item => {   let cycleMesh = new THREE.Mesh(new THREE.TorusGeometry(100, 10, 10, 50), new THREE.MeshLambertMaterial({     color: new THREE.Color(item.color),     side: THREE.DoubleSide   }));   cycleMesh.castShadow = true;   cycleMesh.position.set(item.position.x, item.position.y, item.position.z);   meshes.push(cycleMesh);   fiveCyclesGroup.add(cycleMesh); }); fiveCyclesGroup.scale.set(.036, .036, .036); fiveCyclesGroup.position.set(0, 10, -8); scene.add(fiveCyclesGroup);
  TorusGeometry 圆环面:一个用于生成圆环几何体的类。
  构造函数: TorusGeometry(radius: Float, tube: Float, radialSegments: Integer, tubularSegments: Integer, arc: Float) radius  :圆环的半径,从圆环的中心到管道(横截面)的中心。默认值是 1  tube  :管道的半径,默认值为 0.4  radialSegments  :圆环的分段数,默认值为 8  tubularSegments  :管道的分段数,默认值为 6  arc  :圆环的圆心角(单位是弧度),默认值为 Math.PI * 2
  MeshLambertMaterial 非光泽表面材质:一种非光泽表面的材质,没有镜面高光。该材质使用基于非物理的 Lambertian  模型来计算反射率。这可以很好地模拟一些表面(例如未经处理的木材或石材),但不能模拟具有镜面高光的光泽表面(例如涂漆木材)。
  构造函数: MeshLambertMaterial(parameters : Object) parameters  :(可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入
  9 创建旗帜
  旗面模型是从 sketchfab  下载的,还需要一个旗杆,可以在 Blender  中添加了一个柱状立方体,并调整好合适的长宽高和旗面结合起来。原本想把国旗贴图添加到旗帜模型上,但为了避免使用错误,造成敏感问题,于是使用 北京2022冬奥会 旗帜贴图了 。
  旗面贴图:
  旗面添加了动画,需要在代码中执行动画帧播放。 loader.load(flagModel, mesh => {   mesh.scene.traverse(child => {     if (child.isMesh) {       child.castShadow = true;       // 旗帜       if (child.name === "mesh_0001") {         child.material.metalness = .1;         child.material.roughness = .1;         child.material.map = new THREE.TextureLoader().load(flagTexture);       }       // 旗杆       if (child.name === "柱体") {         child.material.metalness = .6;         child.material.roughness = 0;         child.material.refractionRatio = 1;         child.material.color = new THREE.Color(0xeeeeee);       }     }   });   mesh.scene.rotation.y = Math.PI / 24;   mesh.scene.position.set(2, -7, -1);   mesh.scene.scale.set(4, 4, 4);   // 动画   let meshAnimation = mesh.animations[0];   mixer = new THREE.AnimationMixer(mesh.scene);   let animationClip = meshAnimation;   let clipAction = mixer.clipAction(animationClip).play();   animationClip = clipAction.getClip();   scene.add(mesh.scene); });
  10 创建树木
  为了充实画面,营造冬日氛围,于是就添加了几棵松树 作为装饰。添加松树的时候用到一个技巧非常重要:我们知道因为树的模型非常复杂,有非常多的面数,面数太多会降低页面性能,造成卡顿。本文中使用两个如下图 所示的两个交叉的面来作为树的基座,这样的话树只有两个面数,使用这个技巧可以和大程度上优化页面性能,而且树 的样子看起来也是有 3D 感的。
  材质贴图:
  为了使树只在贴图透明部分透明、其他地方不透明,并且可以产生树状阴影而不是长方体阴影,需要给树模型添加如下 MeshPhysicalMaterial  、 MeshDepthMaterial  两种材质,两种材质使用同样的纹理贴图,其中 MeshDepthMaterial  添加到模型的 custromMaterial  属性上。  let treeMaterial = new THREE.MeshPhysicalMaterial({   map: new THREE.TextureLoader().load(treeTexture),   transparent: true,   side: THREE.DoubleSide,   metalness: .2,   roughness: .8,   depthTest: true,   depthWrite: false,   skinning: false,   fog: false,   reflectivity: 0.1,   refractionRatio: 0, }); let treeCustomDepthMaterial = new THREE.MeshDepthMaterial({   depthPacking: THREE.RGBADepthPacking,   map: new THREE.TextureLoader().load(treeTexture),   alphaTest: 0.5 }); loader.load(treeModel, mesh => {   mesh.scene.traverse(child =>{     if (child.isMesh) {       child.material = treeMaterial;       child.custromMaterial = treeCustomDepthMaterial;     }   });   mesh.scene.position.set(14, -9, 0);   mesh.scene.scale.set(16, 16, 16);   scene.add(mesh.scene);   // 克隆另两棵树   let tree2 = mesh.scene.clone();   tree2.position.set(10, -8, -15);   tree2.scale.set(18, 18, 18);   scene.add(tree2)   // ... });
  实现效果也可以从 上面 Banner  图中可以看到,为了画面更好看,我取消了树的阴影显示。
  在 3D 功能开发中,一些不重要的装饰模型都可以采取这种策略来优化。
  MeshDepthMaterial 深度网格材质:一种按深度绘制几何体的材质。深度基于相机远近平面,白色最近,黑色最远。
  构造函数: MeshDepthMaterial(parameters: Object) parameters  :(可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入
  特殊属性:  .depthPacking[Constant]  : depth packing  的编码。默认为 BasicDepthPacking    .displacementMap[Texture]  :位移贴图会影响网格顶点的位置,与仅影响材质的光照和阴影的其他贴图不同,移位的顶点可以投射阴影,阻挡其他对象,以及充当真实的几何体  .displacementScale[Float]  :位移贴图对网格的影响程度(黑色是无位移,白色是最大位移)。如果没有设置位移贴图,则不会应用此值。默认值为 1  .displacementBias[Float]  :位移贴图在网格顶点上的偏移量。如果没有设置位移贴图,则不会应用此值。默认值为 0
  custromMaterial 自定义材质:给网格添加 custromMaterial  自定义材质属性,可以实现透明外围 png 图片贴图的内容区域阴影。
  11 创建雪花
  创建雪花  ,就要用到粒子知识。 THREE.Points  是用来创建点的类,也用来批量管理粒子。本例中创建了 1500  个雪花粒子,并为它们设置了限定三维空间的随机坐标及横向和竖向的随机移动速度。 // 雪花贴图 let texture = new THREE.TextureLoader().load(snowTexture); let geometry = new THREE.Geometry(); let range = 100; let pointsMaterial = new THREE.PointsMaterial({   size: 1,   transparent: true,   opacity: 0.8,   map: texture,   // 背景融合   blending: THREE.AdditiveBlending,   // 景深衰弱   sizeAttenuation: true,   depthTest: false }); for (let i = 0; i < 1500; i++) {   let vertice = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range * 1.5, Math.random() * range - range / 2);   // 纵向移速   vertice.velocityY = 0.1 + Math.random() / 3;   // 横向移速   vertice.velocityX = (Math.random() - 0.5) / 3;   // 加入到几何   geometry.vertices.push(vertice); } geometry.center(); points = new THREE.Points(geometry, pointsMaterial); points.position.y = -30; scene.add(points);
  Points 粒子:  Three.js  中,雨  、雪  、云  、星辰   等生活中常见的粒子都可以使用 Points 来模拟实现。
  构造函数: new THREE.Points(geometry, material);构造函数可以接受两个参数,一个几何体和一个材质,几何体参数用来制定粒子的位置坐标,材质参数用来格式化粒子 可以基于简单几何体对象如 BoxGeometry  、 SphereGeometry  等作为粒子系统的参数 一般来讲,需要自己指定顶点来确定粒子的位置
  PointsMaterial 点材质:通过 THREE.PointsMaterial  可以设置粒子的属性参数,是 Points  使用的默认材质。
  构造函数: PointsMaterial(parameters : Object) parameters  :(可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入
  材质属性 .blending:材质的.blending  属性主要控制纹理融合的叠加方式。
  .blending  属性的值包括:  THREE.NormalBlending  :默认值  THREE.AdditiveBlending  :加法融合模式  THREE.SubtractiveBlending  :减法融合模式  THREE.MultiplyBlending  :乘法融合模式  THREE.CustomBlending  :自定义融合模式,与 .blendSrc  ,  .blendDst  或 .blendEquation  属性组合使用
  材质属性 .sizeAttenuation:粒子的大小是否会被相机深度衰减,默认为 true  (仅限透视相机)。
  Three.js 向量:几维向量就有几个分量,二维向量 Vector2  有 x  和 y  两个分量,三维向量 Vector3  有x 、y 、z  三个分量,四维向量 Vector4  有 x 、y 、z 、w  四个分量。
  相关API:  Vector2  :二维向量  Vector3  :三维向量  Vector4  :四维向量
  12 镜头控制、缩放适配、动画 controls = new OrbitControls(camera, renderer.domElement); controls.target.set(0, 0, 0); controls.enableDamping = true; // 禁用平移 controls.enablePan = false; // 禁用缩放 controls.enableZoom = false; // 垂直旋转角度限制 controls.minPolarAngle = 1.4; controls.maxPolarAngle = 1.8; // 水平旋转角度限制 controls.minAzimuthAngle = -.6; controls.maxAzimuthAngle = .6;window.addEventListener("resize", () => {   camera.aspect = window.innerWidth / window.innerHeight;   camera.updateProjectionMatrix();   renderer.setSize(window.innerWidth, window.innerHeight); }, false);function animate() {   requestAnimationFrame(animate);   renderer.render(scene, camera);   controls && controls.update();   // 旗帜动画更新   mixer && mixer.update(new THREE.Clock().getDelta());   // 镜头动画   TWEEN && TWEEN.update();   // 五环自转   fiveCyclesGroup && (fiveCyclesGroup.rotation.y += .01);   // 顶点变动之后需要更新,否则无法实现雨滴特效   points.geometry.verticesNeedUpdate = true;   // 雪花动画更新   let vertices = points.geometry.vertices;   vertices.forEach(function (v) {     v.y = v.y - (v.velocityY);     v.x = v.x - (v.velocityX);     if (v.y <= 0) v.y = 60;     if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1;   }); }
  总结
  本文中主要包含的知识点包括:  TorusGeometry  圆环面  MeshLambertMaterial  非光泽表面材质  MeshDepthMaterial  深度网格材质  custromMaterial  自定义材质  Points  粒子  PointsMaterial  点材质 材质属性 .blending  、.sizeAttenuation    Three.js  向量
  进一步优化的空间: 添加更多的交互功能、界面样式进一步优化 吉祥物冰墩墩添加骨骼动画,并可以通过鼠标和键盘控制其移动和交互
  完整代码:https://github.com/dragonir/3d/tree/master/src/containers/Olympic

手机越来越不耐电,只是因为电池老化?或许还跟你这3种习惯有关对于现如今的人们来说,手机是一个具有重要作用的物件,毕竟人们的通讯社交以及多种生活服务都需要通过手机才能完成,手机不仅给人们带来了很大生活的便利,更提高了人们的生活效率。不过由于手机会来了,资金扎堆涌入自动驾驶赛道万亿元市值可期2月28日,自动驾驶卡车技术与运营公司嬴彻科技宣布已完成1。88亿美元的B轮股权融资。红杉中国君联资本联合领投,周大福沄柏资本物产中大集团美团蔚来资本斯道资本博华资本等跟投。嬴彻科自学5个月Java找到了9K的工作,我的方式值得大家借鉴我是去年9月22日才正式学习Java的,因为在国营单位工作了4年,在天津一个月工资只有5000块,而且看不到任何晋升的希望,如果想要往上走,那背后就一定要有关系才行。而且国营单位的想买二手苹果手机怕被坑?教你如何验机想买二手手机怕被坑,看这里就行啦二手手机到底应该怎么验?我花了10分钟写了下面的经验。常用软件爱思或者沙漏,可以从里面看出来问题一般大部分机器都会换电池和前后摄像头,这些都是正常的11。98万起售,搭载插电式混合动力,油耗1。2L,带你看缤越PHEV考虑到使用成本,购车预算,多数消费者都会考虑购买小排量车型,这也是为什么有的车型会推出1。5L1。6L1。2T1。3T1。4T小排量车型的原因。如今市场在向新能源靠拢,不断攻克新的beegovalidation简单使用直接使用packagemainimport(github。comastaxiebeegovalidationlog)typeUserstructNamestringAgeintfu重要!重要!JeecgBoot3。1。0版本发布,快来试试吧项目介绍JeecgBoot是一款企业级的低代码平台!前后端分离架构SpringBoot2。x,SpringCloud,AntDesignVue,Mybatisplus,Shiro,红米note11Epro上架,这价格,红米你变了红米note系列一直是红米最具有性价比的系列,也是红米的销量大头,如今红米note11系列又新增了一位成员,那就是红米note11epro,该机型售价1699元起。该机型一共有三种你知道华为这么多旗舰机中,哪款的综合性能最高吗?现在华为的旗舰机已经发布很多部了,像华为mate系列,华为p系列,华为magic系列,都非常不错。现在我先拿华为最具代表的华为mate40Pro和华为p40Pro对比。华为mate红米Note9上手续航强劲用料良心的合格百元机在2022年5G手机铺天盖地的情况下,于一年前发布的红米Note94G是否能够胜任现在的时代,作为工作机备用机主力机学生机它能不能行。我们来一起看看屏幕方面红米note94G正面是金一南将军讲述任正非真实创业历程,想不到华为是这样的公司作为一家国内外闻名的华为公司老板,金一南将军是这样说的像任正非这样的人,哪儿去找?有多好的运气?他是国家百千万工程吗?他是哪级政府重点扶持他了?他都没有。老任说了我就不会做生意,市
联想Z5s1398元惊喜起售,Z5Pro855版12GB内存惊世降临12月18日,联想在北京全球总部园区举办手机新品发布会,实力悍将联想Z5s震撼亮相,售价仅1398元起。联想Z5ProGT855版搭配12GB超大内存惊世降临,搭配骁龙660处理器LED灯杆屏的5G民生作用将至已至众所周知,目前作为城市发展不可或缺的基础设施,智慧灯杆已经具备供电联网广布等特点。不但可以作为数据的采集端,也可以作为数据终端,整合监控摄像头5G微基站安全报警等硬件,通过信息感知鸳鸯锅妙用很多冬季和好兄弟们搭个伙,把食材备一桌,来顿热气腾腾的火锅,真是再舒服不过。不用开火,也不用下厨忙活。人多,凑一窝,唠唠嗑吃吃火锅,再冷也不哆嗦。都知道鸳鸯锅适合吃火锅清汤和无辣不欢都你能想象有一天靠衣服就能给手机充电吗?今天复旦团队实现了看过钢铁侠的你,一定有过这样的梦想,有一天能够像钢铁侠一样,按一下胸前的按钮,就能身披铠甲,拯救世界。不要以为这只是科幻,在科技前沿领域,这种可穿戴的智能铠甲早已提上日程。随着现代雷佳音说错英文,原来极限挑战里深藏各种捧腹彩蛋极限挑战第七季第一期播出后,很多人都在极限男团之间的互动之中感受到了彼此的亲密和团魂。当然,雷佳音岳云鹏王迅贾乃亮郭京飞邓伦已经一同走过12期的挑战征程,而新加入的黄明昊也凭借自己撬装加油站被查封的原因?前几天我接到这样的咨询,他问我做撬装加油站一定需要审批吗?还得审批就太麻烦了!有没有其他不用审批的方法?当时我就认定这个客户他就是想买撬装加油站(企业加油站)做擦边球经营,所以告诉联通三千兆来袭,打造全场景极速网络方案以匠心致未来互联网时代背景下,网络如同信息传输的血脉,其重要性不言而喻。相信不少人都有过类似经历,家里的WiFi信号时断时续,追剧经常被加载中断办公室带宽总不够用,传输文件慢,视频人类高质量人才求职不把薪水放在第一位综编新经济沸点你知道吗?职场上有一个人群叫高值人才,一般是指年薪在30w,具有较好的工作经历和职业发展潜力,是企业在猎取中高端人才时的重点考虑对象。工作是为了实现自我一位在IBM工抢不到仅500套的小米MIX4三体联名礼盒限量款,直接买也很香前段时间小米发了小米MIX4,配置很香,关注度也很高。更有意思的是,小米还推出了小米MIX4三体联名礼盒限量款,很有纪念意义。这个小米MIX4三体联名礼盒限量款除了主角小米MIX4魅族16系列手机全线降价,比双十一更值得买,网友太突然了!魅族16开售很长一段时间都是缺货状态,前不久刚刚敞开了销售,今天魅族科技突然公布魅族16系列全线降价,这让很多网友都大呼意外!魅族16th664GB版售价2498元,6128GB版荣耀50Pro体验轻薄时尚机身,影像能力更加强大荣耀的数字系列终于发布了!这是荣耀独立后数字系列的首次更新,我第一时间拿到手机后快速的体验了几天,发现这款手机还是有很多地方值得聊聊的。包装还是延续了以往白色的简洁风,配件也是熟悉