javascript - 如何在 Three.js 中使用 RayCaster 拾取文本网格?

标签 javascript three.js autodesk-forge

因此,我在使用 RayCaster 拾取 TextGeometry 时遇到了问题。我正在使用下面的函数 createText() 将此文本渲染到 Canvas 上。这工作正常,它显示出来,甚至将其添加到检查交集的 RayCaster 的网格体数组中,但是,函数 HandleSingleClick() 没有触发由于某种原因在 TextGeometry 上。

我已经使用立方体进行了测试,它确实有效。目的是,如果您单击 TextGeometry,它会改变颜色以表示您单击了它。但是,由于某种原因,以下脚本在处理文本时不起作用。我可以确认网格体已添加到 RayCaster checkin 的数组中,但由于某种原因它没有拾取它们。

import {
  Font,
  TextGeometry
} from '../js/libs/Three.es.js';
import FontJson from '../fonts/helvetiker_bold.typeface.json';

export default class TextExtension extends Autodesk.Viewing.Extension {

  constructor(viewer, options) {

      super()

      this.viewer = viewer
  }

  load() {
      console.log('Viewing.Extension.MeshSelection loaded')

      this.viewer.addEventListener(
          Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT, () => {

              this.dbIds = this.getAllDbIds()
              console.log(this.dbIds);

          });
      this.viewer.toolController.registerTool(this)

      this.viewer.toolController.activateTool(
          'MeshSelection')

      this.intersectMeshes = [];
      return true
  }


  /////////////////////////////////////////////////////////
  // Tool Interface
  //
  /////////////////////////////////////////////////////////
  getNames() {

      return ['MeshSelection']
  }

  activate() {

  }

  deactivate() {

  }

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

      console.log('MeshSelection unloaded')

      this.viewer.toolController.deactivateTool(
          'MeshSelection')

      this.viewer.toolController.unregisterTool(this)

      return true
  }

  /////////////////////////////////////////////////////////
  // Adds a box mesh with random size and position
  // to the scene
  //
  /////////////////////////////////////////////////////////
  addMesh() {

      const geometry = new THREE.BoxGeometry(
          Math.random() * 10 + 5.0,
          Math.random() * 10 + 5.0,
          Math.random() * 10 + 5.0)

      const color = Math.floor(Math.random() * 16777215)

      const material = this.createColorMaterial(color)

      const mesh = new THREE.Mesh(geometry, material)

      mesh.position.x = -50 + Math.random() * 25
      mesh.position.y = -50 + Math.random() * 25
      mesh.position.z = 1 + Math.random() * 1

      this.viewer.impl.scene.add(mesh)

      this.viewer.impl.sceneUpdated(true)

      return mesh
  }

  /////////////////////////////////////////////////////////
  // Creates color material from int
  //
  /////////////////////////////////////////////////////////
  createColorMaterial(color) {

      const material = new THREE.MeshPhongMaterial({
          specular: new THREE.Color(color),
          side: THREE.DoubleSide,
          reflectivity: 0.0,
          color
      })

      const materials = this.viewer.impl.getMaterials()

      materials.addMaterial(
          color.toString(16),
          material,
          true)

      return material
  }

  /////////////////////////////////////////////////////////
  // Creates Raycaster object from the pointer
  //
  /////////////////////////////////////////////////////////
  pointerToRaycaster(domElement, camera, pointer) {

      const pointerVector = new THREE.Vector3()
      const pointerDir = new THREE.Vector3()
      const ray = new THREE.Raycaster()

      const rect = domElement.getBoundingClientRect()

      const x = ((pointer.clientX - rect.left) / rect.width) * 2 - 1
      const y = -((pointer.clientY - rect.top) / rect.height) * 2 + 1

      if (camera.isPerspective) {

          pointerVector.set(x, y, 0.5)

          pointerVector.unproject(camera)

          ray.set(camera.position,
              pointerVector.sub(
                  camera.position).normalize())

      } else {

          pointerVector.set(x, y, -1)

          pointerVector.unproject(camera)

          pointerDir.set(0, 0, -1)

          ray.set(pointerVector,
              pointerDir.transformDirection(
                  camera.matrixWorld))
      }

      return ray
  }

  /////////////////////////////////////////////////////////
  // Click handler
  //
  /////////////////////////////////////////////////////////
  handleSingleClick(event) {
      console.log(this.intersectMeshes);

      const pointer = event.pointers ?
          event.pointers[0] :
          event
      console.log(pointer);
      const rayCaster = this.pointerToRaycaster(
          this.viewer.impl.canvas,
          this.viewer.impl.camera,
          pointer)

      const intersectResults = rayCaster.intersectObjects(
          this.intersectMeshes, true)
      console.log(intersectResults);

      const hitTest = this.viewer.model.rayIntersect(
          rayCaster, true, this.dbIds)

      const selections = intersectResults.filter((res) =>

          (!hitTest || (hitTest.distance > res.distance))
      )

      if (selections.length) {

          console.log('Custom meshes selected:')
          console.log(selections)
          selections[0].object.material.color = this.createColorMaterial(Math.floor(Math.random() * 16777215));
          viewer.impl.sceneUpdated(true);
          return true
      }

      return false
  }

  /////////////////////////////////////////////////////////
  // Get list of all dbIds in the model
  //
  /////////////////////////////////////////////////////////
  getAllDbIds() {

      const {
          instanceTree
      } = this.viewer.model.getData()

      const {
          dbIdToIndex
      } = instanceTree.nodeAccess

      return Object.keys(dbIdToIndex).map((dbId) => {
          return parseInt(dbId)
      })
  }

  createColorMaterial(color) {

      const material = new THREE.MeshPhongMaterial({
          specular: new THREE.Color(color),
          side: THREE.DoubleSide,
          reflectivity: 0.0,
          color
      })

      const materials = this.viewer.impl.getMaterials()

      materials.addMaterial(
          color.toString(),
          material,
          true)

      return material
  }


  /////////////////////////////////////////////////////////
  // Wraps TextGeometry object and adds a new mesh to  
  // the scene
  /////////////////////////////////////////////////////////
  createText(params, index) {
      const geometry = new TextGeometry(params.text,
          Object.assign({}, {
              font: new Font(FontJson),
              params
          }))
      geometry.computeBoundingBox();

      const material = this.createColorMaterial(
          params.color)

      const text = new THREE.Mesh(
          geometry, material)

      text.scale.set(params.scale, params.scale, params.scale);

      text.position.set(
          params.position.x,
          params.position.y,
          10)


      this.intersectMeshes[index] = text;
      this.viewer.impl.scene.add(text);

      this.viewer.impl.sceneUpdated(true)
  }
}

