资讯专栏INFORMATION COLUMN

在 Forge Viewer 里加入自订义线

zilu / 3160人阅读

摘要:可能有许多原因你想在里加入自订义的线型,例如显示线框几何视觉化包围箱或者其他你想带给使用者的视觉回馈。下面是我传写的一个例子,他可以在选重构件后在场景里用自定义线型描绘它的包围箱,在线示例可以参考这里

这篇文章的原著是 Autodesk AND 的 Philippe Leefsma,以下以我简称。

可能有许多原因你想在 Viewer 里加入自订义的线型,例如显示线框(Wireframe)几何、视觉化包围箱(Bounding Box)或者其他你想带给使用者的视觉回馈。基本上这有三种方式来做到这件事,让我们来看看到底要怎么做,首先我们要先产生一个线型几何,其代码入下所示:

const geometry = new THREE.Geometry ()

geometry.vertices.push (new THREE.Vector3 ( 0,  0,  0))
geometry.vertices.push (new THREE.Vector3 (10, 10, 10))

var linesMaterial = new THREE.LineBasicMaterial ({
  color: new THREE.Color (0xFF0000),
  transparent: true,
  depthWrite: false,
  depthTest: true,
  linewidth: 10,
  opacity: 1.0
})

var lines = new THREE.Line (geometry,
  linesMaterial,
  THREE.LinePieces)

下一步我们来看看要怎么将这个线型加入到 Viewer 的场景里(scene):

一、将线型加到 viewer.impl.scene

//1 - 第一种方法
viewer.impl.scene.add (lines)
viewer.impl.invalidate (true)

但这个方法并不是一个靠谱的方法,因为他只能在 FireFox 里正常运作,在我的 Chrome 上是没有作用的。。。所以让我们看看下一个方法。

二、将线型加到 viewer.impl.scene

//2 - 第二种方法
viewer.impl.sceneAfter.add (lines)
viewer.impl.invalidate (true)

这个方法比前一个好多了,他可以在多个浏览器上正常执行,但当你透过修改了构件的可视性后(执行了孤立显示或隐藏等动作),所有的线型都会跟著构件一起消失,我想这是应该是 Viewer 内部的著色器(Shader)和渲染(Rendering)设置造成的。

三、产生 Viewer Overlay 场景,并将线型加入 Overlay 场景:

//3 - 第三种方法
viewer.impl.createOverlayScene (
  "myOverlay", linesMaterial)

viewer.impl.addOverlay (
  "myOverlay", lines)

viewer.impl.invalidate (true)

经测试这个方法非常的靠谱,他可以在多个浏览器上正确执行,并且不受构件可视性的影响。但你不一定要使用第三个方法,你可以根据你的需求选择适合你应用场景的方法。

下面是我传写的一个例子 Viewing.Extension.BoundingBox,他可以在选重构件后在 Viewer 场景里用自定义线型描绘它的包围箱,在线示例可以参考这里:

/////////////////////////////////////////////////////////////////
// BoundingBox Viewer Extension
// By Philippe Leefsma, Autodesk Inc, August 2017
//
/////////////////////////////////////////////////////////////////
import MultiModelExtensionBase from "Viewer.MultiModelExtensionBase"
import Toolkit from "Viewer.Toolkit"

class BoundingBoxExtension extends MultiModelExtensionBase {

