zoukankan      html  css  js  c++  java
  • threejs效果之楼房展示

    threejs效果之楼房展示

    效果:

     

    基础数据:

      楼房每一个楼的底边数据,数据结构为geojson。properties属性中Floor属性为楼房层数,本示例默认所有楼每层等高。

      数据示例:

    {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "geometry": {
            "type": "Polygon",
            "coordinates": [
              [
                [
                  120.32088059979766,
                  31.542322389378242
                ],
                ......
                [
                  120.32088059979766,
                  31.542322389378242
                ]
              ]
            ]
          },
          "properties": {
            "FID": 0,
            "Id": 0,
            "Floor": 4
          },
          "id": 0
        },
        {
          "type": "Feature",
          "geometry": {
            "type": "Polygon",
            "coordinates": [
              [
                [
                  120.32076281379749,
                  31.541746604232802
                ],
                ......
                [
                  120.32076281379749,
                  31.541746604232802
                ]
              ]
            ]
          },
          "properties": {
            "FID": 1,
            "Id": 0,
            "Floor": 6
          },
          "id": 1
        }
      ]
    }    
    View Code

    实现原理:

      通过楼的底边数据生成每个楼每层的面、每个面添加边框、以及墙体边框线等要素,拼接为楼群建筑。

      先将底边的经纬度转换为米,舍去小数点后数据。

    注意事项

      1.threejs生成面、体等为三角面模型,所以本例子的面都为手动绘制

      2.基础数据中底边为经纬度点组成。若直接使用经纬度生成楼层面,因为经纬度小数点位数过多会导致threejs经度处理达不到,出现边框被抽稀的效果。

        经纬度直接生成模型后,因为经纬度区别在小数点后几位,会导致模型过小。放大后会导致整个模型抖动严重。

    代码解析:

      1.initContainer()   方法为入口方法,混入vue组件后调用即可。

      2.modelBox为threejs的canvas容器

    源码:

    1.vue组件:

     1 <template>
     2     <div class="threeModel">
     3         <div id="modelBox"></div>
     4     </div>
     5 </template>
     6 
     7 <script>
     8 import borderData from './人民医院建筑.json'
     9 import createModel from './createModel'
    10 export default {
    11     name: 'threeModel',
    12     mixins:[createModel],
    13     data() {
    14         return {
    15             borderData: borderData,
    16         }
    17     },
    18     mounted() {
    19         this.initContainer(this.borderData)
    20     }
    21 }
    22 </script>
    23 
    24 <style scoped lang="scss">
    25 .threeModel {
    26     background: url('../../../assets/images/loop.png') no-repeat;
    27     background-size: 100% 100%;
    28      100%;
    29     height: 100%;
    30     #modelBox {
    31          100%;
    32         height: 100%;
    33         background: rgba(0, 0, 0, 0.5);
    34     }
    35 }
    36 </style>
    View Code

    2.混入方法:

      1 import * as THREE from 'three'
      2 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
      3 export default {
      4     data(){
      5         return{
      6             _borderData: [], // 楼房基础数据
      7             _bounds: [], // 楼房四至
      8             _center: [] // 楼房中心点
      9         }
     10     },
     11     methods: {
     12         
     13         // 创建场景
     14         initContainer(borderData) {
     15             /*创建场景对象Scene*/
     16             var scene = new THREE.Scene()
     17             // 添加楼房楼层平面
     18             this.addFloors(scene, borderData)
     19             /* 光源设置*/
     20             // 环境光
     21             var ambientLight = new THREE.AmbientLight(0xffffff)
     22             scene.add(ambientLight)
     23             /**
     24              * 相机设置
     25              */
     26             var width = window.innerWidth //窗口宽度
     27             var height = window.innerHeight //窗口高度
     28             var k = width / height //窗口宽高比
     29             var s = 1500 //三维场景显示范围控制系数,系数越大,显示的范围越大
     30             //创建相机对象
     31             var camera = new THREE.PerspectiveCamera(
     32                 45,
     33                 window.innerWidth / window.innerHeight,
     34                 0.1,
     35                 1000000
     36             )
     37             camera.position.set(3000,2000,3000)
     38             camera.lookAt(scene.position)
     39             /**
     40              * 创建渲染器对象
     41              */
     42             var renderer = new THREE.WebGLRenderer({
     43                 antialias: true,
     44                 alpha: true
     45             })
     46             renderer.setSize(window.innerWidth - 300, window.innerHeight)
     47             document.getElementById('modelBox').appendChild(renderer.domElement)
     48 
     49             var controls = new OrbitControls(camera, renderer.domElement)
     50             controls.target = new THREE.Vector3(0, 0, 0) //控制焦点
     51             controls.autoRotate = true;//将自动旋转关闭
     52             let clock = new THREE.Clock();//用于更新轨道控制器
     53             
     54             function animate() {
     55                 renderer.render(scene, camera)
     56 
     57                 let delta = clock.getDelta();
     58                 controls.update(delta);
     59                 requestAnimationFrame(animate)
     60             }
     61             animate()
     62         },
     63         
     64         // 添加楼群
     65         addFloors(scene, data) {
     66             // 数据处理/基础数据计算
     67             this._dataAnalysis(data)
     68             this._getModelBounds()
     69             this._getModelCenter()
     70             this._dataAnalysisAll()
     71             // 新建楼房组
     72             var group = new THREE.Group();
     73             group.rotation.set(-1.6,0,0);
     74             scene.add(group)
     75             // 添加楼层
     76             this._borderData.forEach(res => {
     77                 this.addFloor(group,res)
     78                 // 添加楼房黄色边框墙
     79                 this.createWall(group, res)
     80             })
     81         },
     82         // 添加单个楼
     83         addFloor (group, data) {
     84             let shape = this.createShape(data.points)
     85             let i = 0
     86             let addG = setInterval(() => {
     87                 if (i<data.floor) {
     88                     // 添加透明层
     89                     let mesh;
     90                     if (i === data.floor || i === 0) {
     91                         // 添加楼层顶部和底部效果
     92                         // mesh = this.createPolyline(shape, i, 0.9, 'rgb(14,98,173)')
     93                     } else {
     94                         mesh = this.createPolyline(shape, i)
     95                     }
     96                     group.add(mesh);
     97                     // 添加楼层边界
     98                     this.createPolygonline(group, data.points, i)
     99                     i++
    100                 } else{
    101                     if(addG){
    102                         clearInterval(addG)
    103                     }
    104                 }
    105             }, 30)
    106         },
    107         // 数据转换
    108         _dataAnalysis (borderData) {
    109             let data = []
    110             borderData.features.forEach(res => {
    111                 res.geometry.coordinates.forEach(r => {
    112                         // 将度转换为米
    113                     r = r.map(re => {
    114                         return [(re[0]*1112000).toFixed(0)*1, (re[1]*1112000).toFixed(0)*1]
    115                     })
    116                     data.push({
    117                         floor: res.properties.Floor,
    118                         points: r
    119                     })
    120                 })
    121             })
    122             this._borderData = data
    123         },
    124         // 获取模型四至
    125         _getModelBounds () {
    126             // 四至: 上右下左
    127             let bounds = [0,0,0,0]
    128             // 所有点数组
    129             let pointArr = []
    130             // 所有点经度数组
    131             let pointLonArr = []
    132             // 所有点纬度数组
    133             let pointLatArr = []
    134             // 获取所有点数组
    135             this._borderData.forEach(res => {
    136                 pointArr = pointArr.concat(res.points)
    137             })
    138             // 获取经度、纬度数组
    139             pointArr.forEach(res => {
    140                 pointLonArr.push(res[0])
    141                 pointLatArr.push(res[1])
    142             })
    143             // 获取四至
    144             bounds = [Math.max(...pointLatArr), Math.min(...pointLonArr), Math.min(...pointLatArr), Math.max(...pointLonArr)]
    145             this._bounds = bounds
    146         },
    147         // 获取模型中心点
    148         _getModelCenter () {
    149             let center = [(this._bounds[1] + this._bounds[3])/2,(this._bounds[0] + this._bounds[2])/2]
    150             this._center = center
    151         },
    152         // 数据转换2-将数据移动至原点
    153         _dataAnalysisAll(){
    154             this._borderData.forEach(res => {
    155                 res.points.forEach(re => {
    156                     re[0] = re[0] - this._center[0]
    157                     re[1] = re[1] - this._center[1]
    158                 })
    159             })
    160         },
    161 
    162         // 创建平面集合
    163         createShape (data) {
    164             var shape = new THREE.Shape();
    165             data.forEach((e,i) => {
    166                 if (i === 0) {
    167                     shape.moveTo( ...e);
    168                 } else {
    169                     shape.lineTo( ...e);
    170                 }
    171             })
    172             return shape
    173         },
    174         // 创建楼层平面组
    175         createPolyoneGroup () {
    176             var group = new THREE.Group();
    177             group.rotation.set(-1.6,0,0);
    178             // group.position.set(-30,0,30);
    179             // group.scale.set(5,5,5);
    180             return group
    181         },
    182 
    183         // 创建透明平面
    184         createPolyline(shape, h, opacity = 0.1, color='rgb(0, 0,255, 0)'){
    185             var geometry = new THREE.ShapeGeometry( shape );
    186             var cubeMaterial=new THREE.MeshBasicMaterial({
    187                 color:  color,
    188                 transparent:true,
    189                 opacity:opacity,
    190                 side:THREE.DoubleSide  // 强制双面
    191             });
    192             var mesh = new THREE.Mesh( geometry, cubeMaterial );
    193 
    194             mesh.position.z = h*20;
    195             // mesh.scale.set(1,1,1);
    196             mesh.scale.set(1,1,1);
    197             mesh.rotation.set(0,0,0);
    198 
    199             return mesh
    200         },
    201         // 创建边缘平面
    202         createPolygonline(group, data, h=0){
    203             var material = new THREE.LineBasicMaterial({
    204                 color: 'rgba(53,166,255,0.8)',
    205                 line 1,
    206                 side:THREE.DoubleSide  // 强制双面
    207             });
    208             var geometry = new THREE.Geometry()
    209             for (let item of data) {
    210                 geometry.vertices.push(
    211                     new THREE.Vector3(...item, h*20)
    212                 )
    213             }
    214             var line = new THREE.Line(geometry, material)
    215             // line.scale.set(0.8,0.8,1);
    216             // line.position.set(-10,-10,0);
    217             group.add(line)
    218         },
    219 
    220         // 创建墙面
    221         createWall(group, data){
    222             var material = new THREE.LineBasicMaterial({
    223                 color: 0xffc000
    224             });
    225             let points = data.points
    226             let wallData = []
    227             for (let i=0;i< points.length;i++) {
    228                 if(i + 1 < points.length){
    229                     wallData.push([points[i], points[i+1]])
    230                 }
    231             }
    232             for (let item of wallData) {
    233                 var geometry = new THREE.Geometry();
    234                 geometry.vertices.push(
    235                     new THREE.Vector3( ...item[1], 0 ),
    236                     new THREE.Vector3( ...item[1], data.floor*20 ),
    237                     new THREE.Vector3( ...item[0], data.floor*20 ),
    238                     new THREE.Vector3( ...item[0], 0 ),
    239                     new THREE.Vector3( ...item[1], 0 )
    240                 );
    241                 var line = new THREE.Line( geometry, material );
    242                 group.add(line)
    243             }
    244         },
    245         
    246     }
    247 }
    View Code

    钻研不易,转载请注明出处。。。。。。

  • 相关阅读:
    HDU 4865 Peter's Hobby --概率DP
    UVALive 6093 Emergency Room --优先队列实现的模拟
    UVALive 6665 Dragon’s Cruller --BFS,类八数码问题
    UVALive 6092 Catching Shade in Flatland --枚举+几何计算
    UVALive 6168 Fat Ninjas --二分小数+搜索
    九连环-递归解法
    一道题看bitset应用 --ZOJ 3642
    UVALive 6663 Count the Regions --离散化+DFS染色
    ZOJ 1111 Poker Hands --复杂模拟
    UVALive 6449 IQ Test --高斯消元?
  • 原文地址:https://www.cnblogs.com/s313139232/p/13847677.html
Copyright © 2011-2022 走看看