Я пытаюсь создать 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>
Ниже представлены две фотографии. Я отметил «дефект» спереди, и спрайт виден, когда автомобиль виден сзади, и его не должно быть видно. Заранее спасибо за помощь.