CommunityCodierung & Entwicklunggithub.com

UtkarshBirla28/threejs-geometry

Erstellen und Gestalten von three.js-Geometrien: integrierte Formen, 3D-Text, Vertex-Puffer und -Attribute, Mergen, Instancing, Batchen, Punktwolken und Linien auf WebGL oder mit WebGPU und TSL. Verwende es für 3D-Formen oder Text, benutzerdefinierte Vertexdaten, benutzerdefinierte Meshes, instanziierte Meshes oder Punktwolken.

Was ist threejs-geometry?

Diese Fertigkeit bietet eine umfassende Referenz zum Erstellen und Gestalten von Geometrien mit three.js, Version r186 (einschließlich eines lokalen Overrides für die Arbeit mit einer älteren r175-basierten Pipeline). Sie behandelt alle integrierten Geometrieklassen (Box, Sphere, Plane, Cylinder, Torus, Ring, Polyeder, Lathe, Extrude, Tube und Text) mit detaillierten Codebeispielen und Parameterlisten. Darüber hinaus erklärt sie die Arbeit mit BufferGeometry für benutzerdefinierte Vertexpuffer und -attribute, InstancedMesh für tausende von Objekten mit einem einzigen Draw-Call, InstancedBufferGeometry für erweiterte Instanzdaten, Punktwolken, Linien und Drahtgittermodelle. Die Fertigkeit enthält auch einen speziellen Abschnitt über WebGPU und TSL für das Rendern auf modernen Grafik-APIs. Sie ist ideal für Entwickler, die 3D-Assets, Szenen oder Partikeleffekte in Anwendungen auf Basis von three.js erstellen, und erspart ihnen das mühsame Nachschlagen in der API-Dokumentation.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/UtkarshBirla28/animated-shorts-pipeline/tree/HEAD/.claude/skills/threejs-geometry

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Three.js-Geometrie

Ziel: three.js r186. Beispiele verwenden WebGLRenderer; der Abschnitt WebGPU und TSL verwendet WebGPURenderer.

Lokale Überschreibung (hinzugefügt am 10.11.2026 von Claude für diesen PC; kein Teil der ursprünglichen Fertigkeit). Unsere Pipeline für animierte Kurzfilme (<ROOT>\studio, von mromidev/claude-animated-shorts) ist an three 0.175 (r175) gebunden

  • Remotion 4.0.290 + @react-three/fiber 9.1.2 + pmndrs postprocessing 6.37.2. Behalte three fixiert: shade.ts/cardshade.ts patcht drei Shader-Chunks per String-Patching. Bei der Arbeit an dieser Pipeline:
  • Ignoriere "Häufige Fehler" / API-Ratschläge, die r176+ benötigen (HDRLoader, Timer, PCFSoftShadowMap-Deprecation, setEffects, RenderPipeline, outputBufferType, mesh.pivot, Capsule height, TSL/WebGPU). Überprüfe zunächst, ob die API in r175 existiert.
  • Verwende niemals useFrame, Clock, Timer, delta time, setAnimationLoop oder requestAnimationFrame für Animationen. Remotion rendert Bild für Bild: leite jeden Wert aus useCurrentFrame() / fps ab (und mixer.setTime(frame / fps) für Clips).
  • Post-Processing erfolgt mit pmndrs postprocessing, nicht mit three/addons EffectComposer: Füge keinen OutputPass hinzu (doppelte sRGB-Kodierung).
  • Toon-Farben: Das Tone Mapping in unserem Composer ist NEUTRAL; achte auf ACES-Standardeinstellungen und tonemapping_fragment-Tönung.
  • Für andere three.js-Projekte gilt die ursprüngliche r186-Anleitung unten wie beschrieben.

Kurzstart

import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 5);

// Eine Geometrie ist die Form; viele Meshes können eine Geometrieinstanz gemeinsam nutzen
const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshNormalMaterial());
scene.add(mesh);

renderer.setAnimationLoop(animate);

function animate() {
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
}

Integrierte Geometrien

Grundlegende Formen

