【问题标题】:How can I pick up text mesh with the RayCaster in Three.js?如何在 Three.js 中使用 RayCaster 拾取文本网格?
【发布时间】:2018-07-13 09:26:04
【问题描述】:

所以,我在使用RayCaster 接听TextGeometry 时遇到了问题。我正在使用下面的函数createText() 将此文本渲染到画布上。这很好用,它显示出来了,它甚至将它添加到RayCaster 的网格数组中,它检查交叉点,但是,由于某种原因,函数HandleSingleClick() 没有在 TextGeometries 上触发。

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

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);

【问题讨论】:

    标签: javascript three.js autodesk-forge


    【解决方案1】:

    您需要调试光线投射逻辑以了解发生了什么。在查看器使用的 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
      }
    

    【讨论】:

      猜你喜欢
      • 2020-09-01
      • 2014-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-18
      • 2013-04-14
      • 2015-12-25
      • 1970-01-01
      相关资源
      最近更新 更多