cesium+threejs结合实现GIS+BIM大场景-2

17 篇文章 16 订阅
2 篇文章 3 订阅

最终效果

示例的demo我没做,但是可以放一个最终调试完的QModel产品的效果。大概是这个样子:

自研引擎产品试用,demo下载:

QModel-BIM模型浏览器

常见问题

1、原理是什么?

原理是利用threejs在Canvas上渲染支持背景透明的特性。把两个Canvas叠加在一起,然后在render时,使threejs的camera随Cesium的相机联动。

2、如何屏蔽掉表层threejs这个div的鼠标操作,只让底下的cesium响应操作?

一句话实现,让某个div忽略所有的鼠标事件:ThreeContainer.style.pointerEvents = "none";当它不存在。

3、如果是threejs高版本,按照网友以及cesium博客的过时代码,在新版本下,有一行代码都调整顺序。

4、物体看不到。怎样找到物体呢?

看到上面的红蓝绿坐标系了吗?你在模型的group里面加个helper射向外太空,只要不瞎都能找到。

搬砖内容

这篇文章到处都是。源自于Cesium的官方指导。Integrating Cesium with Three.js – Cesium

在引用条件齐全的条件下,开始以下工作

初始化三个div

<body>
<div id="cesiumContainer"></div>
<div id="ThreeContainer"></div>
</body>
<script> main(); </script>

主要的初始化函数

function main(){
  // boundaries in WGS84 to help with syncing the renderers
  var minWGS84 = [115.23,39.55];
  var maxWGS84 = [116.23,41.55];
  var cesiumContainer = document.getElementById("cesiumContainer");
  var ThreeContainer = document.getElementById("ThreeContainer");

  var _3Dobjects = []; //Could be any Three.js object mesh
  var three = {
    renderer: null,
    camera: null,
    scene: null
  };

  var cesium = {
    viewer: null
  };

  initCesium(); // Initialize Cesium renderer
  initThree(); // Initialize Three.js renderer
  init3DObject(); // Initialize Three.js object mesh with Cesium Cartesian coordinate system
  loop(); // Looping renderer
}

初始化Cesium

function initCesium(){
    cesium.viewer = new Cesium.Viewer(cesiumContainer,{
        useDefaultRenderLoop: false,
        selectionIndicator : false,
        homeButton:false,
        sceneModePicker:false,
        navigationHelpButton:false,
        infoBox : false,
        navigationHelpButton:false,
        navigationInstructionsInitiallyVisible:false,
        animation : false,
        timeline : false,
        fullscreenButton : false,
        allowTextureFilterAnisotropic:false,
        contextOptions:{
            webgl: {
                alpha: false,
                antialias: true,
                preserveDrawingBuffer : true,
                failIfMajorPerformanceCaveat: false,
                depth:true,
                stencil:false,
                anialias:false
            },
        },
        targetFrameRate:60,
        resolutionScale:0.1,
        orderIndependentTranslucency : true,
        creditContainer : "hidecredit",
        imageryProvider : new Cesium.TileMapServiceImageryProvider({
            url: 'Assets/imagery/NaturalEarthII/',
            maximumLevel : 5
        }),
        baseLayerPicker : false,
        geocoder : false,
        automaticallyTrackDataSourceClocks: false,
        dataSources: null,
        clock: null,
        terrainShadows: Cesium.ShadowMode.DISABLED
    });

    var center = Cesium.Cartesian3.fromDegrees(
        (minWGS84[0] + maxWGS84[0]) / 2,
        ((minWGS84[1] + maxWGS84[1]) / 2)-1,
        200000
    );
    cesium.viewer.camera.flyTo({
        destination : center,
        orientation : {
            heading : Cesium.Math.toRadians(0),
            pitch : Cesium.Math.toRadians(-60),
            roll : Cesium.Math.toRadians(0)
        },
        duration: 3
    });
}

初始化threejs

function initThree(){
    var fov = 45;
    var width = window.innerWidth;
    var height = window.innerHeight;
    var aspect = width / height;
    var near = 1;
    var far = 10*1000*1000; // needs to be far to support Cesium's world-scale rendering

    three.scene = new THREE.Scene();
    three.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    three.renderer = new THREE.WebGLRenderer({alpha: true});
    ThreeContainer.appendChild(three.renderer.domElement);  
}

初始化threejs的对象及其所在的WGS84坐标位置(在地图上的位置)

function _3DObject(){
  this.graphMesh = null; //Three.js 3DObject.mesh
  this.minWGS84 = null; //location bounding box
  this.maxWGS84 = null;
}

