Geometries define the shape of 3D objects. Materia provides a comprehensive set of primitive and advanced geometries.
Base class for all geometries. Stores vertex data in GPU-friendly buffer format.
val attributes: Map<String, BufferAttribute> // Vertex attributes
val index: BufferAttribute? // Index buffer
val morphAttributes: Map<String, List<BufferAttribute>> // Morph targets
val groups: List<GeometryGroup> // Material groups
var morphTargetsRelative: Boolean // Morph target mode
val boundingBox: Box3? // Cached bounding box
val boundingSphere: Sphere? // Cached bounding sphere
Standard attributes:
position - Vertex positions (Vector3)normal - Vertex normals (Vector3)uv - Texture coordinates (Vector2)color - Vertex colors (Color)tangent - Tangent vectors (Vector4)val geometry = BufferGeometry()
// Set position attribute
val positions = floatArrayOf(
-1f, -1f, 0f, // Vertex 0
1f, -1f, 0f, // Vertex 1
0f, 1f, 0f // Vertex 2
)
geometry.setAttribute(
"position",
BufferAttribute(positions, itemSize = 3)
)
// Set indices
val indices = floatArrayOf(0f, 1f, 2f)
geometry.setIndex(BufferAttribute(indices, itemSize = 1))
// Compute normals
geometry.computeVertexNormals()
// Attribute management
fun setAttribute(name: String, attribute: BufferAttribute)
fun getAttribute(name: String): BufferAttribute?
fun deleteAttribute(name: String)
fun hasAttribute(name: String): Boolean
// Index buffer
fun setIndex(index: BufferAttribute?)
// Bounding volumes
fun computeBoundingBox(): Box3
fun computeBoundingSphere(): Sphere
// Transformations
fun translate(x: Float, y: Float, z: Float)
fun scale(x: Float, y: Float, z: Float)
fun rotateX(angle: Float)
fun rotateY(angle: Float)
fun rotateZ(angle: Float)
fun applyMatrix4(matrix: Matrix4)
// Morph targets
fun setMorphAttribute(name: String, targets: Array<BufferAttribute>)
fun getMorphAttribute(name: String): List<BufferAttribute>?
fun computeMorphedBoundingBox()
fun computeMorphedBoundingSphere()
// Groups (for multi-material)
fun addGroup(start: Int, count: Int, materialIndex: Int = 0)
fun clearGroups()
// Instancing
fun setInstancedAttribute(name: String, attribute: BufferAttribute)
var instanceCount: Int
val isInstanced: Boolean
// Utility
fun getTriangleCount(): Int
fun getVertexCount(): Int
fun clone(): BufferGeometry
fun dispose()
Rectangular box (cube).
val geometry = BoxGeometry(
width = 1f,
height = 1f,
depth = 1f,
widthSegments = 1,
heightSegments = 1,
depthSegments = 1
)
Parameters:
width - Size along X axisheight - Size along Y axisdepth - Size along Z axiswidthSegments - Number of segmented faces along widthheightSegments - Number of segmented faces along heightdepthSegments - Number of segmented faces along depthExamples:
// Simple cube
val cube = BoxGeometry(2f, 2f, 2f)
// Subdivided box (smoother shading)
val smoothBox = BoxGeometry(1f, 1f, 1f, 10, 10, 10)
// Rectangular prism
val platform = BoxGeometry(10f, 0.5f, 5f)
Sphere with customizable segments.
val geometry = SphereGeometry(
radius = 1f,
widthSegments = 32,
heightSegments = 16,
phiStart = 0f,
phiLength = PI.toFloat() * 2f,
thetaStart = 0f,
thetaLength = PI.toFloat()
)
Parameters:
radius - Sphere radiuswidthSegments - Horizontal segmentsheightSegments - Vertical segmentsphiStart - Horizontal starting anglephiLength - Horizontal sweep anglethetaStart - Vertical starting anglethetaLength - Vertical sweep angleExamples:
// Standard sphere
val sphere = SphereGeometry(radius = 1f, widthSegments = 32, heightSegments = 16)
// High-detail sphere
val smoothSphere = SphereGeometry(1f, 64, 64)
// Hemisphere
val hemisphere = SphereGeometry(
radius = 1f,
thetaLength = PI.toFloat() / 2f
)
// Sphere segment
val segment = SphereGeometry(
radius = 1f,
phiStart = 0f,
phiLength = PI.toFloat() // Half sphere horizontally
)
Flat rectangular surface.
val geometry = PlaneGeometry(
width = 1f,
height = 1f,
widthSegments = 1,
heightSegments = 1
)
Examples:
// Ground plane
val ground = PlaneGeometry(width = 100f, height = 100f)
// Subdivided for terrain
val terrain = PlaneGeometry(
width = 50f,
height = 50f,
widthSegments = 128,
heightSegments = 128
)
// Wall
val wall = PlaneGeometry(10f, 5f)
Cylinder with optional different top/bottom radii (cone).
val geometry = CylinderGeometry(
radiusTop = 1f,
radiusBottom = 1f,
height = 2f,
radialSegments = 32,
heightSegments = 1,
openEnded = false,
thetaStart = 0f,
thetaLength = PI.toFloat() * 2f
)
Parameters:
radiusTop - Top radiusradiusBottom - Bottom radiusheight - Height of cylinderradialSegments - Number of faces around circumferenceheightSegments - Number of faces along heightopenEnded - Open or capped endsthetaStart - Starting anglethetaLength - Sweep angleExamples:
// Standard cylinder
val cylinder = CylinderGeometry(
radiusTop = 1f,
radiusBottom = 1f,
height = 3f,
radialSegments = 32
)
// Cone
val cone = CylinderGeometry(
radiusTop = 0f,
radiusBottom = 1f,
height = 2f
)
// Pipe (open-ended)
val pipe = CylinderGeometry(
radiusTop = 0.5f,
radiusBottom = 0.5f,
height = 5f,
openEnded = true
)
// Truncated cone
val frustum = CylinderGeometry(
radiusTop = 0.5f,
radiusBottom = 1.5f,
height = 3f
)
Cone (specialized cylinder).
val geometry = ConeGeometry(
radius = 1f,
height = 2f,
radialSegments = 32,
heightSegments = 1,
openEnded = false,
thetaStart = 0f,
thetaLength = PI.toFloat() * 2f
)
Examples:
// Standard cone
val cone = ConeGeometry(radius = 1f, height = 2f)
// Pyramid (low segments)
val pyramid = ConeGeometry(radius = 1f, height = 2f, radialSegments = 4)
// Party hat
val hat = ConeGeometry(radius = 1f, height = 3f, radialSegments = 64)
Donut shape.
val geometry = TorusGeometry(
radius = 1f,
tube = 0.4f,
radialSegments = 16,
tubularSegments = 64,
arc = PI.toFloat() * 2f
)
Parameters:
radius - Torus radius (center to tube center)tube - Tube radiusradialSegments - Segments around tubetubularSegments - Segments around torusarc - Central angleExamples:
// Standard torus
val torus = TorusGeometry(radius = 1f, tube = 0.4f)
// Thin ring
val ring = TorusGeometry(radius = 2f, tube = 0.1f)
// Partial torus (arc)
val arc = TorusGeometry(
radius = 1f,
tube = 0.3f,
arc = PI.toFloat() // Half donut
)
Knot-shaped torus.
val geometry = TorusKnotGeometry(
radius = 1f,
tube = 0.4f,
tubularSegments = 64,
radialSegments = 8,
p = 2, // Winding number
q = 3 // Winding number
)
Examples:
// Trefoil knot
val trefoil = TorusKnotGeometry(
radius = 1f,
tube = 0.3f,
p = 2,
q = 3
)
// Cinquefoil knot
val cinquefoil = TorusKnotGeometry(
radius = 1f,
tube = 0.3f,
p = 5,
q = 2
)
// Complex knot
val complex = TorusKnotGeometry(
radius = 1f,
tube = 0.2f,
p = 3,
q = 7,
tubularSegments = 128,
radialSegments = 16
)
Extrude 2D shapes into 3D.
// Define 2D shape
val shape = Shape().apply {
moveTo(0f, 0f)
lineTo(0f, 1f)
lineTo(1f, 1f)
lineTo(1f, 0f)
lineTo(0f, 0f)
}
val geometry = ExtrudeGeometry(
shapes = listOf(shape),
options = ExtrudeGeometryOptions(
depth = 1f,
bevelEnabled = true,
bevelThickness = 0.1f,
bevelSize = 0.1f,
bevelSegments = 3,
steps = 1,
curveSegments = 12
)
)
Examples:
// Star extrusion
val starShape = Shape().apply {
for (i in 0 until 10) {
val angle = (i / 10f) * PI.toFloat() * 2f
val radius = if (i % 2 == 0) 1f else 0.5f
val x = cos(angle) * radius
val y = sin(angle) * radius
if (i == 0) moveTo(x, y)
else lineTo(x, y)
}
}
val star = ExtrudeGeometry(
shapes = listOf(starShape),
options = ExtrudeGeometryOptions(depth = 0.5f)
)
// Text extrusion
val textShape = createTextShape("HELLO")
val text3D = ExtrudeGeometry(
shapes = listOf(textShape),
options = ExtrudeGeometryOptions(
depth = 0.2f,
bevelEnabled = true,
bevelThickness = 0.03f,
bevelSize = 0.02f
)
)
Revolve a 2D curve around an axis.
val points = listOf(
Vector2(0f, 0f),
Vector2(0.5f, 0.5f),
Vector2(0.3f, 1f),
Vector2(0.1f, 1.5f),
Vector2(0f, 2f)
)
val geometry = LatheGeometry(
points = points,
segments = 32,
phiStart = 0f,
phiLength = PI.toFloat() * 2f
)
Examples:
// Vase
val vaseProfile = listOf(
Vector2(0f, 0f),
Vector2(0.8f, 0.2f),
Vector2(1f, 1f),
Vector2(0.9f, 2f),
Vector2(0.7f, 2.5f),
Vector2(0.5f, 2.7f)
)
val vase = LatheGeometry(vaseProfile, segments = 64)
// Wine glass
val glassProfile = listOf(
Vector2(0f, 0f),
Vector2(0.3f, 0f),
Vector2(0.1f, 1f),
Vector2(0.3f, 1.5f),
Vector2(0.8f, 2f),
Vector2(0.8f, 2.5f)
)
val glass = LatheGeometry(glassProfile)
Tube following a 3D curve.
// Define curve
val curve = CatmullRomCurve3(
points = listOf(
Vector3(0f, 0f, 0f),
Vector3(1f, 1f, 0f),
Vector3(2f, 0f, 1f),
Vector3(3f, -1f, 0f)
)
)
val geometry = TubeGeometry(
path = curve,
tubularSegments = 64,
radius = 0.3f,
radialSegments = 8,
closed = false
)
Examples:
// Pipe following a path
val pipePath = QuadraticBezierCurve3(
v0 = Vector3(0f, 0f, 0f),
v1 = Vector3(5f, 5f, 0f),
v2 = Vector3(10f, 0f, 0f)
)
val pipe = TubeGeometry(pipePath, tubularSegments = 64, radius = 0.5f)
// Cable
val cablePath = CubicBezierCurve3(
v0 = Vector3(0f, 0f, 0f),
v1 = Vector3(2f, 3f, 1f),
v2 = Vector3(4f, -1f, 2f),
v3 = Vector3(6f, 0f, 0f)
)
val cable = TubeGeometry(cablePath, radius = 0.1f, radialSegments = 6)
3D text from TrueType fonts.
val geometry = TextGeometry(
text = "Hello World",
parameters = TextGeometryParameters(
font = font,
size = 1f,
height = 0.2f,
curveSegments = 12,
bevelEnabled = true,
bevelThickness = 0.03f,
bevelSize = 0.02f,
bevelSegments = 3
)
)
Examples:
// Load font
val fontLoader = FontLoader()
val font = fontLoader.load("fonts/helvetiker_regular.typeface.json")
// Simple text
val simpleText = TextGeometry(
text = "Materia",
parameters = TextGeometryParameters(
font = font,
size = 2f,
height = 0.5f
)
)
// Beveled text
val fancyText = TextGeometry(
text = "3D TEXT",
parameters = TextGeometryParameters(
font = font,
size = 1f,
height = 0.3f,
bevelEnabled = true,
bevelThickness = 0.05f,
bevelSize = 0.04f
)
)
Geometry from parametric equations.
// Define parametric function
fun parametricFunction(u: Float, v: Float, target: Vector3) {
val x = u * 2f - 1f
val y = v * 2f - 1f
val z = sin(u * PI.toFloat() * 2f) * cos(v * PI.toFloat() * 2f)
target.set(x, y, z)
}
val geometry = ParametricGeometry(
func = ::parametricFunction,
slices = 32,
stacks = 32
)
Examples:
// Wave surface
fun wave(u: Float, v: Float, target: Vector3) {
val x = u * 10f - 5f
val z = v * 10f - 5f
val y = sin(x) * cos(z)
target.set(x, y, z)
}
val waveSurface = ParametricGeometry(::wave, 64, 64)
// Mobius strip
fun mobius(u: Float, v: Float, target: Vector3) {
val angle = u * PI.toFloat() * 2f
val majorRadius = 2f
val t = v * 2f - 1f
val x = (majorRadius + t * cos(angle / 2f)) * cos(angle)
val y = (majorRadius + t * cos(angle / 2f)) * sin(angle)
val z = t * sin(angle / 2f)
target.set(x, y, z)
}
val mobius = ParametricGeometry(::mobius, 64, 32)
Perfect geometric shapes with all faces, edges, and angles equal.
// Tetrahedron (4 faces)
val tetrahedron = TetrahedronGeometry(radius = 1f, detail = 0)
// Octahedron (8 faces)
val octahedron = OctahedronGeometry(radius = 1f, detail = 0)
// Icosahedron (20 faces)
val icosahedron = IcosahedronGeometry(radius = 1f, detail = 0)
// Dodecahedron (12 faces)
val dodecahedron = DodecahedronGeometry(radius = 1f, detail = 0)
// Higher detail (subdivided)
val smoothIcosahedron = IcosahedronGeometry(radius = 1f, detail = 3)
// Create geometry
val geometry = BufferGeometry()
// Define triangle vertices
val vertices = floatArrayOf(
-1f, -1f, 0f, // v0
1f, -1f, 0f, // v1
0f, 1f, 0f // v2
)
// Define normals
val normals = floatArrayOf(
0f, 0f, 1f, // n0
0f, 0f, 1f, // n1
0f, 0f, 1f // n2
)
// Define UVs
val uvs = floatArrayOf(
0f, 0f, // uv0
1f, 0f, // uv1
0.5f, 1f // uv2
)
// Set attributes
geometry.setAttribute("position", BufferAttribute(vertices, 3))
geometry.setAttribute("normal", BufferAttribute(normals, 3))
geometry.setAttribute("uv", BufferAttribute(uvs, 2))
// Compute additional data
geometry.computeBoundingBox()
geometry.computeBoundingSphere()
val geometry = BoxGeometry(1f, 1f, 1f)
// Access position attribute
val positionAttr = geometry.getAttribute("position")
val positions = positionAttr!!.array
// Modify vertices
for (i in positions.indices step 3) {
positions[i] *= 2f // Scale X
positions[i + 1] *= 2f // Scale Y
positions[i + 2] *= 2f // Scale Z
}
// Mark as needing update
positionAttr.needsUpdate = true
// Recompute bounds
geometry.computeBoundingBox()
geometry.computeBoundingSphere()
val merged = BufferGeometryUtils.mergeBufferGeometries(
listOf(geometry1, geometry2, geometry3)
)
// Smooth normals
geometry.computeVertexNormals()
// Flat normals
geometry.computeFlatNormals()
geometry.computeTangents()
val bbox = geometry.computeBoundingBox()
println("Min: ${bbox.min}, Max: ${bbox.max}")
val sphere = geometry.computeBoundingSphere()
println("Center: ${sphere.center}, Radius: ${sphere.radius}")
geometry.dispose() when done