您的位置:首页 > Web前端 > JavaScript

three.js 第一个项目总结

2018-03-18 17:32 232 查看
项目功能主要是允许用户选择一张背景图 然后可以选择任意一四边形区域 然后在此区域画上一个窗户(比如),并且后面可以选择该窗户的材质等外观选项。
整个过程大概拆为两部分,一是画窗户并且可以更改外观,二是如何选择区域并且可以让画好的窗户通过transformation填充至选区。
技术选择。有两个明显的选项:一是通过图片切换实现外观的变动,需要准备很多图片但是代码实现比较简单,在考虑区域选择时可能要用到canvas,但因为是图片,只是将图片映射到选区,也是ok的;二是通过webGL,画出窗户框架,之后只需要小的材质图即可。如果熟悉webGL(或者是其相关著名框架three.js) 实现成本不那么高的话,还是第二种更加地自然,也省些资源(设计,加载等)。虽然不是那么地熟悉three.js,但也是学过一些的,对自己来说第二种逻辑很清晰简单,还是选择地第二种。
一开始并没有考虑选区的问题,先去做的第一部分。
总之先将窗户画了个fullsize - 背景图/canvas的尺寸。因为之前很少看到有文章或者教程书里提到如何实现精确的尺寸,就想试试看。先看camera,renderer设置代码: const pcameraSettings = getCameraInfoFromDimesion(this._dy.containerWidth / this._dy.containerHeight * 1600, 1600); // 见下方
 this._3.camera = new THREE.PerspectiveCamera(pcameraSettings.fov, pcameraSettings.aspect, 0.1, 4000);
this._3.camera.position.z = pcameraSettings.z; // z will not change again

this._3.renderer = new THREE.WebGLRenderer({ alpha: true, preserveDrawingBuffer: true, antialias: true });
this._3.renderer.setSize(this._dy.containerWidth, this._dy.containerHeight);
const getCameraInfoFromDimesion = (width, height) => {
  const fov = 45; // difault fov
  const radian = fov / 180 * Math.PI;
  const aspect = roundNumberTo(width / height, 2);
  const z = roundNumberTo(height / (2 * Math.tan(radian / 2)), 2);
  return {
    fov,
    aspect,
    z: z,
  };
};
要点在于camera的z值。这里物体(mesh)位于(0, 0)点,高度1600,宽度containerRatio * 1600 (相机aspect为containerRatio)。希望物体全屏,则要求相机可视区域为(containerRatio * 1600 x 1600)。如图得到z = h / (2 * tan(alpha / 2))。带入h得到合适z值即可。



接着该画窗户了。本来想直接用个模型,但是窗户尺寸是可变的。就好像以前用那种button背景图片,上边框下边框设计固定,中间可以无限重复那种...最终还是选择了自己画,就是顶点啊边啊自己一个个地去定义,因为看着效果图感觉是能画出来的,虽然有点麻烦,但其实也只是一些算式和循环等,这样做其实也是自然合理的。(不清楚有没有更好地办法,3d建模只大概知道一点点。)
那一个矩形面举例:



const vertices = [
new THREE.Vector3(v0.x, v0.y, 0),
new THREE.Vector3(v1.x, v1.y, 0),
new THREE.Vector3(v2.x, v2.y, 0),
new THREE.Vector3(v3.x, v3.y, 0),
];
const faces = [
   new THREE.Face3(0, 2, 1),
   new THREE.Face3(2, 0, 3),
];
const geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;这样就画了一个矩形面,但这个面并没有深度。根据项目要求,其实只需要展示front face,所以没有画depth。画是ok的,但是那样就要增加不少的顶点和面,想象一个长方体,出了正面,还有另外5个面。也许会问那为什么动用three.js呢,嗯,虽然少了depth,看上去是二维,但是考虑整个场景,其实依然可以认为是在三维空间画物体。更重要的一点,布吉岛其他合适的库啊。
后面就是一些计算,计算各种尺寸啊间距啊等,没有很复杂的地方。
至此,物体画好啦。开始思考第二部分,实现选区的变形,以及将画好的窗户映射到选区。
实现选区变形,用的是TrackballControls,和DragControls,从官网实例draggable cubes抠出来的,这两controls好像没文档,只能自己看文档或者改参数试试。先这么用着的...
剩下就是映射到选区,图形学在下只看了一点教程懂一些很基础的,经历了这个功能后,懂得这样是不行的...本以为不就是根据窗户默认位置,和选区四点坐标得到个变形矩阵呗。嗯是这样的,可是矩阵怎么求,好难。



后来经人提点(yes,大知乎),知道了应该去查射影变化 透视变化,然后找到csdn一个大神的文章,这个方法好聪明啊~ 具体推到可以在原文章内看。在下只是把C++代码转成了js,传入原始四边形和目标四边形顶点得到变换矩阵。因为大神写的是二维变换,而自己代码内是三维顶点,于是对顶点做了个遍历,求出各顶点[x,y]变换后的坐标,z依旧为0,返回。基本就可以了。
第一个功能比较麻烦的three.js项目,做个小记录。有些概念不是特别清晰,感觉容易忘。因为是基于自己一点点知识去摸索的,所以每步感觉实现得...很朴实。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: