In my scenario, I have an asset inventory containing multiple assets. I am looking to implement a feature where whenever a user hovers over the assets, it triggers rendering with an OrbitController (Trackball is preferred but not feasible due to a bug). The challenge lies in the fact that the "this" variable of the class instance cannot be passed into the render method of the class:
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js';
import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r122/examples/jsm/controls/OrbitControls.js';
class Main {
constructor(canvasId)
{
this.canvas = document.querySelector(canvasId);
this.renderer = new THREE.WebGLRenderer({canvas: this.canvas});
this.fov = 75;
this.aspect = 2; // the canvas default
this.near = 0.1;
this.far = 5;
this.camera = new THREE.PerspectiveCamera(this.fov, this.aspect, this.near, this.far);
this.camera.position.z = 2;
this.controls = new OrbitControls(this.camera, this.canvas);
this.controls.target.set(0, 0, 0);
this.controls.update();
this.scene = new THREE.Scene();
this.color = 0xFFFFFF;
this.intensity = 1;
this.light = new THREE.DirectionalLight(this.color, this.intensity);
this.light.position.set(-1, 2, 4);
this.scene.add(this.light);
this.boxWidth = 1;
this.boxHeight = 1;
this.boxDepth = 1;
this.geometry = new THREE.BoxGeometry(this.boxWidth, this.boxHeight, this.boxDepth);
}
makeInstance(geometry, color, x){
let material = new THREE.MeshPhongMaterial(color);
let cube = new THREE.Mesh(geometry, material);
this.scene.add(cube);
cube.position.x = x;
return cube;
}
resizeRendererToDisplaySize(renderer) {
this.canvas = this.renderer.domElement;
let width = this.canvas.clientWidth;
let height = this.canvas.clientHeight;
let needResize = this.canvas.width !== width || this.canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
render() {
// this -> control object or window whereas it should be the class instance
if (this.resizeRendererToDisplaySize(this.renderer)) {
this.canvas = this.renderer.domElement;
this.camera.aspect = this.canvas.clientWidth / this.canvas.clientHeight;
this.camera.updateProjectionMatrix();
}
this.renderer.render(this.scene, this.camera);
}
starter() {
this.makeInstance(this.geometry, 0x44aa88, 0);
this.makeInstance(this.geometry, 0x8844aa, -2);
this.makeInstance(this.geometry, 0xaa8844, 2);
this.render();
this.controls.addEventListener('change', this.render);
window.addEventListener('resize', this.render);
// note: this is a workaround for an OrbitControls issue
// in an iframe. Will remove once the issue is fixed in
// three.js
window.addEventListener('mousedown', (e) => {
e.preventDefault();
window.focus();
});
window.addEventListener('keydown', (e) => {
e.preventDefault();
});
}
}
let main = new Main('#a');
main.starter();
To address the issue, I had to replace "this" with the "main" instance in the render method. However, this approach compromises the class structure and restricts the generation of other instances like main2. For a live demo, please refer to the following CodePen link: https://codepen.io/jimver04/pen/XWjLPLo