2

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:

  1. Does include light
  2. Does seem to render not only once
  3. 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());
  }

}

1 Answer 1

2

I tested out and your code works with some suggestions

You can totally drop rerender function and just make sure to load the color of your scene like this:

this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xf5f5f5);

Make sure, that image that you load has a correct path, you can try out:

this.earthSurface.map = textureLoader.load('https://upload.wikimedia.org/wikipedia/commons/b/b8/Exploding_planet.jpg');
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, it turned out exactly as you said - the issue was caused by the combination of this.scene.background not being set as well as textureLoader.load() not being able to resolve my path for some weird reason.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.