Navigate

Search topics across all sections

GitHub
Meshes & ObjectsEssential

Mesh Component

A mesh is the most fundamental visible thing in 3D. If you can see it in a 3D scene, it is probably a mesh. But a mesh by itself is nothing -- it needs two ingredients: a shape (the geometry) and a surface look (the material). Think of it as a mannequin wearing an outfit. The mannequin is the geometry. The outfit is the material. Together, they make something you can actually see.

You create a beautiful sphere with meshStandardMaterial in a nice coral color. But when you run the app, the sphere is completely black. The shape is there -- you can see the silhouette against the background -- but the color is gone. It looks like a black hole.

terminal
Scene renders but all objects appear black.
meshStandardMaterial requires light sources to calculate color.
No <ambientLight> or <directionalLight> found in scene.

Real-world

Picture a mannequin in a clothing store. The mannequin has a body shape -- arms, torso, legs. That is the geometry. Now dress it in a red silk shirt. The shirt has color, texture, and shininess. That is the material.

A naked mannequin is invisible in 3D (no material = nothing to render). A shirt floating in mid-air has no form (no geometry = nothing to shape). You need both. The mesh is the combination: body plus clothing equals something you can see and interact with.

Geometry

The shape (box, sphere, torus)

+

Material

The look (color, texture, shine)

=

Mesh

A visible 3D object

Dressing a Mannequin

Let us build a mesh step by step. First the body, then the outfit, then we will bring it to life with animation.

Step 1Choose a body shape (geometry)

Geometry defines the form. R3F gives you all of Three.js's built-in shapes: boxes, spheres, cylinders, torus knots, and more. The args array controls the dimensions.

geometries.tsxTSX
{/* A box: width, height, depth */}
<boxGeometry args={[1, 1, 1]} />

{/* A sphere: radius, widthSegments, heightSegments */}
<sphereGeometry args={[0.6, 32, 32]} />

More segments means a smoother shape, but also more work for your GPU. A sphere with 32 segments looks smooth. One with 8 looks like a gem.

Step 2Pick an outfit (material)

Material controls how the surface looks. Different materials have different capabilities and performance costs.

materials.tsxTSX
{/* Basic: always visible, ignores light */}
<meshBasicMaterial color="hotpink" />

{/* Standard: realistic, needs lights */}
<meshStandardMaterial color="coral" />

{/* Physical: most realistic, most expensive */}
<meshPhysicalMaterial
  color="gold"
  metalness={1}
  roughness={0.2}
/>

Think of materials on a spectrum: Basic is a t-shirt (cheap, simple), Standard is a nice jacket (good looking, reasonable cost), Physical is a tailored suit (stunning, expensive).

Step 3Put them together as a mesh

Wrap the geometry and material inside a <mesh> tag. Add position, rotation, or scale to place it in your scene.

MyMesh.tsxTSX
<mesh position={[0, 1, 0]}>
  <sphereGeometry args={[0.6, 32, 32]} />
  <meshStandardMaterial color="coral" />
</mesh>

That is a coral-colored sphere floating 1 unit above the origin. The mannequin (sphere shape) is dressed (coral standard material) and placed in the scene.

What you just learned

A mesh is geometry (shape) + material (appearance)

Geometry defines vertices, faces, and the form of the object

Material defines color, roughness, metalness, and how light interacts

meshBasicMaterial ignores lights; meshStandardMaterial needs them

Use args for geometry dimensions; use props for material properties

Animate meshes with useFrame and refs, never with useState

Question

Can two meshes share the same geometry or material? Why would you want to do that?

Yes, and you should whenever possible. If you have 100 trees that all use the same trunk shape, sharing one geometry means one set of vertices in GPU memory instead of 100. Same for materials. Shared resources = less memory, better performance. In R3F, you can share by passing a ref or by using useMemo.

Think about it...

You place a mesh with meshStandardMaterial in your scene but forget to add lights. What do you see?

Hint: Think about what happens in a completely dark room. Can you see the shape of an object?

Try These Challenges

Put what you learned into practice. Try each challenge in the demo above using the Leva controls, then check the solution.

Try This!

Beginner

Set wireframe={true} on all materials -- what do you see?

Try This!

Beginner

Change metalness to 1 and roughness to 0 -- mirror effect!

Try This!

Intermediate

Remove all lights from the scene -- which shapes are still visible?

These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.

1
Recreating geometry and material every render
Creating Three.js objects inside the component body
Don't do this
MyMesh.tsxTSX
function MyMesh() {
  // Recreated on EVERY render!
  const geo = new THREE.BoxGeometry(1, 1, 1)
  const mat = new THREE.MeshStandardMaterial()
  return <mesh geometry={geo} material={mat} />
}
Creating new Three.js objects inside a component body means they are constructed on every React render, wasting memory and CPU. Use JSX children and let R3F handle the lifecycle.
2
Missing lights with PBR materials
Standard and Physical materials need light to be visible
Don't do this
Scene.tsxTSX
// Renders completely black
<mesh>
  <sphereGeometry args={[1, 32, 32]} />
  <meshStandardMaterial color="coral" />
</mesh>
MeshStandardMaterial simulates real light interaction. Without light sources, it renders black. Add ambient and directional lights, or use MeshBasicMaterial if you want something always visible.
3
Transparent objects with incorrect render order
Transparent meshes hide objects behind them
Don't do this
Transparency.tsxTSX
<mesh>
  <sphereGeometry args={[1, 32, 32]} />
  <meshStandardMaterial
    transparent opacity={0.3}
    color="skyblue"
  />
</mesh>
Transparent objects that write to the depth buffer can hide objects behind them. Set depthWrite={false} on transparent materials to prevent this. Use renderOrder to control draw order explicitly.

Best Practices

Share geometry and material

Reuse the same instances across identical meshes. Use module-level constants or useMemo to avoid creating duplicates.

Use the simplest material

Do not default to MeshPhysicalMaterial. If you do not need realistic lighting, MeshBasicMaterial is much cheaper and always visible without lights.

Lower segments for distant objects

A sphere with 64 segments and one with 16 look the same when far away. Fewer segments means less GPU work. Start low and increase only if you notice facets.

Animate with refs, not state

For 60fps animations, mutate through a ref inside useFrame. Using useState triggers React re-renders which is far too slow for smooth animation.