Custom Geometry

Back to Modules

Custom Geometry in Three.js

In Three.js, while there are many built-in geometries (like BoxGeometry, SphereGeometry, etc.), you often need to create custom shapes that are not readily available. This is primarily done using THREE.BufferGeometry, which is the modern and efficient way to represent mesh data.

THREE.BufferGeometry

BufferGeometry stores vertex attributes (like position, normal, and UV coordinates) in typed arrays, which are then directly passed to the GPU. This makes it highly performant for complex geometries.

Key Attributes of BufferGeometry:

To define a custom geometry, you typically need to specify at least the following attributes:

Creating a Custom Triangle Geometry Example

Here's a basic example of how to create a single triangle using BufferGeometry:

import * as THREE from 'three';

// Scene, Camera, Renderer setup (assuming these are already defined)
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 1. Define the vertex data
const positions = new Float32Array([
    0.0,  1.0,  0.0,  // Vertex 0 (top)
   -1.0, -1.0,  0.0,  // Vertex 1 (bottom-left)
    1.0, -1.0,  0.0   // Vertex 2 (bottom-right)
]);

// Normals for a flat triangle pointing towards the camera (positive Z)
const normals = new Float32Array([
    0.0,  0.0,  1.0,  // Normal for Vertex 0
    0.0,  0.0,  1.0,  // Normal for Vertex 1
    0.0,  0.0,  1.0   // Normal for Vertex 2
]);

// UV coordinates for texture mapping
const uvs = new Float32Array([
    0.5,  1.0,  // UV for Vertex 0 (top-center of texture)
    0.0,  0.0,  // UV for Vertex 1 (bottom-left of texture)
    1.0,  0.0   // UV for Vertex 2 (bottom-right of texture)
]);

// 2. Create a new BufferGeometry
const geometry = new THREE.BufferGeometry();

// 3. Set the attributes
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));

// Optional: If you have shared vertices, you can use an index buffer.
// For a single triangle, it's just 0, 1, 2.
// const indices = new Uint16Array([0, 1, 2]);
// geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// 4. Create a material
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide });

// 5. Create a Mesh using the custom geometry and material
const triangleMesh = new THREE.Mesh(geometry, material);
scene.add(triangleMesh);

camera.position.z = 2;

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

Important Considerations: