Scene geometry

Overview

The @use-gpu/scene package provides a classic 3D scene hierarchy with matrix transforms. Unlike most 3D engines, this is just one use-case of Use.GPU, which can be bypassed entirely, or composed with other parts.

A basic scene looks like:

return (
  <Scene>
    <Node position={[1, 2, 3]} rotation={[0, 1, 0]}>
      <Mesh mesh={mesh} shaded />
    </Node>
  </Scene>
);

Use <Node> to apply and nest matrix transforms, which are applied from parent to child. These take the classic position, rotation and scale attributes, though you can also use quaternion and matrix for more advanced use.

Use <Mesh> to render individual triangle meshes, or <Instances> to render multiple copies of one mesh.

Mesh

A mesh is a dictionary of any of the attributes that can be given to <FaceLayer>, i.e. positions, uvs, indices, ... Each is a StorageSource. You can load these using <Data> or any other data-driven geometry component.

There are also a handful of pre-fab geometries available:

These return a CPUGeometry object. This is just a wrapper around attributes along with their schema. This can be passed to <GeometryData> to create GPUGeometry from it.

This is best done via a <Gather>, so you gather up related resources up-front, e.g. a texture:

const geometry = useOne(() => makeBoxGeometry({ width: 2 }));

return (
  <Gather
    children={[
      <GeometryData geometry={geometry} />,
      <ImageTexture url="/textures/test.png" />,
    ]}
    then={([
      mesh,
      texture,
    ]) => (
      <Scene>
        <PBRMaterial albedoMap={texture}>
          <Mesh
            mesh={mesh}
            shaded
          />
        </PBRMaterial>
      </Scene>
    )
  />
);

Instancing

To render many copies of the same mesh, use <Instances>. This takes a render prop that receives a contextual <Instance> component type:

  <Instances
    mesh={mesh}
    shaded
    render={(Instance) => (<>
      <Instance position={[1, 2, 3]} />
      <Instance position={[3, 4, 5]} />
    </>)
  />

Each instance can be transformed directly like a <Node>, but you can also wrap them in additional nodes if needed.

Primitive

You can "escape" from the scene model, using a <Primitive>. This will gather the combined matrix transform and provide it as a TransformContext to its children. Thus it can be applied to other geometry layers, or combined with non-matrix transforms.

A <Mesh> is in fact just a convenient wrapper consisting of a <FaceLayer> inside a <Primitive>.

Materials

Meshes can be wrapped inside material components such as <BasicMaterial> and <PBRMaterial> to style them. These take properties for color, emissive, texture, normal map, etc.

These materials use the more fundamental <ShaderFlatMaterial> and <ShaderLitMaterial> components, for respectively unlit and lit geometry. They take custom shader functions to make arbitrary materials.

menu
format_list_numbered