webgl mit three.js: die Kamera

3D Kamera steuern

Zum besseren Verständnis der Kamera-Einstellungen, insbesondere der Werte von near, far und Field of View (fov): SplitView zum Teilen der Scene mit zwei Kameras, Split-View mit zwei Fenstern in die Szene.

23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Das Frustum der Kamera

Während eine Fotokamera einen eingeschränkten Bereich der Schärfentiefe hat, und alles davor und dahinter unscharf ist, rendert die 3D-Kamera nur einen eingeschränkten Bereich und schneidet alles vor und hinter diesem Bereich ab.

3D Frustum

Bei einer perspektivischen Kamera hat der angezeigte Raum die Form eines Frustums, bei einer orthografischen Kamera ein Quader. Alles außerhalb des Frustums / Quader ist abgeschnitten, und wenn near, far und FOV (Field of View) nicht richtig eingerichtet sind, zeigen die vorderen Objekte Löcher oder die hinten liegenden Objekte werden abgeschnitten.

dat.gui

dat.gui ist eine kleine Controller-Library, die eine Benutzerschnittstelle für das Ändern von Variablen aufbaut. Das R109-Paket von three.js liefert diese nützlichen Hilfen unter examples/jsm/libs/ mit und wird zusätzlich zu three.js importiert.

import * as THREE      from '/threejs/build/three.module.js';
import {OrbitControls} from '/threejs/examples/jsm/controls/OrbitControls.js'; // Benutzersteuerung der Kamera
import {GLTFLoader}    from '/threejs/examples/jsm/loaders/GLTFLoader.js';     // Modelle von 3D-Programmen importieren
import {GUI}           from '/threejs/examples/jsm/libs/dat.gui.module.js';

Die Klasse MinMaxGUIHelper sorgt dafür, das bei der Einstellung von near und far die Werte für far immer größer sind als die Werte für near.

class MinMaxGUIHelper {
  constructor (obj, minProp, maxProp, minDif) {
    this.obj = obj;
    this.minProp = minProp;
    this.maxProp = maxProp;
    this.minDif = minDif;
  }
  get min() {
    return this.obj[this.minProp];
  }
  set min(v) {
    this.obj[this.minProp] = v;
    this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
  }
  
  get max() {
    return this.obj[this.maxProp];
  }
  
  set maxv(v) {
    this.obj[this.maxProp] = v;
    this.min = this.min;    // min-Setter
  }
}

ThreeJS SplitView

Ein tieferes Verständnis für den sichtbaren Teil der Szene liefert der SplitView mit einer zweiten Kamera. So kommen wir der Darstellung in den 3D-Programmen mit grafischer Oberfläche näher.

Ähnlich wie in einem grafische 3D-Programm gibt der SplitView zwei Fenster auf die Szene: die Originalszene mit den sichtbaren Elemente und eine weitere Ansicht, um die Kamera mit gedachten Linien für das Field of View.

function setScissorForElement(elem) {
   const canvasRect = canvas.getBoundingClientRect();
   const elemRect = elem.getBoundingClientRect();

   // Rechteck relativ zum Canvas-Element
   const right = Math.min(elemRect.right, canvasRect.right) - canvasRect.left;
   const left = Math.max(0, elemRect.left - canvasRect.left);
   const bottom = Math.min(elemRect.bottom, canvasRect.bottom) - canvasRect.top;
   const top = Math.max(0, elemRect.top - canvasRect.top);

   const width = Math.min(canvasRect.width, right - left);
   const height = Math.min(canvasRect.height, bottom - top);

   // Abschneiden, um nur einen Teil des Canvas zu rendern 
   const positiveYUpBottom = canvasRect.height - bottom;
   renderer.setScissor(left, positiveYUpBottom, width, height);
   renderer.setViewport(left, positiveYUpBottom, width, height);

   // Seitenverhältnis – Aspect Ratio – zurückgeben
   return width / height;
}