2

i'm trying to get a simple canvas to load a simple stl file on an angular project and don't seem to be able to get this to work...

I tried many guides and nothing seem to work. when using native javascript with the same kind of code it works perfectly.

I have a canvas with a viewchild: <canvas #myCanvas></canvas> in my html.

In my .ts file:

import {Component, ViewChild, AfterViewInit} from '@angular/core';
import * as THREE from 'three';
var OrbitControls = require('three-orbit-controls')(THREE)
var STLLoader = require('three-stl-loader')(THREE)
var loader = new STLLoader()
import Scene = THREE.Scene;
import Mesh = THREE.Mesh;
import PerspectiveCamera = THREE.PerspectiveCamera;
import WebGLRenderer = THREE.WebGLRenderer;
import TrackballControls = THREE.TrackballControls;
import {log} from "util";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit{
  ngAfterViewInit(): void {
    this.myCanvas.nativeElement.style.background = "grey";
    this.myCanvas.nativeElement.style.width="1000px"
    this.myCanvas.nativeElement.style.height="500px"
  }

  @ViewChild("myCanvas") myCanvas;
  private scene: Scene;
  private camera: PerspectiveCamera;
  private renderer: WebGLRenderer;
  private controls: TrackballControls;
  title = 'app works!';
  constructor(){
    this.init3D();
  }
  init3D(){
    log("init3D")
    // renderer
    this.renderer = new THREE.WebGLRenderer({alpha: true, canvas: this.myCanvas});
    log(""+window.innerWidth+" "+ window.innerHeight )
    this.renderer.setSize( window.innerWidth, window.innerHeight );

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

    // camera
    this.camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.01, 10000 );

    this.camera.position.set( 113, 111, 113 );
    this.scene.add( new THREE.AmbientLight( 0x222222 ) );

    this.scene.add( this.camera ); // required, because we are adding a light as a child of the camera

    // controls
    this.controls = OrbitControls;

    // lights

    var light = new THREE.PointLight( 0xffffff, 0.8 );
    this.camera.add( light );

    loader.load('./assets/plate.stl', geometry => {
      var material = new THREE.MeshNormalMaterial()
      var mesh = new THREE.Mesh(geometry, material)
      log(this.scene.toJSON())
      this.scene.add(mesh)
    })

    this.animate();

    window.addEventListener( 'resize', this.onWindowResize, false );
  }

  animate() {

    window.requestAnimationFrame(_ => this.animate());

    this.camera.lookAt( this.scene.position );

    this.renderer.render(this.scene, this.camera);

  }

  onWindowResize() {

    this.camera.aspect = window.innerWidth / window.innerHeight;

    this.camera.updateProjectionMatrix();

    this.renderer.setSize( window.innerWidth, window.innerHeight );

  }

}

I get no errors but there is nothing in my canvas when the page finish to load. What am i missing here?

2 Answers 2

9

I got it to run, i'm posting a working code if some one will need it in the future.

The problem was my canvas wasn't initialized yet, when i moved the 3d initialization to "ngAfterViewInit" it worked.

to use the code you have to run this installs:

npm i --save three
npm i @types/three --save-dev 
npm i --save three-stl-loader
npm i --save three-orbit-controls

in the .html file:

<canvas #myCanvas></canvas>

in the .ts file:

import {Component, ViewChild, AfterViewInit, OnInit, Renderer2, Input} from '@angular/core';
import * as THREE from 'three';
var OrbitControls = require('three-orbit-controls')(THREE)
var STLLoader = require('three-stl-loader')(THREE)
var loader = new STLLoader()
import Scene = THREE.Scene;
import Mesh = THREE.Mesh;
import PerspectiveCamera = THREE.PerspectiveCamera;
import WebGLRenderer = THREE.WebGLRenderer;
import TrackballControls = THREE.TrackballControls;

@Component({
  selector: 'app-stl-loader',
  templateUrl: './stl-loader.component.html',
  styleUrls: ['./stl-loader.component.css']
})
export class StlLoaderComponent implements OnInit {

  @ViewChild("myCanvas") myCanvas:any;
  @Input()
  private path:string;
  private scene: Scene;
  private camera: PerspectiveCamera;
  private renderer: WebGLRenderer;
  private controls: any;

  ngOnInit(): void {
    //add listener for the resize of the window - will resize the renderer to fit the window
    let global = this.render.listen('window', 'resize', (evt) => {
      this.onWindowResize();
    })
  }

  ngAfterViewInit(): void {
    this.init3D();
  }
  constructor(private render: Renderer2){

  }
  init3D(){
    // renderer
    this.renderer = new THREE.WebGLRenderer({alpha: true, canvas:  this.myCanvas.nativeElement});
    this.renderer.setSize( window.innerWidth, window.innerHeight );

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

    // camera
    this.camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.01, 10000 );
    this.camera.position.set( 113, 111, 113 );
    this.camera.aspect = window.innerWidth / window.innerHeight;
    this.scene.add( new THREE.AmbientLight( 0x222222 ) );
    this.scene.add( this.camera ); // required, because we are adding a light as a child of the camera

    // controls
    this.controls = new OrbitControls(this.camera,this.renderer.domElement);

    // lights
    var light = new THREE.PointLight( 0xffffff, 0.8 );
    this.camera.add( light );

    loader.load(this.path, geometry => {
      var material = new THREE.MeshPhongMaterial( { color: 0xBEBEBE } );

      var mesh = new THREE.Mesh( geometry, material );
      this.scene.add(mesh)
    })

    //request animation
    this.animate();

  }

  /**
   * render the scene and request the window animation frame
   */
  animate() {

    this.camera.lookAt( this.scene.position );

    this.renderer.render(this.scene, this.camera);

    window.requestAnimationFrame(_ => this.animate());

  }

  /**
   * will resize the renderer and the camera to the right size of the window
   */
  onWindowResize() {

    this.camera.aspect = window.innerWidth / window.innerHeight;

    this.camera.updateProjectionMatrix();

    this.renderer.setSize( window.innerWidth, window.innerHeight );

  }

}

the path to the STL file is given as an input to the component.

Raz

Sign up to request clarification or add additional context in comments.

Comments

0

ng-three-template This dude created a template for angular + three.

using that template, you can easily:

import {STLLoader} from 'three/examples/jsm/loaders/STLLoader';

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.