threlte logo

Rendering Points

<script>
  import { Canvas } from '@threlte/core'
  import Scene from './Scene.svelte'
</script>

<div>
  <Canvas>
    <Scene />
  </Canvas>
</div>

<style>
  div {
    height: 100%;
  }
</style>
<script lang="ts">
  import { T } from '@threlte/core'
  import { Align, OrbitControls } from '@threlte/extras'

  const size = 30
  const count = size ** 3

  const positions = new Float32Array(count * 3)

  // 3D math squiggles
  for (let i = 0; i < count; i++) {
    // 1D to 3D array
    let x = i / (size * size)
    let y = (i / size) % size
    let z = i % size

    const vx =
      Math.sin(Math.abs(size - x) * 0.1) * Math.sin(Math.abs(size - y) * 0.1) * 10 +
      Math.random() * 0.1

    const vy =
      Math.sin(Math.abs(size - x) * 0.3) * Math.sin(Math.abs(size - y) * 0.3) * 10 +
      Math.random() * 0.1

    const vz = y + Math.random() * 0.01 * z

    //x
    positions[i * 3 + 0] = vx
    //y
    positions[i * 3 + 1] = vy
    //z
    positions[i * 3 + 2] = vz
  }
</script>

<T.PerspectiveCamera
  makeDefault
  position={[50, 50, 50]}
  fov={15}
>
  <OrbitControls autoRotate />
</T.PerspectiveCamera>

<T.DirectionalLight
  position.y={10}
  position.z={10}
/>

<Align>
  <T.Points>
    <T.BufferGeometry>
      <T.BufferAttribute
        args={[positions, 3]}
        attach={({ parent, ref }) => {
          parent.setAttribute('position', ref)
          return () => {
            // cleanup function called when ref changes or the component unmounts
            // https://threlte.xyz/docs/reference/core/t#attach
          }
        }}
      />
    </T.BufferGeometry>
    <T.PointsMaterial size={0.25} />
  </T.Points>
</Align>
<script lang="ts">
  import { T } from '@threlte/core'
  import { Align, OrbitControls } from '@threlte/extras'
  import { BufferGeometry, Vector3 } from 'three'

  const size = 30
  const count = size ** 3

  const vectorPositions: Vector3[] = []

  // 3D math squiggles
  for (let i = 0; i < count; i++) {
    // 1D to 3D array
    let x = i / (size * size)
    let y = (i / size) % size
    let z = i % size

    const vx =
      Math.sin(Math.abs(size - x) * 0.1) * Math.sin(Math.abs(size - y) * 0.1) * 10 +
      Math.random() * 0.1

    const vy =
      Math.sin(Math.abs(size - x) * 0.3) * Math.sin(Math.abs(size - y) * 0.3) * 10 +
      Math.random() * 0.1

    const vz = y + Math.random() * 0.01 * z

    vectorPositions.push(new Vector3(vx, vy, vz))
  }

  const pointsBufferGeometry = new BufferGeometry().setFromPoints(vectorPositions)
</script>

<T.PerspectiveCamera
  makeDefault
  position={[50, 50, 50]}
  fov={15}
>
  <OrbitControls autoRotate />
</T.PerspectiveCamera>

<T.DirectionalLight
  position.y={10}
  position.z={10}
/>

<Align>
  <T.Points>
    <T is={pointsBufferGeometry} />
    <T.PointsMaterial size={0.25} />
  </T.Points>
</Align>

Using Points

Points work in Threlte the same way they do in Three. Check three docs about Points and Point Material to learn more.

Ensuring Points Work Correctly with BufferGeometry

For your points to function correctly, it’s essential that they have an associated BufferGeometry with a specified attribute for point positions. Here’s a straightforward method using the default Threlte approach:

<T.Points>
  <T.BufferGeometry>
    <T.BufferAttribute
      args={[positions, 3]}
      attach={({ parent, ref }) => {
        parent.setAttribute('position', ref)
        return () => {
          // cleanup function called when ref changes or the component unmounts
          // https://threlte.xyz/docs/reference/core/t#attach
        }
      }}
    />
  </T.BufferGeometry>
  <T.PointsMaterial size={0.25} />
</T.Points>

In the case of <T.BufferAttribute>, it is not enough to make it a child of <T.BufferGeometry>. To actually link it, you must invoke the attach method. If you skip this step, the attribute won’t be associated with the geometry. Learn more about how attach works.

Alternatively, you can also define and manage BufferGeometry within <script> tags or in an external file. Once done, the <T> component allows for direct attachment to <T.Points>, like so:

<T.Points>
  <T is={pointsBufferGeometry} />
  <T.PointsMaterial size={0.25} />
</T.Points>

Working code for this approach can be found in SceneAlternative.svelte file of this example.