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.
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; }