Любой способ заставить спрайт частично не «исчезнуть» при размещении на Object3D - PullRequest
0 голосов
/ 30 марта 2020

извините, что беспокою, я совсем новичок в Три js, и я борюсь. Я пытаюсь создать 360-градусный автомобильный просмотрщик, в который можно добавлять маркеры дефектов (спрайты). Когда вы нажимаете на автомобиль, он добавляет маркер, но маркер частично исчезает (см. Скриншоты ниже). Мне нужно, чтобы для параметра deepTest было установлено значение true, поскольку, когда маркер находится за автомобилем, он не должен быть виден.

car-viewer.component.ts

import {AfterViewInit, Component, ElementRef, HostListener, OnInit, ViewChild} from '@angular/core';
import {ScanCommunication} from '../services/scan-communication.service';
import {Car} from '../models/car.model';
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
import {
  AmbientLight, AxesHelper, Box3, Box3Helper,
  Color,
  DirectionalLight, Group, Object3D,
  PerspectiveCamera,
  PointLight,
  Raycaster,
  Scene, Sprite, SpriteMaterial, TextureLoader,
  Vector2, Vector3,
  WebGLRenderer
} from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import {MathUtils} from 'three/examples/jsm/utils/MathUtils';
import {_Math} from 'three/src/math/Math';
import degToRad = _Math.degToRad;
import {reduce} from 'rxjs/operators';

export interface Coordinates {
  x: number;
  y: number;
  z: number;
}

@Component({
  selector: 'app-car-viewer',
  templateUrl: './car-viewer.component.html',
  styleUrls: ['./car-viewer.component.css'],
  providers: []
})
export class CarViewerComponent implements OnInit, AfterViewInit {
  @ViewChild('canvas', {static: false}) canvas: HTMLCanvasElement;
  carData: Car;

  scene = new Scene();
  camera = null;
  hLight = new AmbientLight(0x404040, 100);
  directionalLight = new DirectionalLight(0xffffff, 100);
  pointLight1 = new PointLight(0xc4c4c4, 10);
  pointLight2 = new PointLight(0xc4c4c4, 10);
  pointLight3 = new PointLight(0xc4c4c4, 10);
  pointLight4 = new PointLight(0xc4c4c4, 10);
  renderer = new WebGLRenderer({antialias: true, canvas: this.canvas});
  loader = new GLTFLoader();
  objectGroup = new Group();
  axesHelper = new AxesHelper(200);
  controls = null;
  mousePosition = new Vector2();
  rayCaster = new Raycaster();
  axis = new Vector3(0, 1, 0);
  step = Math.PI * 0.25;
  tile = null;
  selectedObject = null;
  car: Object3D;
  box = new Box3();

  constructor(private scannedData: ScanCommunication) {
    this.carData = scannedData.getCar();
    this.renderer.autoClear = false;
  }

  @HostListener('window:resize', ['$event'])
  onResize(event) {
    // this.tile = document.getElementById('viewerTile');
    this.renderer.setSize(this.tile.clientWidth, this.tile.clientHeight);
    this.camera.aspect = this.tile.clientWidth / this.tile.clientHeight;
    this.camera.updateProjectionMatrix();
  }