new THREE.BoxGeometry(1, 1, 1); // Breite, Höhe, Tiefe, BreitenSegmente, HöhenSegmente, TiefenSegmente
new THREE.SphereGeometry(1, 32, 16); // Radius, BreitenSegmente, HöhenSegmente, phiStart, phiLength, thetaStart, thetaLength
new THREE.SphereGeometry(1, 32, 16, 0, Math.PI); // Halbkugel (phi-Schwenk, Schnitt durch die Pole)
new THREE.SphereGeometry(1, 32, 16, 0, Math.PI * 2, 0, Math.PI / 2); // Kuppel (Schnitt am Äquator)
new THREE.PlaneGeometry(10, 10, 1, 1); // Breite, Höhe, BreitenSegmente, HöhenSegmente
new THREE.CircleGeometry(1, 32); // Radius, Segmente, thetaStart, thetaLength
new THREE.CylinderGeometry(1, 1, 2, 32); // radiusTop, radiusBottom, Höhe, radialeSegmente, HöhenSegmente, openEnded, thetaStart, thetaLength
new THREE.CylinderGeometry(1, 1, 2, 6); // Sechseckprisma
new THREE.ConeGeometry(1, 2, 32); // Radius, Höhe, radialeSegmente, HöhenSegmente, openEnded, thetaStart, thetaLength
new THREE.TorusGeometry(1, 0.4, 16, 100); // Radius, Rohr, radialeSegmente, tubuläreSegmente, arc, thetaStart, thetaLength
new THREE.TorusGeometry(1, 0.4, 16, 100, Math.PI); // Halbbogen
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3); // Radius, Rohr, tubuläreSegmente, radialeSegmente, p, q
new THREE.RingGeometry(0.5, 1, 32, 1); // innererRadius, äußererRadius, thetaSegmente, phiSegmente, thetaStart, thetaLength

Fortgeschrittene Formen

new THREE.CapsuleGeometry(0.5, 1, 4, 8, 1); // Radius, Höhe (nur der Mittelteil), KappenSegmente, radialeSegmente, HöhenSegmente

// Radius, Detail - jede Detailebene unterteilt jede Fläche
new THREE.IcosahedronGeometry(1, 0); // 20 Flächen bei Detail 0
new THREE.DodecahedronGeometry(1, 0);
new THREE.OctahedronGeometry(1, 0);
new THREE.TetrahedronGeometry(1, 0);

// Polyeder - flaches Vertices-Array, Indices, Radius, Detail
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
new THREE.PolyhedronGeometry(vertices, indices, 1, 0);

Pfadbasierte Formen

// Lathe - ein Vector2-Profil, das um die Y-Achse gedreht wird: Punkte, Segmente, phiStart, phiLength
const profile = [
  new THREE.Vector2(0, 0), new THREE.Vector2(0.5, 0), new THREE.Vector2(0.5, 1), new THREE.Vector2(0, 1),
];
new THREE.LatheGeometry(profile, 32);

// Extrude - eine 2D-Form, die entlang der Z-Achse extrudiert wird
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(1, 0);
shape.lineTo(1, 1);
shape.lineTo(0, 1);
new THREE.ExtrudeGeometry(shape, {
  steps: 1, depth: 1, bevelEnabled: true,
  bevelThickness: 0.1, bevelSize: 0.1, bevelSegments: 3,
});

// Tube - eine kreisförmige Abtastung entlang einer Kurve: Pfad, tubuläreSegmente, Radius, radialeSegmente, geschlossen
const curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0),
]);
new THREE.TubeGeometry(curve, 64, 0.2, 8, false);

Textgeometrie

import { FontLoader } from "three/addons/loaders/FontLoader.js";
import { TextGeometry } from "three/addons/geometries/TextGeometry.js";

// Eine .typeface.json-Schriftart aus examples/fonts im three.js-Repository
const font = await new FontLoader().loadAsync("fonts/helvetiker_regular.typeface.json");
const geometry = new TextGeometry("Hello", {
  font: font,
  size: 1, // Textgröße in Welteinheiten
  depth: 0.2, // Extrusionstiefe
  curveSegments: 12,
  bevelEnabled: true,
  bevelThickness: 0.03,
  bevelSize: 0.02,
  direction: "ltr", // 'ltr', 'rtl' (rechts nach links) oder 'tb' (oben nach unten)
});

