Почему мой щелчок по модели дает неверные координаты при использовании rotateOnAxis? - PullRequest
0 голосов
/ 24 марта 2020

Прежде всего, я хочу извиниться, если этот вопрос мне кажется глупым, и если мой код выглядит немного грязным. Я пытаюсь создать просмотрщик 360 с Three js, и хотя все работает, у меня проблемы с моим rotateOnAxis. У меня есть две кнопки, которые должны поворачивать объект на 45 градусов. Когда вы нажимаете на объект, он должен добавить «точку дефекта» в модель, как красная точка. Сначала все работает правильно, но как только вы нажимаете кнопки поворота и пытаетесь добавить точку, точка y добавляется неправильно.

car-viewer.component.ts

import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader';
import {
  AmbientLight, AxesHelper,
  Color,
  DirectionalLight, Group, Object3D,
  PerspectiveCamera,
  PointLight,
  Raycaster,
  Scene, Sprite, SpriteMaterial, TextureLoader,
  Vector2, Vector3,
  WebGLRenderer
} from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('canvas', {static: false}) canvas: HTMLCanvasElement;
  carImageSource: string;

  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();
  tile = null;
  selectedObject = null;
  car: Object3D;

  constructor() {
  }

  @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.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);
        }
        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;
    this.camera = new PerspectiveCamera(17.5, aspect, 1, 5000);
    this.loadCar();
    document.getElementById('scene').addEventListener('touchstart', (evt) => {
      console.log('click event fired');
      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);
          }
          console.log(this.selectedObject);
        }
      }
    }, false);
  }

  ngOnInit() {
    this.carImageSource = 'assets/360Viewer/hatchback_360.png';
  }

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

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

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

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

    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);
    // 1972_datsun_240k_gt_non_commercial_use_only - 0.15, 0.15, 0.15
    // porsche_panamera - 1, 1, 1
    // tesla_model_3 - 0.47, 0.47, 0.47
    this.loader.load('/assets/porsche_panamera/scene.gltf',
      (gltf) => {
        const car = gltf.scene.children[0];
        this.car = car;
        gltf.scene.name = 'car';
        this.scene.scale.set(1, 1, 1);
        car.scale.set(1, 1, 1);
        this.objectGroup.add(gltf.scene);

        this.renderer.setPixelRatio(this.tile.clientWidth / this.tile.clientHeight);
        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 sprite = new Sprite(spriteMaterial);
    sprite.position.set(point.x, point.y, point.z);
    sprite.scale.set(12.5, 12.5, 12.5);

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

  onRightClicked() {
    const rotationAxis = new Vector3(0, 1, 0);
    this.objectGroup.parent.rotateOnAxis(rotationAxis, -45);
    console.log(this.objectGroup.parent);
  }

  onLeftClicked() {
    const rotationAxis = new Vector3(0, 1, 0);
    this.objectGroup.parent.rotateOnAxis(rotationAxis, 45);
  }
}

car-viewer.component. html

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

car-viewer.component, css

.mat-figure {
  margin: 0px;
}

#scene {
  width: 100%;
  height: 100%;
}

#canvas {
  width: 100%;
  height: 100%;
}

#number {
  position: absolute;
  z-index: -1;
}

.annotation {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  margin-left: 15px;
  margin-top: 15px;
  padding: 1em;
  width: 200px;
  color: #fff;
  background: rgba(0, 0, 0, 0.8);
  border-radius: .5em;
  font-size: 12px;
  line-height: 1.2;
  transition: opacity .5s;
}

Я не знаю, будет ли полезен стек-блиц, но вот оно : https://stackblitz.com/edit/angular-7ockwf

Как я уже сказал, этот код может выглядеть плохо, но это моя первая попытка любого webgl. Если вы можете помочь мне, указав мне в правильном направлении. Есть два изображения. Один - это начальная нагрузка и добавленные точки вниз по центру автомобиля и на светофорах. Другое изображение после того, как я щелкнул вправо шесть раз и отметил те же пятна. Заранее спасибо. This image is after i clicked right six times and marked the same spots as the other image, lights, under lights and down the middle of the car.[![][1]] 2

...