  // @HostListener('touchstart', ['$event'])
  onDocumentTouchStart(evt) {
    console.log('click event fired');
    evt.preventDefault();
    if (evt.cancelable) {
      evt.preventDefault();
    }

    if (this.selectedObject) {
      this.selectedObject = null;
    }

    const rect = this.renderer.domElement.getBoundingClientRect();
    this.mousePosition.x = + ( ( evt.changedTouches[0].pageX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
    this.mousePosition.y = - ( ( evt.changedTouches[0].pageY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
    this.rayCaster.setFromCamera(this.mousePosition, this.camera);
    const intersects = this.rayCaster.intersectObjects(this.objectGroup.children, true);
    if (intersects.length > 0) {
      const res = intersects.filter(( intersection ) => {

        return intersection && intersection.object;

      } )[ 0 ];

      if ( res && res.object ) {
        this.selectedObject = res.object;
        if (this.selectedObject.type === 'Sprite') {
          console.log('%cClicked on Sprite with uuid:  ' + this.selectedObject.uuid, 'background: #222; color: #bada55');
          this.selectedObject.material.color.set( '#f00' );
        } else {
          this.load(intersects[0].point);
        }
        console.log(this.selectedObject);
      }
    }
  }

  @HostListener('touchmove', ['$event'])
  onDocumentTouchMove(evt) {
    if (evt.cancelable) {
      evt.preventDefault();
    }
    console.log('touchmove');
  }

  ngAfterViewInit() {
    this.scene.add(this.axesHelper);
    this.tile = document.getElementById('viewerTile');
    const aspect = this.tile.clientWidth / this.tile.clientHeight;
    // fov: 1.75
    this.camera = new PerspectiveCamera(17.5, aspect, 1, 5000);
    this.loadCar();
    document.getElementById('scene').addEventListener('touchstart', (evt) => {
      evt.preventDefault();
      if (evt.cancelable) {
        evt.preventDefault();
      }

      if (this.selectedObject) {
        // this.selectedObject.material.color.set( '#f9f9f9' );
        this.selectedObject = null;
      }

      const rect = this.renderer.domElement.getBoundingClientRect();
      this.mousePosition.x = + ( ( evt.changedTouches[0].pageX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
      this.mousePosition.y = - ( ( evt.changedTouches[0].pageY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
      this.rayCaster.setFromCamera(this.mousePosition, this.camera);
      console.log(this.mousePosition);
      const intersects = this.rayCaster.intersectObjects(this.objectGroup.children, true);
      console.log('intersects length: ' + intersects.length);
      if (intersects.length > 0) {
        const res = intersects.filter(( intersection ) => {

          return intersection && intersection.object;

        } )[ 0 ];

        if ( res && res.object ) {
          this.selectedObject = res.object;
          if (this.selectedObject.type === 'Sprite') {
            console.log('%cClicked on Sprite with uuid:  ' + this.selectedObject.uuid, 'background: #222; color: #bada55');
            this.selectedObject.material.color.set( '#f00' );
          } else {
            this.load(intersects[0].point);
          }
        }
      }
    }, false);

    document.getElementById('scene').addEventListener('touchend', (evt) => {
      evt.preventDefault();
      const mousePosition = new Vector2();
      const rect = this.renderer.domElement.getBoundingClientRect();
      mousePosition.x = + ( ( evt.changedTouches[0].pageX - rect.left ) / ( rect.width - rect.left ) ) * 2 - 1;
      mousePosition.y = - ( ( evt.changedTouches[0].pageY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
      console.log('touchend: ' + JSON.stringify(mousePosition));
    }, false);
  }

  ngOnInit() {
  }

  loadCar() {
    this.scene.add(this.objectGroup);
    this.scene.background = new Color(0xdddddd);
    this.objectGroup.add(this.hLight);

    this.camera.rotation.y = 15 / 180 * Math.PI;
    this.camera.position.x = 0;
    this.camera.position.y = 500;
    this.camera.position.z = 1200;
    this.camera.lookAt(0, 0, 0);

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.minDistance = 750;
    this.controls.maxDistance = 1500;
    this.controls.maxPolarAngle = Math.PI / 2;
    this.controls.autoRotate = false;
    this.controls.enableZoom = true;
    this.controls.enablePan = true;
    this.controls.update();

    this.directionalLight.position.set(0, 1, 0);
    this.directionalLight.castShadow = true;
    // this.objectGroup.add(this.directionalLight);

    this.pointLight1.position.set(0, 300, 500);
    // this.objectGroup.add(this.pointLight1);

    this.pointLight2.position.set(500, 100, 0);
    // this.objectGroup.add(this.pointLight2);

    this.pointLight3.position.set(0, 100, -500);
    // this.objectGroup.add(this.pointLight3);

    this.pointLight4.position.set(-500, 300, 0);
    // this.objectGroup.add(this.pointLight4);

    this.renderer.setSize(this.tile.clientWidth, this.tile.clientHeight);
    this.renderer.domElement.id = 'canvas';
    const cvs = document.getElementById('scene').appendChild(this.renderer.domElement);
    // mercedes-benz_gla-220_amg - hatchback
    // porsche_panamera - grand tourer
    // tesla_model_3 - sedan
    // 2019_ford_ranger_raptor_civil_cities_skylines - bakkie
    this.loader.load('/assets/lamborghini_urus/scene.gltf',
      (gltf) => {
        const car = gltf.scene.children[0];
        this.scene.scale.set(1, 1, 1);
        car.scale.set(1, 1, 1);
        this.car = car;
        gltf.scene.name = 'car';
        // gltf.scene.overrideMaterial.transparent = false;
        this.objectGroup.add(gltf.scene);

        this.renderer.setPixelRatio(this.tile.clientWidth / this.tile.clientHeight);

        this.box = new Box3().setFromObject(this.car);
        const color = new Color( 'skyblue' );
        const boxHelper = new Box3Helper(this.box, color);
        boxHelper.name = 'boundingBox';
        const size = new Vector3();
        console.log(this.box.min, this.box.max, this.box.getSize(size));

        this.autoScale(size);
        // this.scene.add(boxHelper);

        this.animate();
      });
  }

  animate() {
    window.requestAnimationFrame(() => this.animate());
    this.controls.update();
    this.renderer.render(this.scene, this.camera);
  }

  load(point) {
    const texture = new TextureLoader().load('assets/marker.gif');
    const spriteMaterial = new SpriteMaterial({
      map: texture,
      alphaTest: 0.5,
      transparent: false,
      depthTest: true,
      depthWrite: false
    });

    const size = new Vector3();
    this.box.getSize(size);

    const sprite = new Sprite(spriteMaterial);

    // this.setSpritePosition(sprite, size, point.x, point.y, point.z);

    sprite.position.set(point.x, point.y, point.z);

    sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);

    this.objectGroup.add(sprite);
    this.animate();
  }

  setSpritePosition(sprite, size, x, y, z) {
    console.log(x, y, z);
    const multiplier = 0.08;
    if (x > 0) {
      x = x + (multiplier * x);
      if (y > 0) {
        y = y + (multiplier * y);
        if (z > 0) {
          z = z + (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
        if (z < 0) {
          z = z - (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
      }
      if (y < 0) {
        y = y - (multiplier * y);
        if (z > 0) {
          z = z + (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
        if (z < 0) {
          z = z - (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
      }
    }
    if (x < 0) {
      x = x + (multiplier * x);
      if (y > 0) {
        // y = y + (multiplier * y);
        if (z > 0) {
          z = z + (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
        if (z < 0) {
          z = z - (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
      }
      if (y < 0) {
        y = y - (multiplier * y);
        if (z > 0) {
          z = z + (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
        if (z < 0) {
          z = z - (multiplier * z);
          sprite.position.set(x, y, z);
          sprite.scale.set(0.1 * size.x, 0.1 * size.x, 0.1 * size.x);
          this.objectGroup.add(sprite);
          this.animate();
        }
      }
    }
  }

  autoScale(size) {
    const x = 0;
    const z = size.z * 4;
    const y = size.y;
    this.camera.position.x = x;
    this.camera.position.y = y;
    this.camera.position.z = z;
  }

  onRightClicked() {
    this.camera.position.applyAxisAngle(this.axis, this.step);
  }

  onLeftClicked() {

    this.camera.position.applyAxisAngle(this.axis, -this.step);
  }
}

car-viewer.component. html

<mat-grid-list cols="1" rowHeight="50%">
  <mat-grid-tile id="viewerTile" colspan="1" rowspan="1">
    <div id="scene"></div>
  </mat-grid-tile>
  <mat-grid-tile colspan="1" rowspan="1" style="background: grey">
    <button (click)="onLeftClicked()">Left</button>
    <button (click)="onRightClicked()">Right</button>
  </mat-grid-tile>
</mat-grid-list>

Как видите, я пытался изменить вручную положение в соответствии со значением балла, но оно не работает должным образом. Мне было интересно, есть ли способ, которым я могу достичь этого. Извините, если код грязный, я новичок в ТРИ JS и пытаюсь разобраться с этим. Заранее спасибо.

Это то, что сейчас происходит. Спрайт частично исчезает. Мой ожидаемый результат - он НЕ исчезнет.

This is what is currently happening. The sprite partially disappears. My expected result is to have it NOT disappear.

...