geometry.center(); // Glyphen am Ursprung neu zentrieren
scene.add(new THREE.Mesh(geometry, new THREE.MeshNormalMaterial()));

BufferGeometry

Die Basisklasse jeder Geometrie: typisierte Arrays von Vertexdaten plus ein optionaler Index. Attribute sind benannte Puffer mit itemSize Werten pro Vertex; position, normal und uv sind die, die Materialien standardmäßig lesen.

Benutzerdefinierte BufferGeometry

const geometry = new THREE.BufferGeometry();

// Vier Vertices, jeweils drei Floats (x, y, z)
const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));

// Indices verwenden Vertices über die beiden Dreiecke hinweg wieder
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// Normalen steuern die Beleuchtung, UVs adressieren Texturen
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
// Optionale Vertex-Farben, gerendert mit material.vertexColors = true
const colors = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0]);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

scene.add(new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ vertexColors: true })));

Attributtypen

const count = 4;
const geometry = new THREE.BufferGeometry();
// Float32 für Positionen, Normalen, UVs und Fließkommafarben
geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(count * 3), 3));
// Uint16-Indices adressieren Vertices 0 bis 65534 (65535 ist der Primitive-Restart-Wert); setIndex([...]) mit einem einfachen Array wählt selbstständig Uint16 oder Uint32
geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(count), 1));
// Uint8-Farben benötigen normalized = true (drittes Argument), damit Bytes als 0.0-1.0 zum Shader gelangen
geometry.setAttribute("color", new THREE.BufferAttribute(new Uint8Array(count * 3), 3, true));

Aktualisieren einer BufferGeometry

const geometry = new THREE.PlaneGeometry(2, 2);
const positions = geometry.attributes.position;
positions.setXYZ(0, -2, -2, 0); // Vertex 0 überschreiben
positions.getX(0); // Einzelne Komponenten mit getX / getY / getZ lesen
positions.needsUpdate = true; // Änderung hochladen; ein Array kann nach dem ersten Rendern nicht wachsen, daher das Maximum zuweisen und geometry.setDrawRange(0, n) verwenden
geometry.computeVertexNormals(); // Normalen müssen den neuen Positionen entsprechen
geometry.computeBoundingBox(); // Begrenzungsvolumen steuern Frustum-Culling und Raycasting
geometry.computeBoundingSphere();

Interleaved-Puffer

// Ein Puffer, der Position (3 Floats) und UV (2 Floats) pro Vertex hält
const interleavedBuffer = new THREE.InterleavedBuffer(
  new Float32Array([
    -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1, // vier Vertices: xyz + uv
  ]),
  5, // Schrittweite: Floats pro Vertex
);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0));
geometry.setAttribute("uv", new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3));
geometry.setIndex([0, 1, 2, 0, 2, 3]); // zwei Dreiecke über die vier Vertices
// BufferGeometryUtils.interleaveAttributes([position, normal, uv]) packt vorhandene Attribute auf diese Weise

Kanten und Drahtgitter

const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
// Kanten, bei denen sich die Normalen der beiden Flächen um mindestens thresholdAngle (Grad; hier 15) unterscheiden, plus offene Grenzkanten
const edges = new THREE.EdgesGeometry(boxGeometry, 15);
const edgeLines = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffffff }));
// Jede Dreieckskante, einschließlich Diagonalen; eine von zwei Dreiecken geteilte Kante wird einmal gezeichnet
const wireframe = new THREE.WireframeGeometry(boxGeometry);
const wireLines = new THREE.LineSegments(wireframe, new THREE.LineBasicMaterial({ color: 0xffffff }));
scene.add(edgeLines, wireLines);

Punkte

