Three.js renders a black scene because of texture loading.
I am using three.js inside an angular component (angular version 8).
I was trying to follow an old three.js tutorial on rendering Earth in WebGL which used now deprecated THREE.ImageUtils.loadTexture()
to load a texture for mesh material map.
It didn't work for me, so I tried using modern THREE.TextureLoader().load()
. However, for some reason, it never acted upon its callback.
So I tried using THREE.TextureLoader().load()
paired with THREE.LoadingManager()
. While THREE.LoadingManager()
's callback seems to work, it still produces only a black scene with some light.
While I'm new at using three.js, to me it seems that my code:
- Does include light
- Does seem to render not only once
- Doesn't throw any errors to console
Code:
In my component.html:
...
<div #rendererContainer></div>
...
In my component.ts:
import {Component, OnInit, ViewChild, ElementRef, AfterViewInit} from '@angular/core';
import * as THREE from 'three';
export class MyComponent implements OnInit, AfterViewInit {
@ViewChild('rendererContainer', {static: false}) rendererContainer: ElementRef;
renderer = new THREE.WebGLRenderer();
scene = null;
camera = null;
mesh = null;
earthSurface = new THREE.MeshStandardMaterial({color: 0xaaaaaa});
constructor() {
// scene and camera
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 1000);
this.camera.position.z = 1.5;
// light
this.scene.add(new THREE.AmbientLight(0x333333));
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 3, 5);
this.scene.add(light);
const manager = new THREE.LoadingManager();
const textureLoader = new THREE.TextureLoader(manager);
this.earthSurface.map = textureLoader.load('planet.jpg');
manager.onLoad = () => {
// call back
const geometry = new THREE.SphereGeometry(0.5, 32, 32);
this.mesh = new THREE.Mesh(
geometry,
this.earthSurface
);
this.scene.add(this.mesh);
this.rerender();
console.log(this.earthSurface);
};
}
ngOnInit() {}
ngAfterViewInit() {
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.rendererContainer.nativeElement.appendChild(this.renderer.domElement);
this.animate();
// setInterval(() => {this.rerender();}, 1.5 * 1000);
}
rerender() {
this.renderer.render(this.scene, this.camera);
}
animate() {
this.renderer.render(this.scene, this.camera);
window.requestAnimationFrame(() => this.animate());
}
}