Skip to content

Commit

Permalink
Controlled Particles (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmans committed Sep 22, 2022
1 parent e0a1c00 commit 7dadce0
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/thirty-ads-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vfx-composer-r3f": patch
---

Added a first version of `<Particle>`, a scene-graph component that controls a single particle from the CPU.
13 changes: 6 additions & 7 deletions apps/vfx-composer-examples/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import {
Application,
Description,
Example,
FlatStage,
Heading
} from "r3f-stage"
import { Application, Description, Example, Heading } from "r3f-stage"
import "r3f-stage/styles.css"
import AsteroidExample from "./examples/Asteroid"
import ControlledParticlesExample from "./examples/ControlledParticles"
import { FireflyExample } from "./examples/FireflyExample"
import { FogExample } from "./examples/FogExample"
import MagicWellExample from "./examples/MagicWellExample"
Expand Down Expand Up @@ -74,6 +69,10 @@ export default () => (
<SoftParticlesExample />
</Example>

<Example path="controlled-particles" title="Controlled Particles">
<ControlledParticlesExample />
</Example>

<Heading>Scenes</Heading>
<Example path="scenes/asteroid" title="Asteroid">
<AsteroidExample />
Expand Down
34 changes: 34 additions & 0 deletions apps/vfx-composer-examples/src/examples/ControlledParticles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useFrame } from "@react-three/fiber"
import { useRef } from "react"
import { Group } from "three"
import { Particle, Particles } from "vfx-composer-r3f"

export default function ControlledParticlesExample() {
const group = useRef<Group>(null!)

useFrame(({ clock }) => {
group.current.position.set(
Math.cos(clock.elapsedTime * 1.3),
Math.sin(clock.elapsedTime * 1.7),
0
)
})

return (
<group>
<Particles>
<sphereGeometry args={[0.5, 16, 16]} />
<meshStandardMaterial color="hotpink" />

<group ref={group}>
<mesh>
<boxGeometry />
<meshBasicMaterial wireframe />
</mesh>

<Particle />
</group>
</Particles>
</group>
)
}
57 changes: 57 additions & 0 deletions packages/vfx-composer-r3f/src/Particle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Object3DProps, useFrame } from "@react-three/fiber"
import React, {
forwardRef,
useImperativeHandle,
useLayoutEffect,
useRef
} from "react"
import { Matrix4, Object3D } from "three"
import { useParticlesContext } from "./Particles"

const hideMatrix = new Matrix4().makeScale(0, 0, 0)

const tmpMatrix = new Matrix4()

/**
* Use `<Particle>` to emit a single particle that remains CPU-controlled, meaning
* that it will continuously update its instance matrix to match its transform
* in the Three.js scene graph.
*
* **Note:** As soon as you use just a single `<Particle>` in your `<Particles>` effect,
* it will disable the partial buffer updates, and result in a full buffer update every frame.
*/
export const Particle = forwardRef<Object3D, Object3DProps>((props, ref) => {
const sceneObject = useRef<Object3D>(null!)
const particles = useParticlesContext()
const id = useRef<number>()

/* Hide the particle again on unmount */
useLayoutEffect(() => {
const cursor = particles.cursor
id.current = cursor
particles.emit(1)

return () => {
particles.setMatrixAt(cursor, hideMatrix)
}
}, [particles])

/* Every frame, update the particle's matrix, and queue a re-upload */
useFrame(() => {
if (id.current === undefined) return

particles.setMatrixAt(
id.current,
tmpMatrix
.copy(sceneObject.current.matrixWorld)
.premultiply(particles.matrixWorld.invert())
)

particles.instanceMatrix.needsUpdate = true
})

/* Forward the ref */
useImperativeHandle(ref, () => sceneObject.current)

return <object3D ref={sceneObject} {...props} />
})
1 change: 1 addition & 0 deletions packages/vfx-composer-r3f/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./Emitter"
export * from "./hooks/particles"
export * from "./makeParticles"
export * from "./Particle"
export * from "./Particles"

0 comments on commit 7dadce0

Please sign in to comment.