位置: 编程技术 - 正文

Three.js开发实现3D地图的实践过程总结(three.js怎么用)

编辑:rootadmin

推荐整理分享Three.js开发实现3D地图的实践过程总结(three.js怎么用),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:three.js原理,基于threejs的开源项目,three.js入门指南,three. js,three.js bim,three. js,three.js开发工具,threejs开发教程,内容如对您有帮助,希望把文章链接给更多的朋友!

前言

本文主要介绍Three.js的开发基础和基本原理,以及如何实现3D全景图。想在web端实现3D全景图的效果,除了全景图片、WebGL外,还需要处理很多细节。据我所知,目前国外3D全景图比较好的是KrPano,国内很多3D全景服务是在使用krpano的工具。

前段时间连续上了一个月班,加班加点完成了一个3D攻坚项目。也算是由传统web转型到webgl图形学开发中,坑不少,做了一下总结分享。

Three.js

基于简化WebGL开发复杂度和降低入门难度的目的,mrdoob)在WebGL标准基础上封装了一个轻量级的JS 3D库—— Three.js。

在我看来,Three.js具有以下特点:

完备 具备3D开发所需完整功能,基本上使用WebGL能实现的效果,用Three.js都能更简单地实现 易用 架构设计比较清晰和合理,易于理解,扩展性较好,且开发效率高于WebGL 开源 项目开源,且有一批活跃的贡献者, 持续维护升级中

Three.js使WebGL更加好用,可以实现很棒的3D效果,比如:

游戏 hellorun 数据可视化 armsglobe

1、法向量问题

法线是垂直于我们想要照亮的物体表面的向量。法线代表表面的方向因此他们为光源和物体的交互建模中具有决定性作用。每一个顶点都有一个关联的法向量。

  

如果一个顶点被多个三角形共享,共享顶点的法向量等于共享顶点在不同的三角形中的法向量的和。N=N1+N2;

  

所以如果不做任何处理,直接将3维物体的点传递给BufferGeometry,那么由于法向量被合成,经过片元着色器插值后,就会得到这个黑不溜秋的效果

    

我的处理方式使顶点的法向量保持唯一,那么就需要在共享顶点处,拷贝一份顶点,并重新计算索引,是的每个被多个面共享的顶点都有多份,每一份有一个单独的法向量,这样就可以使得每个面都有一个相同的颜色  

2、光源与面块颜色  

开发过程中设计给了一套配色,然而一旦有光源,面块的最终颜色就会与光源混合,颜色自然与最终设计的颜色大相径庭。下面是Lambert光照模型的混合算法。

  

而且产品的要求是顶面保持设计的颜色,侧面需要加入光源变化效果,当对地图做操作时,侧面颜色需要根据视角发生变化。那么我的处理方式是将顶面与侧面分别绘制(创建两个Mesh),顶面使用MeshLambertMaterial的emssive属性设置自发光颜色与设计颜色保持一致,也就不会有光照效果,侧面综合使用Emssive与color来应用光源效果。  

  

3、POI标注

Three中创建始终朝向相机的POI可以使用Sprite类,同时可以将文字和图片绘制在canvas上,将canvas作为纹理贴图放到Sprite上。但这里的一个问题是canvas图像将会失真,原因是没有合理的设置sprite的scale,导致图片被拉伸或缩放失真。

问题的解决思路是要保证在3d世界中的缩放尺寸,经过一系列变换投影到相机屏幕后仍然与canvas在屏幕上的大小保持一致。这需要我们计算出屏幕像素与3d世界中的长度单位的比值,然后将sprite缩放到合适的3d长度。  

Three.js开发实现3D地图的实践过程总结(three.js怎么用)

4、点击拾取问题  

webgl中3D物体绘制到屏幕将经过以下几个阶段  

  

