There seems to be something that I don't understand in this code here. It keeps on throwing an error, although all seems correct to me. Possibly someone can spot it...
I know the class is quite long but I thought it would be better to insert the whole code. It crashed inside createScene()
method when I try to add my 3D model to the scene with this.scene.add(object) although the scene has been initialized at the top of this method with this.scene = new THREE.Scene()
and I also have tried initializing it on top of the class with an empty object but that doesn't help.
To be honest quite new to angular and no idea where to look for the error. The error reads Cannot read property 'scene' of undefined.
The strangest thing is that if this line is commented out the same lines are used to add light in create light method and it seems to be fine. The obj 3D model loads fine as well and doesn't go into error brackets so its not that I guess.
Would be really grateful if someone could spot the error. Thanks.
import { AfterContentInit, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import * as THREE from 'three-full';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements AfterContentInit {
private renderer: THREE.WebGLRenderer;
private camera: THREE.PerspectiveCamera;
private cameraTarget: THREE.Vector3;
public scene: THREE.Scene = {make: null};
public fieldOfView: number = 60;
public nearClippingPane: number = 1;
public farClippingPane: number = 1100;
public controls: THREE.OrbitControls;
@ViewChild('canvas')
private canvasRef: ElementRef;
constructor() {
this.render = this.render.bind(this);
this.onModelLoadingCompleted = this.onModelLoadingCompleted.bind(this);
}
ngAfterContentInit() {
this.createScene();
this.createLight();
this.createCamera();
this.startRendering();
this.addControls();
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
private createScene() {
this.scene = new THREE.Scene();
var objLoader = new THREE.OBJLoader();
var myMan: any = {};
objLoader.load(
// resource URL
'/assets/man.obj',
// called when resource is loaded
function ( object ) {
myMan = object;
this.scene.add(object);
},
// called when loading is in progresses
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
}
public render() {
this.renderer.render(this.scene, this.camera);
}
private onModelLoadingCompleted(collada) {
var modelScene = collada.scene;
this.scene.add(modelScene);
this.render();
}
private createLight() {
var light = new THREE.PointLight(0xffffff, 1, 1000);
light.position.set(0, 0, 100);
this.scene.add(light);
var light = new THREE.PointLight(0xffffff, 1, 1000);
light.position.set(0, 0, -100);
this.scene.add(light);
}
private createCamera() {
let aspectRatio = this.getAspectRatio();
this.camera = new THREE.PerspectiveCamera(
this.fieldOfView,
aspectRatio,
this.nearClippingPane,
this.farClippingPane
);
// Set position and look at
this.camera.position.x = 10;
this.camera.position.y = 10;
this.camera.position.z = 100;
}
private getAspectRatio(): number {
let height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private startRendering() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true
});
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setClearColor(0xffffff, 1);
this.renderer.autoClear = true;
let component: HomeComponent = this;
(function render() {
//requestAnimationFrame(render);
component.render();
}());
}
public addControls() {
this.controls = new THREE.OrbitControls(this.camera);
this.controls.rotateSpeed = 1.0;
this.controls.zoomSpeed = 1.2;
this.controls.addEventListener('change', this.render);
}
public onMouseDown(event: MouseEvent) {
console.log("onMouseDown");
event.preventDefault();
// Example of mesh selection/pick:
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / this.renderer.domElement.clientWidth) * 2 - 1;
mouse.y = - (event.clientY / this.renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, this.camera);
var obj: THREE.Object3D[] = [];
this.findAllObjects(obj, this.scene);
var intersects = raycaster.intersectObjects(obj);
console.log("Scene has " + obj.length + " objects");
console.log(intersects.length + " intersected objects found")
intersects.forEach((i) => {
console.log(i.object); // do what you want to do with object
});
}
private findAllObjects(pred: THREE.Object3D[], parent: THREE.Object3D) {
// NOTE: Better to keep separate array of selected objects
if (parent.children.length > 0) {
parent.children.forEach((i) => {
pred.push(i);
this.findAllObjects(pred, i);
});
}
}
public onMouseUp(event: MouseEvent) {
console.log('Mouse Up');
}
@HostListener('window:resize', ['$event'])
public onResize(event: Event) {
this.canvas.style.width = "100%";
this.canvas.style.height = "100%";
console.log("onResize: " + this.canvas.clientWidth + ", " + this.canvas.clientHeight);
this.camera.aspect = this.getAspectRatio();
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.render();
}
@HostListener('document:keypress', ['$event'])
public onKeyPress(event: KeyboardEvent) {
console.log("onKeyPress: " + event.key);
}
}