Autodesk.Viewing.theExtensionManager.registerExtension(
  'TextSpawner', TextExtension);

最佳答案

您需要调试光线转换逻辑以找出发生了什么。在查看器使用的 Three.js 版本中,有一个检查来查看测试网格中的几何对象是否为 THREE.BufferGeometry 或 THREE.Geometry 实例,如果没有,则不计算相交逻辑。

为了使其兼容,同时添加尽可能少的代码,我使用了以下方法:

  /////////////////////////////////////////////////////////
  // Wraps TextGeometry object and adds a new mesh to
  // the scene
  /////////////////////////////////////////////////////////
  createText (params) {

    const textGeometry = new TextGeometry(params.text,
      Object.assign({}, {
        font: new Font(FontJson),
        params
      }))

    // use a geometry recognized by the viewer 
    // THREE.js version
    const geometry = new THREE.BufferGeometry

    geometry.fromGeometry(textGeometry)

    const material = this.createColorMaterial(
      params.color)

    const text = new THREE.Mesh(
      geometry , material)

    text.position.set(
      params.position.x,
      params.position.y,
      params.position.z)

    this.viewer.impl.scene.add(text)

    this.viewer.impl.sceneUpdated(true)

    return text
  }

关于javascript - 如何在 Three.js 中使用 RayCaster 拾取文本网格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48590109/

相关文章:

javascript - 单击按钮时显示更多处于 react 状态的项目

javascript - 将用户 id 字段添加到 Accounts 包的 Meteor.Users 集合中

javascript - 使用 JavaScript 从超链接加载时的默认下拉值

javascript - 搜索引擎机器人 - 爬虫 - 蜘蛛 - 等是否有 javascript?

amazon-web-services - Three.js AWS S3 CORS

javascript - 当相机移动三个js时线消失

javascript - 我的代码有什么问题吗? (Threejs聚光灯阴影)

autodesk-forge - Autodesk Forge 获取访问 token

javascript - 纹理未显示在对象 Forge Three.js 上

javascript - 如何在节点旁边添加图像或 svg?