所以要在3D应用做点击拾取,首先要将屏幕坐标系转化成ndc坐标系,这时候得到ndc的xy坐标,由于2d屏幕并没有z值所以,屏幕点转化成3d坐标的z可以随意取值,一般取0.5(z在-1到1之间

然后将ndc坐标转化成3D坐标:  ndc = P * MV * Vec4  Vec4 = MV-1 * P -1 * ndc  这个过程在Three中的Vector3类中已经有实现:

将得到的3d点与相机位置结合起来做一条射线,分别与场景中的物体进行碰撞检测。首先与物体的外包球进行相交性检测,与球不相交的排除,与球相交的保存进入下一步处理。将所有外包球与射线相交的物体按照距离相机远近进行排序,然后将射线与组成物体的三角形做相交性检测。求出相交物体。当然这个过程也由Three中的RayCaster做了封装,使用起来很简单:

5、性能优化

随着场景中的物体越来越多,绘制过程越来越耗时,导致手机端几乎无法使用。

在图形学里面有个很重要的概念叫“one draw all”一次绘制,也就是说调用绘图api的次数越少,性能越高。比如canvas中的fillRect、fillText等,webgl中的drawElements、drawArrays;所以这里的解决方案是对相同样式的物体,把它们的侧面和顶面统一放到一个BufferGeometry中。这样可以大大降低绘图api的调用次数,极大的提升渲染性能。

  

这样解决了渲染性能问题,然而带来了另一个问题,现在是吧所有样式相同的面放在一个BufferGeometry中(我们称为样式图形),那么在面点击时候就无法单独判断出到底是哪个物体(我们称为物体图形)被选中,也就无法对这个物体进行高亮缩放处理。我的处理方式是,把所有的物体单独生成物体图形保存在内存中,做面点击的时候用这部分数据来做相交性检测。对于选中物体后的高亮缩放处理,首先把样式面中相应部分裁减掉,然后把选中的物体图形加入到场景中,对它进行缩放高亮处理。裁剪方法是,记录每个物体在样式图形中的其实索引位置,在需要裁切时候将这部分索引制零。在需要恢复的地方在把这部分索引恢复成原状。

6、面点击移动到屏幕中央

这部分也是遇到了不少坑,首先的想法是:

面中心点目前是在世界坐标系内的坐标,先用center.project(camera)得到归一化设备坐标,在根据ndc得到屏幕坐标,而后根据面中心点屏幕坐标与屏幕中心点坐标做插值,得到偏移量,在根据OribitControls中的pan方法来更新相机位置。这种方式最终以失败告终,因为相机可能做各种变换,所以屏幕坐标的偏移与3d世界坐标系中的位置关系并不是线性对应的。  

最终的想法是:  

我们现在想将点击面的中心点移到屏幕中心,屏幕中心的ndc坐标永远都是(0,0)我们的观察视线与近景面的焦点的ndc坐标也是0,0;也就是说我们要将面中心点作为我们的观察点(屏幕的中心永远都是相机的观察视线),这里我们可以直接将面中心所谓视线的观察点,利用lookAt方法求取相机矩阵,但如果这样简单处理后的效果就会给人感觉相机的姿态变化了,也就是会感觉并不是平移过去的,所以我们要做的是保持相机当前姿态将面中心作为相机观察点。  

回想平移时我们将屏幕移动转化为相机变化的过程是知道屏幕偏移求target,这里我们要做的就是知道target反推屏幕偏移的过程。首先根据当前target与面中心求出相机的偏移向量,根据相机偏移向量求出在相机x轴和up轴的投影长度,根据投影长度就能返推出应该在屏幕上的平移量。 

7、2/3D切换

D切换的主要内容就是当相机的视线轴与场景的平面垂直时,使用平行投影,这样用户只能看到顶面给人的感觉就是2D视图。所以要根据透视的视锥体计算出平行投影的世景体。

因为用户会在2D、3D场景下做很多操作,比如平移、缩放、旋转,要想无缝切换,这个关键在于将平行投影与视锥体相机的位置、lookAt方式保持一致;以及将他们放大缩小的关键点:distance的比例与zoom来保持一致。

平行投影中,zoom越大代表六面体的首尾两个面面积越小,放大越大。

8、3D中地理级别  

地理级别实际是像素跟墨卡托坐标系下米的对应关系,这个有通用的标准以及计算公式:

各个级别中像素与米的对应关系如下:

3D中的计算策略是,首先需要将3D世界中的坐标与墨卡托单位的对应关系搞清楚,如果已经是以mi来做单位,那么就可以直接将相机的投影屏幕的高度与屏幕的像素数目做比值,得出的结果跟上面的ranking做比较,选择不用的级别数据以及比例尺。注意3D地图中的比例尺并不是在所有屏幕上的所有位置与现实世界都满足这个比例尺,只能说是相机中心点在屏幕位置处的像素是满足这个关系的,因为平行投影有近大远小的效果。

9、poi碰撞

由于标注是永远朝着相机的,所以标注的碰撞就是把标注点转换到屏幕坐标系用宽高来计算矩形相交问题。至于具体的碰撞算法,大家可以在网上找到,这里不展开。下面是计算poi矩形的代码

总结

标签: three.js怎么用

本文链接地址:https://www.jiuchutong.com/biancheng/369840.html 转载请保留说明!

上一篇:three.js中文文档学习之如何本地运行详解(threejs中文文档pdf)

下一篇:JavaScript内存泄漏的处理方式(js内存释放)

  • 小规模纳税人租赁不动产税率
  • 房地产企业怎么认定
  • 残疾人就业保障金会计分录怎么做
  • 个体户缴纳经营所得个税怎么算的
  • 专项附加扣除可以随时填报吗
  • 酒店开办费
  • 预提工资与计提工资的区别
  • 单位之间调动
  • 预授权撤销怎么撤销
  • 新增资产额怎么计算
  • 服装企业销售方式
  • 企业销售赠券的增值税如何处理
  • 出口退税的报关单当月可以申请退税吗?
  • 资产负债表长期借款包括哪些
  • 嵌入式软件产品增值税即征即退
  • 产品不合格重新加工叫什么
  • 工厂临时住宿
  • 税金及附加小于应缴纳所得税是什么原因
  • 印花税税目错了能申报更正吗
  • 工会经费向地方税务局缴纳的比例是多少
  • 学校应该缴纳的税
  • 集体福利支出包括
  • 以货抵债会计处理
  • 筹建期水电费计入什么科目
  • 购入需要安装的固定资产会计科目
  • 个体户经营所得核定税率
  • 金蝶k3购货发票怎么点击记账
  • 增值税加计扣除是什么意思啊
  • 本月负数发票大于正数发票 留抵的增值税怎么做账
  • 成本算错了
  • 总分机构怎么纳税
  • 农业合作社收到政府补贴做到其他收入里可以吗
  • 跨年度的暂估入库账务处理
  • 电脑经常蓝屏修复
  • 服务器centos6.9安装教程
  • qbupdate.exe - qbupdate是什么进程 有什么作用
  • abm文件怎么打开
  • 公租房租金收入免企业所得税吗
  • seti@home.exe - seti@home是什么进程 有什么用
  • 进项税一定是专票吗
  • kpupgrader.exe是什么
  • 深入解析windows第7版卷2
  • 资产负债表中其他综合收益怎么填
  • 生产型企业出口退税退的是哪部分的税
  • 报销差旅费退回余款填什么凭证
  • 作废发票需要拿回执单吗
  • ubuntu20.04安装cuda10.2
  • ai的工具介绍
  • function函数的定义
  • 前端等比例缩放
  • php dirname函数
  • 期末结转主营业务收入负数
  • 前期认证相符且不符合
  • php网站访问量大怎么优化
  • 发票有种类型
  • 上月的普票下月可以记账么
  • 外贸公司美金账户开立要求
  • 非公益捐赠如何入账
  • 合资公司政策
  • 分包抵扣金额
  • 信息技术服务费可以全额抵扣吗
  • 管理费用怎么结转到本年利润未分配利润里了
  • 金税盘发票全额抵扣如何做账
  • 私企干不长久
  • win8 itunes
  • 智能abc不能输入汉字
  • os x10.11el capitan公测版下载地址(公测版计划注册教程)
  • linux配置java环境变量无法保存并退出
  • 在Mac OS Yosemite 系统中如何发送超大邮件附件
  • windows8.1开机
  • js 文件缓存
  • unity优化gc
  • shell脚本编程实验报告
  • rom开发是做什么的
  • angularjs常用总结
  • jquery获取file文件
  • jQuery插件ajaxfileupload.js实现上传文件
  • 郑州市惠济区税务局黄国选
  • 税控盘反写后才能开票吗
  • 今年烟草税多少钱
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设