Как я могу спрятать свой спрайт, если он находится за объектом? - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь создать 360-градусный автомобиль с маркерами дефектов. Все работает правильно, за исключением того, что спрайты показывают, даже если это позади автомобиля. Я хочу, чтобы он не был виден, если он находится за машиной. Я пытался получить доступ к материалу объекта, чтобы изменить прозрачность, но безуспешно. Я также попытался сделать заказ, но он не работает. Извините, если код грязный, я новичок в Three js.

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: true,
      depthTest: false,
      depthWrite: false
    });

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

    const sprite = new Sprite(spriteMaterial);
    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();
  }

  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>

Ниже представлены две фотографии. Я отметил «дефект» спереди, и спрайт виден, когда автомобиль виден сзади, и его не должно быть видно. Заранее спасибо за помощь. enter image description here

enter image description here

...