Hi I am trying to load a glb file using threejs library which is working fine. I want to draw a rectangle on that 3D object model but due to some reason mousedown event is not getting triggered.
Here is the code sample:-
import { Component, ViewChild, ElementRef, AfterViewInit, OnInit , NgZone} from '@angular/core';
import * as THREE from 'three';
// import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls';
import { FlexAlignStyleBuilder } from '@angular/flex-layout';
const fov = 45;
const near = 5;
const far = 100;
@Component({
selector: 'ms-building-model-two-d-view',
templateUrl: './building-model-two-d-view.component.html',
styleUrls: ['./building-model-two-d-view.component.scss']
})
export class BuildingModelTwoDViewComponent implements OnInit, AfterViewInit {
@ViewChild('viewContainer') viewContainer: ElementRef;
// canvas: any;
@ViewChild('canvas') canvas: ElementRef;
view = 'front';
scene: any;
renderer: any;
camera: any;
controls: any;
loader: any;
dracoLoader: any;
model: any;
target: any;
width: any;
height: any;
dragging: boolean;
rayCaster: any;
startPosition: any = {
x: 0,
y: 0
};
vertexSize: any;
geometry: any;
constructor(private zone: NgZone) {
}
ngOnInit(): void {
}
ngAfterViewInit(): void {
// return;
this.rayCaster = new THREE.Raycaster();
this.geometry = new THREE.PlaneGeometry( 0, 0 );
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas.nativeElement
});
this.width = this.canvas.nativeElement.clientWidth;
this.height = this.canvas.nativeElement.clientHeight;
this.interactionsSetup()
this.renderer.setSize(this.width - 20, this.height);
this.renderer.setPixelRatio(window.devicePixelRatio);
// this.viewContainer.nativeElement.appendChild(this.renderer.domElement);
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color('black');
this.cameraSetup();
this.lightSetup();
this.objectSetup()
}
onViewChanges = (event) => {
this.view = event.value;
this.cameraSetup()
}
cameraSetup() {
const position = []
if (this.view === 'front') {
position.push(100, 0, 0)
} else if (this.view === 'side') {
position.push(0, 0, 100)
} else if (this.view === 'top') {
position.push(0, 100, 0)
}
this.camera = new THREE.OrthographicCamera(
this.width / - 2, this.width / 2, this.height / 2, this.height / - 2, 1, 1000 )
// 0, 0, 0, 0, near, far);
this.camera.zoom = 10;
this.camera.position.set(...position);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
// this.prospectiveCamera = new THREE.PerspectiveCamera(fov, 0, near, far);
// this.prospectiveCamera.position.set(10, 10, 10);
// this.prospectiveControls = new OrbitControls(this.prospectiveCamera, this.prospectiveContainer.nativeElement);
// this.prospectiveControls.update();
}
lockRotation = (event) => {
if (event.checked) {
this.controls.enableRotate = false;
this.controls.enable = false;
} else {
this.controls.enableRotate = true;
this.controls.enable = true;
}
this.controls.update();
}
// lightSetup() {
// const color = 0xFFFFFF;
// const intensity = 1;
// const light = new THREE.DirectionalLight(color, intensity);
// light.position.set(0, 10, 0);
// light.target.position.set(-5, 0, 0);
// this.scene.add(light);
// this.scene.add(light.target);
// }
lightSetup = () => {
this.addAmbientLight();
this.addSpotLight();
this.addRectLight();
this.addPointLight(0xfff000, { x: 0, y: 10, z: -100 });
this.addPointLight(0x79573e, { x: 100, y: 10, z: 0 });
this.addPointLight(0xc27439, { x: 20, y: 5, z: 20 });
}
addAmbientLight = () => {
const light = new THREE.AmbientLight("#ffffff", 1);
this.scene.add(light);
}
addSpotLight = () => {
const light = new THREE.SpotLight("#ca6631", 1, 10000);
light.position.set(-5, 100, -5);
// light.shadowMap = new THREE.Vector2(4096, 4096);
light.shadowBias = 0.001;
light.castShadow = true;
this.scene.add(light);
}
addRectLight = () => {
const light = new THREE.RectAreaLight("#341212", 1, 2000, 2000);
light.position.set(5, 50, 50);
light.lookAt(0, 0, 0);
this.scene.add(light);
}
addPointLight = (color, position) => {
const light = new THREE.PointLight(color, 1, 1000, 1);
light.position.set(position.x, position.y, position.z);
this.scene.add(light);
}
objectSetup = () => {
// const cubeSize = 4;
// const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
// const cubeMat = new THREE.MeshPhongMaterial({color: '#8AC'});
// const mesh = new THREE.Mesh(cubeGeo, cubeMat);
// mesh.position.set(0, 0, 0);
// this.scene.add(mesh);
/*
* Create a Rectangle
*/
this.geometry.vertices.push(new THREE.Vector3(-this.vertexSize, this.vertexSize, 0.0));
this.geometry.vertices.push(new THREE.Vector3(this.vertexSize, this.vertexSize, 0.0));
this.geometry.vertices.push(new THREE.Vector3(this.vertexSize, -this.vertexSize, 0.0));
this.geometry.vertices.push(new THREE.Vector3(-this.vertexSize, -this.vertexSize, 0.0));
this.geometry.faces.push(new THREE.Face3(0, 1, 2));
this.geometry.faces.push(new THREE.Face3(0, 2, 3));
const material = new THREE.MeshBasicMaterial({
color: 0xDB1E1E,
wireframe: true,
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(this.geometry, material);
mesh.rotation.x = Math.PI / 2;
this.scene.add(mesh);
this.loader = new GLTFLoader();
this.dracoLoader = new DRACOLoader();
this.dracoLoader.setDecoderPath("three/examples/js/libs/draco/");
this.loader.setDRACOLoader(this.dracoLoader);
this.loader.load('../../../../assets/model/blender_optimize.glb', (gltf) => {
const box = new THREE.Box3().setFromObject(gltf.scene);
const center = new THREE.Vector3();
box.getCenter(center);
gltf.scene.position.sub( center ); // center the model
gltf.scene.rotation.y = Math.PI;
// gltf.scene.position.x += gltf.scene.position.x - center.x;
// gltf.scene.position.y += gltf.scene.position.y - center.y;
// gltf.scene.position.z += gltf.scene.position.z - center.z;
this.scene.add(gltf.scene);
// gltf.scene.matrixAutoUpdate = false;
// gltf.scene.updateMatrix()
// new TrackballControls( this.camera , this.renderer.domElement);
this.render()
// this.canvasSetup();
}, (xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
// called when loading has errors
(error) => {
console.log('An error happened');
});
}
interactionsSetup = () => {
// this.canvas = this.renderer.domElement;
// console.log(this.canvas)
this.canvas.nativeElement.addEventListener('mousedown',
this.logThis.bind(this))
// this.canvas.nativeElement.onmousemove = this.onDrag.bind(this);
// this.canvas.nativeElement.onmouseup = this.onMouseUp.bind(this);
}
get3DPosition = (event) => {
const offset = this.canvas.nativeElement.getBoundingClientRect();
const position = {
x: ((event.clientX - offset.left) / this.canvas.nativeElement.clientWidth) * 2 - 1,
y: -((event.clientY - offset.top) / this.canvas.nativeElement.clientHeight) * 2 + 1
};
this.rayCaster.setFromCamera(position, this.camera);
const intersects = this.rayCaster.intersectObjects(this.scene.children, true);
if (intersects.length > 0) {
return intersects[0].point;
}
}
onMouseDown = (e) => {
// debugger;
console.log('Mouse Down')
const relative = this.get3DPosition(e);
if (!relative) {
return;
}
this.dragging = true;
this.startPosition.x = e.pageX;
this.startPosition.y = e.pageY;
this.scene.children[1].position.set(relative.x + this.vertexSize, relative.y, relative.z);
// this.controls.enabled = false;
}
onDrag = (e) => {
if (this.dragging) {
const clientX = (e.pageX - this.startPosition.x) / 10;
const clientY = (e.pageY - this.startPosition.y) / 10;
const vertices = this.geometry.vertices;
vertices[1].x = -clientX * -1;
vertices[2].x = -clientX * -1;
vertices[2].y = -clientY * -1;
vertices[3].y = -clientY * -1;
this.geometry.verticesNeedUpdate = true;
}
}
onMouseUp = () => {
this.dragging = false;
}
startAnimationLoop = () => {
// this.target.x = (1 - this.mouse.x) * 0.001;
// this.target.y = (1 - this.mouse.y) * 0.001;
// this.renderer.render(this.scene, this.camera);
window.requestAnimationFrame(this.startAnimationLoop);
}
render() {
this.resizeRendererToDisplaySize();
// turn on the scissor
// this.renderer.setScissorTest(true);
this.scene.background.set(0xffffff);
// render from the 1st camera
// const elementViewSize = this.setScissorForElement(this.viewContainer.nativeElement);
const canvasRect = this.canvas.nativeElement.getBoundingClientRect();
const elementViewSize = {
width: canvasRect.width,
height: canvasRect.height
}
// adjust the camera for this aspect
this.camera.left = elementViewSize.width / -2;
this.camera.right = elementViewSize.width / 2;
this.camera.top = elementViewSize.height / 2;
this.camera.bottom = elementViewSize.height / -2;
this.camera.updateProjectionMatrix();
this.renderer.render(this.scene, this.camera);
// elementViewSize = this.setScissorForElement(this.prospectiveContainer.nativeElement);
// // adjust the camera for this aspect
// this.prospectiveCamera.aspect = elementViewSize.width / elementViewSize.height;
// this.prospectiveCamera.updateProjectionMatrix();
// // render
// this.renderer.render(this.scene, this.prospectiveCamera);
window.requestAnimationFrame(this.render.bind(this));
}
resizeRendererToDisplaySize() {
// this.canvas = this.renderer.domElement;
const width = this.canvas.nativeElement.clientWidth;
const height = this.canvas.nativeElement.clientHeight;
const needResize = this.canvas.nativeElement.width !== width || this.canvas.nativeElement.height !== height;
if (needResize) {
this.renderer.setSize(width - 20, height, false);
}
return needResize;
}
// setScissorForElement (elem) {
// const canvasRect = this.canvas.getBoundingClientRect();
// const elemRect = elem.getBoundingClientRect();
// // compute a canvas relative rectangle
// const right = Math.min(elemRect.right, canvasRect.right) - canvasRect.left;
// const left = Math.max(0, elemRect.left - canvasRect.left);
// const bottom = Math.min(elemRect.bottom, canvasRect.bottom) - canvasRect.top;
// const top = Math.max(0, elemRect.top - canvasRect.top);
// const width = Math.min(canvasRect.width, right - left);
// const height = Math.min(canvasRect.height, bottom - top);
// // setup the scissor to only render to that part of the canvas
// const positiveYUpBottom = canvasRect.height - bottom;
// // const x = top
// this.renderer.setScissor(left, top, width, height);
// this.renderer.setViewport(left, top, width, height);
// // return the aspect
// return {
// width: width,
// height: height
// };
// }
logThis() {
alert('clicked')
}
}
Check interactionsSetup method, There I am trying to add an eventListener which mousedown to the canvas, But its not working.
I should be able to click on the canvas and when I do, it should alert “Clicked”.