  /////////////////////////////////////////////////////////
  // Class constructor
  //
  /////////////////////////////////////////////////////////
  constructor (viewer, options) {

    super (viewer, options)

    this.onContextMenu = this.onContextMenu.bind(this)

    this.linesMaterial = this.createMaterial(0x0000FF)

    this.lineGroups = []
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  createMaterial (color = 0x000000, opacity = 1.0) {

    return new THREE.LineBasicMaterial({
      color: new THREE.Color(color),
      transparent: true,
      depthWrite: false,
      depthTest: true,
      linewidth: 10,
      opacity
    })
  }

  /////////////////////////////////////////////////////////
  // Load callback
  //
  /////////////////////////////////////////////////////////
  load () {

    this.viewer.loadDynamicExtension(
      "Viewing.Extension.ContextMenu").then(
      (ctxMenuExtension) => {
        ctxMenuExtension.addHandler(
          this.onContextMenu)
      })

    console.log("Viewing.Extension.BoundingBox loaded")

    return true
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  get className() {

    return "bounding-box"
  }

  /////////////////////////////////////////////////////////
  // Extension Id
  //
  /////////////////////////////////////////////////////////
  static get ExtensionId () {

    return "Viewing.Extension.BoundingBox"
  }

  /////////////////////////////////////////////////////////
  // Unload callback
  //
  /////////////////////////////////////////////////////////
  unload () {

    console.log("Viewing.Extension.BoundingBox unloaded")

    super.unload ()

    return true
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  onModelRootLoaded () {

    this.options.loader.show (false)

    this.viewer.impl.createOverlayScene (
      "boundingBox",
      this.linesMaterial)
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  async onSelection (event) {

    if (event.selections.length) {

      const selection = event.selections[0]

      const model =
        this.viewer.activeModel ||
        this.viewer.model

      this.selectedDbId = selection.dbIdArray[0]

      const bbox =
        await Toolkit.getWorldBoundingBox(
          model, this.selectedDbId)

      this.drawBox(bbox)
    }
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  drawBox (bbox) {

    const geometry = new THREE.Geometry()

    const { min, max } = bbox

    geometry.vertices.push(new THREE.Vector3(min.x, min.y, min.z))
    geometry.vertices.push(new THREE.Vector3(max.x, min.y, min.z))

    geometry.vertices.push(new THREE.Vector3(max.x, min.y, min.z))
    geometry.vertices.push(new THREE.Vector3(max.x, min.y, max.z))

    geometry.vertices.push(new THREE.Vector3(max.x, min.y, max.z))
    geometry.vertices.push(new THREE.Vector3(min.x, min.y, max.z))

    geometry.vertices.push(new THREE.Vector3(min.x, min.y, max.z))
    geometry.vertices.push(new THREE.Vector3(min.x, min.y, min.z))

    geometry.vertices.push(new THREE.Vector3(min.x, max.y, max.z))
    geometry.vertices.push(new THREE.Vector3(max.x, max.y, max.z))

    geometry.vertices.push(new THREE.Vector3(max.x, max.y, max.z))
    geometry.vertices.push(new THREE.Vector3(max.x, max.y, min.z))

    geometry.vertices.push(new THREE.Vector3(max.x, max.y, min.z))
    geometry.vertices.push(new THREE.Vector3(min.x, max.y, min.z))

    geometry.vertices.push(new THREE.Vector3(min.x, max.y, min.z))
    geometry.vertices.push(new THREE.Vector3(min.x, max.y, max.z))

    geometry.vertices.push(new THREE.Vector3(min.x, min.y, min.z))
    geometry.vertices.push(new THREE.Vector3(min.x, max.y, min.z))

    geometry.vertices.push(new THREE.Vector3(max.x, min.y, min.z))
    geometry.vertices.push(new THREE.Vector3(max.x, max.y, min.z))

    geometry.vertices.push(new THREE.Vector3(max.x, min.y, max.z))
    geometry.vertices.push(new THREE.Vector3(max.x, max.y, max.z))

    geometry.vertices.push(new THREE.Vector3(min.x, min.y, max.z))
    geometry.vertices.push(new THREE.Vector3(min.x, max.y, max.z))

    const lines = new THREE.Line(geometry,
      this.linesMaterial,
      THREE.LinePieces)

    this.lineGroups.push(lines)

    this.viewer.impl.addOverlay("boundingBox", lines)

    this.viewer.impl.invalidate(
      true, true, true)
  }

  /////////////////////////////////////////////////////////
  //
  //
  /////////////////////////////////////////////////////////
  onContextMenu (event) {

    const model =
      this.viewer.activeModel ||
      this.viewer.model

    event.menu.forEach((entry) => {

      const title = entry.title.toLowerCase()

      switch (title) {

        case "isolate":
          entry.target = () => {
            Toolkit.isolateFull(
              this.viewer, this.selectedDbId, model)
          }
          break

        case "hide selected":
          entry.target = () => {
            Toolkit.hide(
              this.viewer, this.selectedDbId, model)
          }
          break

        case "show all objects":
          entry.target = () => {
            Toolkit.isolateFull(
              this.viewer, [], model)
            this.viewer.fitToView()
          }
          break

        default: break
      }
    })

    const instanceTree = model.getData().instanceTree

    const dbId = event.dbId || (instanceTree
        ? instanceTree.getRootId()
        : -1)

    if (dbId > -1) {

      event.menu.push({
        title: "Clear All BoundingBoxes",
        target: () => {
          this.lineGroups.forEach((lines) => {

            this.viewer.impl.removeOverlay("boundingBox", lines)
          })

          this.viewer.impl.invalidate(
            true, true, true)

          this.lineGroups = []
        }
      })
    }
  }
}

Autodesk.Viewing.theExtensionManager.registerExtension (
  BoundingBoxExtension.ExtensionId,
  BoundingBoxExtension)

export default "Viewing.Extension.BoundingBox"

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91850.html

相关文章

  • Forge Viewer上显示自订义属性

    摘要:最近有的小伙伴们都在询问要怎么在里显示自订义属性,要做到这个是挺容易的。在来我们透过继承来创建自个的属性面板使用的语法,部份代码来自的无法从服务器获取属性透过撰写括展让自定义属性窗取代自带的以上希望对各为小伙伴有帮助参考 最近有 Autodesk Forge 的小伙伴们都在询问要怎么在 Viewer 里显示自订义属性,要做到这个是挺容易的。目前有两种方式可以做到这个效果,一种是直接添加...

    seasonley 评论0 收藏0
  • 订义 Forge Viewer ModelStructurePanel 的交互行为

    摘要:在官方释出版的同时发布了新版本的,这个面版已被整个重新改写,这次更新也加入一些新的交互行为,下面我们将会稍作解释。 这礼拜的小技巧是关于如何以不加入太多的 JavaScript 的方式自订义 ModelStructurePanel 的交互行为,这个小技巧受到这篇问与答的启发:Prevent zoom in Forge viewer when clicking in Model Brow...

    xialong 评论0 收藏0
  • 自定义 Forge Viewer 右键菜单(Context Menu)

    摘要:前阵子有些圈的朋友们都在询问同一个问题要怎么在的自带右键菜单上添加自定义项目或是只显示自订义项目以下将针对在自带右键菜单上添加自定义项目和只显示自订义项目的右键菜单进行说明。 前阵子有些 Autodesk Forge 圈的朋友们都在询问同一个问题『要怎么在 Viewer 的自带右键菜单上添加自定义项目或是只显示自订义项目』~ 以下将针对『在自带右键菜单上添加自定义项目』和『只显示自订义...

    Harriet666 评论0 收藏0
  • Forge Viewer 里展示/隐藏构件材质

    摘要:对于大多数的模型文档都可以透过服务提取转换在里渲染构件外观时所需的材质及贴图。所以我们可以透过它遍历所有材质,找出我们想隐藏贴图的那些材质,将它的颜色设置为灰色,同时也可以透过它将隐藏贴图的材质回复。 这篇文章来自 Autodesk ADN 的梁晓冬,以下以我简称。 对于大多数的模型文档都可以透过 Autodesk Forge Model Derivative 服务提取、转换在 Vie...

    Dean 评论0 收藏0
  • 透过 three.js Forge Viewer 里头创建 3D 文字(使用部份 r81 的功能

    摘要:但很不幸的,新功能要加入里头这件事对于开发团队而言绝非一件易事,是需要一些时间来完成的这篇文章将带领大家用最少的工作量将上的新功能拿来上使用。在这个案例里头,我们可以只将和其他相依文档引入例如。 showImg(https://segmentfault.com/img/bV25af?w=1311&h=696); 对于 Forge Viewer 比较熟悉的朋友可能知道 Forge Vie...

    xuhong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<