Прежде всего, я хочу извиниться, если этот вопрос мне кажется глупым, и если мой код выглядит немного грязным. Я пытаюсь создать просмотрщик 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. Если вы можете помочь мне, указав мне в правильном направлении. Есть два изображения. Один - это начальная нагрузка и добавленные точки вниз по центру автомобиля и на светофорах. Другое изображение после того, как я щелкнул вправо шесть раз и отметил те же пятна. Заранее спасибо. ] 2