Gridens - информационные технологии

Как я могу подобрать текстовую сетку с помощью RayCaster в Three.js?

Итак, я столкнулся с проблемой при использовании RayCaster для получения TextGeometry. Я использую функцию createText() ниже, чтобы отобразить этот текст на холсте. Это работает нормально, оно отображается и даже добавляет его в массив мешей для RayCaster проверки на пересечение, однако функция HandleSingleClick() по какой-то причине не срабатывает на TextGeometries.

Я тестировал с помощью кубов, и это работает. Намерение состоит в том, что если вы нажмете на TextGeometry, он изменит цвет, чтобы обозначить, что вы нажали на него. Однако по какой-то причине следующий скрипт не работает с текстом. Я могу подтвердить, что сетки добавляются в массив, который регистрирует 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);

Ответы:


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
  }
05.02.2018
Новые материалы

Журналы Py № 2: Если, Элиф, Иначе?
У меня такое чувство, будто я давно ничего не писал, хотя прошло два дня с тех пор, как я опубликовал свою первую историю. В любом случае, сегодня произошло много всего, так что приступим...

Работа в Реакции
Я изучаю React в Bloc прямо сейчас. До сих пор я изо всех сил пытался понять темы. Тем не менее, я только что закончил проблему, над которой некоторое время размышлял, и хочу записать свой..

Нужен ли банкам искусственный интеллект, чтобы кардинально изменить свою работу?
Почему необходимо использовать искусственный интеллект в банковской сфере? Существенное использование многочисленных инноваций ИИ, таких как машинное обучение , глубокое обучение и..

Какую последнюю статью вы считаете стоящей поделиться?
Я люблю читать качественные статьи. Не стесняйтесь делиться своей работой.

Преобразование CoreML, позволяющее использовать Fast-Neural-Style-Transfer на iOS и MacOS.
Как использовать Fast-Neural-Style-Transfer на iOS Преобразованная модель: GitHub — john-rocky/CoreML-Models: Преобразованный зоопарк моделей CoreML...

ИИ в правоохранительных органах: мощный инструмент с двойной природой
Искусственный интеллект (ИИ) революционизирует правоохранительную деятельность, предлагая инновационные тактики расследования, повышая достоверность доказательств и оптимизируя процессы. Тем..

Autoencoder Average Distance  — классический способ, используемый внутри Microsoft для выявления сходства…
Среднее расстояние автоэнкодера (AAD) использует более простой подход для определения расстояния между двумя наборами данных. Нейронный автоэнкодер может преобразовать любой элемент данных в..