Skip to content

Commit

Permalink
docs(attach): add documentation for attach prop
Browse files Browse the repository at this point in the history
  • Loading branch information
andretchen0 committed Nov 3, 2024
1 parent 7498cc9 commit 4a2e096
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
{ text: 'Extending', link: '/advanced/extending' },
{ text: 'Primitives', link: '/advanced/primitive' },
{ text: 'Scaling Performance 🚀', link: '/advanced/performance' },
{ text: 'Attach', link: '/advanced/attach' },
{
text: 'Caveats',
link: '/advanced/caveats',
Expand Down
190 changes: 190 additions & 0 deletions docs/advanced/attach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# `attach` 🖇

Using the `attach` prop, you can tell Tres exactly where you want to insert a child into its parent.

:::info

The `attach` prop is not required for many common cases. For instance:

* adding a single `<Material>` to a `<Mesh>`
* adding a `<Geometry>` to a `<Mesh>`
* adding one or more `<Mesh>`s to a parent `<Mesh>`

:::

## Background

Tres tries to automatically determine where to insert child tag into its parent. For example, in this code, Tres will:

* automatically insert the geometry into `parent.geometry`
* automatically insert the material into `parent.material`

```vue
<template>
<TresMesh name="parent">
<TresBoxGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</template>
```

## Problem

Tres covers common cases, like above. But it doesn't cover every possible case.

When Tres doesn't automatically choose the proper insertion location for a child, one solution is to fall back to procedural code in `<script>`.

Here's how you might add multiple materials to a mesh using `<script>`:

```vue
<script setup lang="ts">
import { MeshBasicMaterial } from 'three'
import { onMounted, shallowRef } from 'vue'
const meshRef = shallowRef()
onMounted(() => {
meshRef.value.material = [
new MeshBasicMaterial({ color: 'red' }),
new MeshBasicMaterial({ color: 'orange' }),
new MeshBasicMaterial({ color: 'yellow' }),
new MeshBasicMaterial({ color: 'green' }),
new MeshBasicMaterial({ color: 'blue' }),
new MeshBasicMaterial({ color: 'purple' }),
]
})
</script>
<template>
<TresMesh ref="meshRef">
<TresBoxGeometry />
</TresMesh>
</template>
```

But this workaround means:

* your materials aren't managed by Tres
* your code is imperative, not declarative
* your code is non-reactive by default

## Solution

The `attach` prop lets you specify where an object will be added to the parent object using declarative code.

## Usage

Here's the example above, rewritten declaratively using `attach`:

```vue
<template>
<TresMesh>
<TresBoxGeometry />
<TresMeshBasicMaterial color="red" attach="material-0" />
<TresMeshBasicMaterial color="orange" attach="material-1" />
<TresMeshBasicMaterial color="yellow" attach="material-2" />
<TresMeshBasicMaterial color="green" attach="material-3" />
<TresMeshBasicMaterial color="blue" attach="material-4" />
<TresMeshBasicMaterial color="purple" attach="material-5" />
</TresMesh>
</template>
```

## "Pierced" `attach`

You can deeply attach a child to a parent by "piercing" – i.e., using a kebab-case string.

### Pseudocode

First, here are a few simple pseudocode examples. This will attach `bar` at `foo.ab.cd`:

```html
<foo>
<bar attach="ab-cd" />
</foo>
```

This will attach `bar` at `foo.ab.cd.ef`:

```html
<foo>
<bar attach="ab-cd-ef" />
</foo>
```

### Usage

As a concrete example, you can used "pierced" `attach` to add custom `BufferAttribute`s:

```vue
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
const positions = new Float32Array([-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0])
</script>
<template>
<TresCanvas clear-color="gray">
<TresMesh :scale="0.3333">
<TresBufferGeometry>
<TresBufferAttribute
attach="attributes-position"
:count="positions.length / 3"
:array="positions"
:itemSize="3"
/>
</TresBufferGeometry>
<TresMeshBasicMaterial color="red" />
</TresMesh>
</TresCanvas>
</template>
```

## Arrays

You can attach within arrays by using array indices in the `attach` string.

### Usage

For example, you can use array indices to attach `THREE` post-processing passes to the `THREE.EffectComposer.passes` array:

```vue
<script lang="ts" setup>
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass'
import { UnrealBloomPass } from 'three-stdlib'
import { extend, useLoop, useTres } from '@tresjs/core'
import { shallowRef } from 'vue'
extend({ EffectComposer, OutputPass, UnrealBloomPass, RenderPass })
const { renderer, scene, camera, sizes } = useTres()
const composer = shallowRef<EffectComposer>()
useLoop().render(() => {
if (composer.value) {
composer.value!.render()
}
})
</script>
<template>
<TresEffectComposer
ref="composer"
:args="[renderer]"
:set-size="[sizes.width.value, sizes.height.value]"
>
<TresRenderPass
:args="[scene, camera]"
attach="passes-0"
/>
<TresUnrealBloomPass
:args="[undefined, 0.5, 0.1, 0]"
attach="passes-1"
/>
<TresOutputPass
attach="passes-2"
:set-size="[sizes.width.value, sizes.height.value]"
/>
</TresEffectComposer>
</template>
```

0 comments on commit 4a2e096

Please sign in to comment.