const count = 1000;
const positions = new Float32Array(count * 3).map(() => (Math.random() - 0.5) * 10);
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
// sizeAttenuation (standardmäßig true) verkleinert Punkte mit der Tiefe unter einer perspektivischen Kamera: Ein Punkt erstreckt sich über size * (Canvas-CSS-Höhe / 2) / Tiefe CSS-Pixel
const material = new THREE.PointsMaterial({ size: 0.1, color: 0xffffff });
const points = new THREE.Points(geometry, material);
scene.add(points);

Unter WebGPURenderer zeichnet das WebGPU-Backend Punkte mit einem Pixel unabhängig von der Materialgröße; siehe den Abschnitt WebGPU und TSL für das instanziierte Sprite, das Größen wiederherstellt.

Linien

const linePoints = [
  new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0),
];
const geometry = new THREE.BufferGeometry().setFromPoints(linePoints);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });

// Line verbindet die Punkte der Reihe nach; LineLoop schließt zum ersten Punkt zurück
const line = new THREE.Line(geometry, material);
const loop = new THREE.LineLoop(geometry, material);
scene.add(line, loop);

// LineSegments zeichnet unabhängige Paare: Vertex 0-1, 2-3, ...
const segmentsGeometry = new THREE.BufferGeometry().setFromPoints([linePoints[0], linePoints[1], linePoints[1], linePoints[2]]);
const segments = new THREE.LineSegments(segmentsGeometry, material);
scene.add(segments);

LineLoop wird unter WebGPURenderer nicht unterstützt: es protokolliert einen Fehler und rendert nichts. Schließe dort eine Schleife, indem du den ersten Punkt wiederholst und Line verwendest.

InstancedMesh

Ein Draw-Call für viele Kopien einer Geometrie, jede mit ihrer eigenen Transformation.

const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshBasicMaterial(); // multipliziert mit Instanzfarben; MeshNormalMaterial ignoriert sie
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
  dummy.position.set((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20);
  dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
  dummy.scale.setScalar(0.5 + Math.random());
  dummy.updateMatrix();
  instancedMesh.setMatrixAt(i, dummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true; // nach Änderungen erforderlich, sobald das Mesh gerendert wurde; vorher harmlos

// setColorAt erstellt instanceColor bei der ersten Verwendung; nach der Schleife markieren
for (let i = 0; i < count; i++) {
  instancedMesh.setColorAt(i, new THREE.Color(Math.random(), Math.random(), Math.random()));
}
instancedMesh.instanceColor.needsUpdate = true;

scene.add(instancedMesh);

Zur Laufzeit Instanzen wie folgt aktualisieren und raycasten:

// mesh ist hier ein InstancedMesh
const matrix = new THREE.Matrix4();
const index = 7;
mesh.getMatrixAt(index, matrix);
matrix.setPosition(0, 2, 0); // nur diese Instanz verschieben
mesh.setMatrixAt(index, matrix);
mesh.instanceMatrix.needsUpdate = true; // nach jedem Stapel von setMatrixAt-Aufrufen markieren
mesh.computeBoundingSphere(); // Instanzen verschoben: die von Frustum-Culling und Raycasting verwendeten Grenzen aktualisieren

// Raycasting meldet, welche Instanz getroffen wurde
const raycaster = new THREE.Raycaster();
const hits = raycaster.intersectObject(mesh);
if (hits.length > 0) {
  const instanceId = hits[0].instanceId; // undefined für ein nicht instanziiertes Objekt
}

InstancedBufferGeometry

Pro-Instanz-Attribute über Transformation und Farbe hinaus.

const count = 1000;
const geometry = new THREE.InstancedBufferGeometry();
geometry.copy(new THREE.BoxGeometry(1, 1, 1)); // kopiert den Index und alle Attribute
geometry.instanceCount = count; // erforderlich: copy() überträgt keine Instanzanzahl

const offsets = new Float32Array(count * 3).map(() => Math.random() * 10);
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));

// Mit WebGLRenderer und einem ShaderMaterial deklariere `in vec3 offset;` im Vertex-
// Shader selbst und addiere es zur Position (siehe threejs-shaders). Unter WebGPURenderer
// sind Pro-Instanz-Daten ein TSL-Knoten - siehe den Abschnitt WebGPU und TSL.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Verwandte Skills