function init3DObject(){
  //Cesium entity
  var entity = {
    name : 'Polygon',
    polygon : {
      hierarchy : Cesium.Cartesian3.fromDegreesArray([
        minWGS84[0], minWGS84[1],
        maxWGS84[0], minWGS84[1],
        maxWGS84[0], maxWGS84[1],
        minWGS84[0], maxWGS84[1],
      ]),
      material : Cesium.Color.RED.withAlpha(0.2)
    }
  };
  var Polygon = cesium.viewer.entities.add(entity);

  // Lathe geometry
  var doubleSideMaterial = new THREE.MeshNormalMaterial({
    side: THREE.DoubleSide
  });
  var segments = 10;
  var points = [];
  for ( var i = 0; i < segments; i ++ ) {
      points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * segments + 5, ( i - 5 ) * 2 ) );
  }
  var geometry = new THREE.LatheGeometry( points );
  var latheMesh = new THREE.Mesh( geometry, doubleSideMaterial ) ;
  latheMesh.scale.set(1500,1500,1500); //scale object to be visible at planet scale
  latheMesh.position.z += 15000.0; // translate "up" in Three.js space so the "bottom" of the mesh is the handle
  latheMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
  var latheMeshYup = new THREE.Group();
  latheMeshYup.add(latheMesh)
  three.scene.add(latheMeshYup); // don’t forget to add it to the Three.js scene manually

  //Assign Three.js object mesh to our object array
  var _3DOB = new _3DObject();
  _3DOB.threeMesh = latheMeshYup;
  _3DOB.minWGS84 = minWGS84;
  _3DOB.maxWGS84 = maxWGS84;
  _3Dobjects.push(_3DOB);

  // dodecahedron
  geometry = new THREE.DodecahedronGeometry();
  var dodecahedronMesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial()) ;
  dodecahedronMesh.scale.set(5000,5000,5000); //scale object to be visible at planet scale
  dodecahedronMesh.position.z += 15000.0; // translate "up" in Three.js space so the "bottom" of the mesh is the handle
  dodecahedronMesh.rotation.x = Math.PI / 2; // rotate mesh for Cesium's Y-up system
  var dodecahedronMeshYup = new THREE.Group();
  dodecahedronMeshYup.add(dodecahedronMesh)
  three.scene.add(dodecahedronMeshYup); // don’t forget to add it to the Three.js scene manually

  //Assign Three.js object mesh to our object array
  _3DOB = new _3DObject();
  _3DOB.threeMesh = dodecahedronMeshYup;
  _3DOB.minWGS84 = minWGS84;
  _3DOB.maxWGS84 = maxWGS84;
  _3Dobjects.push(_3DOB);
}

开始循环渲染

function loop(){
  requestAnimationFrame(loop);
  renderCesium();
  renderThreeObj();
}
function renderCesium(){
  cesium.viewer.render();
}

其中threejs的渲染是需要特殊处理的。官方这个版本,应该是threejs r80之前的写法。

function renderThreeObj(){
  // register Three.js scene with Cesium
  three.camera.fov = Cesium.Math.toDegrees(cesium.viewer.camera.frustum.fovy) // ThreeJS FOV is vertical
  three.camera.updateProjectionMatrix();

  var cartToVec = function(cart){
    return new THREE.Vector3(cart.x, cart.y, cart.z);
  };

  // Configure Three.js meshes to stand against globe center position up direction
  for(id in _3Dobjects){
    minWGS84 = _3Dobjects[id].minWGS84;
    maxWGS84 = _3Dobjects[id].maxWGS84;
    // convert lat/long center position to Cartesian3
    var center = Cesium.Cartesian3.fromDegrees((minWGS84[0] + maxWGS84[0]) / 2, (minWGS84[1] + maxWGS84[1]) / 2);

    // get forward direction for orienting model
    var centerHigh = Cesium.Cartesian3.fromDegrees((minWGS84[0] + maxWGS84[0]) / 2, (minWGS84[1] + maxWGS84[1]) / 2,1);

    // use direction from bottom left to top left as up-vector
    var bottomLeft  = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], minWGS84[1]));
    var topLeft = cartToVec(Cesium.Cartesian3.fromDegrees(minWGS84[0], maxWGS84[1]));
    var latDir  = new THREE.Vector3().subVectors(bottomLeft,topLeft ).normalize();

    // configure entity position and orientation
    _3Dobjects[id].graphMesh.position.copy(center);
    _3Dobjects[id].graphMesh.lookAt(centerHigh);
    _3Dobjects[id].graphMesh.up.copy(latDir);
  }

  // Clone Cesium Camera projection position so the
  // Three.js Object will appear to be at the same place as above the Cesium Globe
  three.camera.matrixAutoUpdate = false;
  var cvm = cesium.viewer.camera.viewMatrix;
  var civm = cesium.viewer.camera.inverseViewMatrix;
  three.camera.matrixWorld.set(
      civm[0], civm[4], civm[8 ], civm[12],
      civm[1], civm[5], civm[9 ], civm[13],
      civm[2], civm[6], civm[10], civm[14],
      civm[3], civm[7], civm[11], civm[15]
  );
  three.camera.matrixWorldInverse.set(
      cvm[0], cvm[4], cvm[8 ], cvm[12],
      cvm[1], cvm[5], cvm[9 ], cvm[13],
      cvm[2], cvm[6], cvm[10], cvm[14],
      cvm[3], cvm[7], cvm[11], cvm[15]
  );
  three.camera.lookAt(new THREE.Vector3(0,0,0));

  var width = ThreeContainer.clientWidth;
  var height = ThreeContainer.clientHeight;
  var aspect = width / height;
  three.camera.aspect = aspect;
  three.camera.updateProjectionMatrix();

  three.renderer.setSize(width, height);
  three.renderer.render(three.scene, three.camera);
}

  • 8
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值