在 Revit 里重现 Forge Viewer相机的状态

0

最近,我收到一个客户的需求,希望可以把Viewer的相机状态通过Revit API还原到Revit里。所以我们来看看要如何实现这个要求。在开始之前,你要先知道一些有关于Revit相机的事情:

  • Revit预设的相机FOV值大约为50度,焦距为38.6mm,片幅尺寸为36mm。
  • Revit默认的渲染图片尺寸为6英吋。
  • 为了调整Revit相机的FOV值,我们必须利用修改3D视图的裁剪尺寸来完成。因为Revit API没有直接的方法可以修改相机的FOV值。
  • Viewer的相机视角比Revit的相机视角宽。

注意:上述关于Revit的相机参数皆为我反复测试得出,Revit没有确切的值,即皆为近似值。

好的,我们转换过程的总思路如下(注意:接下来的步骤适用透视相机模式):

  • Forge Viewer的部分:

    1. 从当前视图的 Viewer 相机获取焦距,目标,位置和上向量。

      • 调用 Viewer3D#getFocalLength 以取得焦距。
      • 调用 Viewer3D#getState({ viewport: true }) 以取得当前视图必要的相机状态,例如:

        {
          "viewport": {
            "name": "",
            "eye": [
              -14.870469093323,
              36.571562767029,
              -1.2129259109497
            ],
            "target": [
              -14.770469665527,
              36.571967124939,
              -1.2129259109497
            ],
            "up": [
              0,
              0,
              1
            ],
            "worldUpVector": [
              0,
              0,
              1
            ],
            "pivotPoint": [
              -14.770469665527,
              36.571967124939,
              -1.2129259109497
            ],
            "distanceToOrbit": 0.10000024532334,
            "aspectRatio": 3.1789297658863,
            "projection": "perspective",
            "isOrthographic": false,
            "fieldOfView": 90.68087674208
          }
        }
    2. 获取当前加载模型的 global offset(注意:Viewer 默认使用 global offset 来调整加载模型的位置,以避免浮点运算精度和 z-buffer fighting的问题):

      • 调用 viewer.model.getData().globalOffset取得global offset的值,例如:

        {
          "x": -0.253891,
          "y": -45.556179,
          "z": 6.134186
        }
    3. 从Viewer相机的目标和位置减去 globalOffset:

      const state = viewer.getState({ viewport: true });
      const globalOffset = viewer.model.getData().globalOffset
      
      const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
      // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
      
      const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
      // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
      
      const originTarget = currentTarget.clone().add( globalOffset );
      // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
      
      const originPosition = currentPosition.clone().add( globalOffset );
      // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}
  • Revit的部分:

    1. 在这个部分,我们将利用Revit中的裁剪区域3D透视图来完成我们的目标。
    2. 使用Viewer的相机状态计算Revit 3D视图方向并创建透视3D视图:

      // From Forge Viewer
      
      //const currentTarget = new THREE.Vector3().fromArray( state.viewport.target );
      // {x: -14.770469665527344, y: 36.571967124938965, z: -1.212925910949707}
      
      //const currentPosition = new THREE.Vector3().fromArray( state.viewport.eye );
      // {x: -14.870469093322754, y: 36.57156276702881, z: -1.212925910949707}
      
      //const originTarget = currentTarget.clone().add( globalOffset );
      // {x: -15.02436066552734, y: -8.984211875061035, z: 4.921260089050291}
      
      //const originPosition = currentPosition.clone().add( globalOffset );
      // {x: -15.12436009332275, y: -8.984616232971192, z: 4.921260089050291}
      
      //const up = new THREE.Vector3().fromArray( state.viewport.up );
      // {x: 0, y: 0, z: 1}
      
      using(var trans = new Transaction(this.Document, "Map LMV Camera"))
      {
          try
          {
                  if(trans.Start() == TransactionStatus.Started)
                  {
                      IEnumerable<ViewFamilyType> viewFamilyTypes = from elem in new FilteredElementCollector(this.Document).OfClass(typeof(ViewFamilyType))
                                          let type = elem as ViewFamilyType
                                          where type.ViewFamily == ViewFamily.ThreeDimensional
                                          select type;
                  
                      // Create a new Perspective View3D
                      View3D view3D = View3D.CreatePerspective(this.Document, viewFamilyTypes.First().Id);
                      Random rnd = new Random();
                     view3D.Name = string.Format("Camera{0}", rnd.Next()) ;
                     // By default, the 3D view uses a default orientation.
                     // Change the orientation by creating and setting a ViewOrientation3D 
                     var position = new XYZ(-15.12436009332275, -8.984616232971192, 4.921260089050291);
                     var up = new XYZ(0,0,1);
                     var target = new XYZ(-15.02436066552734, -8.984211875061035, 4.921260089050291);
                     var sightDir = target.Subtract( position ).Normalize();
                  
                     var orientation = new ViewOrientation3D( position, up, sightDir );
                     view3D.SetOrientation( orientation );
              
                     // turn off the far clip plane with standard parameter API
                     Parameter farClip = view3D.LookupParameter("Far Clip Active");
                     farClip.Set(0);
                  
                    Parameter cropRegionVisible = view3D.LookupParameter("Crop Region Visible");
                    cropRegionVisible.Set(1);
                  
                    Parameter cropView = view3D.LookupParameter("Crop View");
                    cropView.Set(1);
                  
                    trans.Commit();
                  }    
          }
          catch(Exception ex)
          {
              trans.RollBack();
              TaskDialog.Show("Revit", ex.Message);
          }
      }
      • 上述程序代码的结果:

        After creating 3d view

    3. 使用上述提到经过反复测试而来的相机参数来计算裁剪区域的范围:

      • Revit 相机预设的 FOV 值近似50度,焦距为38.6mm,片幅尺寸为36mm。
      • Revit 默认的渲染图片尺寸近似值为6吋。
      • 因此,裁剪区域的范围计算为:

        • 宽度:6" x 38.6 /视图的相机焦距。6" x 38.6 / 12 = 19.3" = 490.22 mm
        • 高度:19.3" x 常规相机片幅的比例。19.3" x 2/3 = 12.87" = 326.898 mm

      • 透过 Revit UI 设定 Revit 裁切区域并记住在裁剪区域的对话框中选择 Field of view:

        LMV-Revit-Edit-Crop-Region_0

      • 这是最终结果:

        Changing crop size-rvt

        Changing crop size-lmv

此篇文章同步发布于 Forge 官方博客 https://forge.autodesk.com/bl...,希望有帮助!

你可能感兴趣的

载入中...