Skip to content

Commit

Permalink
feat(Fit): add component, playground, demo
Browse files Browse the repository at this point in the history
  • Loading branch information
andretchen0 committed Apr 29, 2024
1 parent a0b2a84 commit a521903
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export default defineConfig({
{ text: 'Precipitation', link: '/guide/staging/precipitation' },
{ text: 'Sparkles', link: '/guide/staging/sparkles' },
{ text: 'Ocean', link: '/guide/staging/ocean' },
{ text: 'Fit', link: '/guide/staging/fit' },
],
},
{
Expand Down
30 changes: 30 additions & 0 deletions docs/.vitepress/theme/components/FitDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { Fit, OrbitControls } from '@tresjs/cientos'
import { BoxGeometry, MeshNormalMaterial } from 'three'
const positions: number[][] = []
for (let y = 100; y <= 120; y += 10) {
for (let x = 100; x <= 120; x += 10) {
positions.push([x, y, 9999])
}
}
const geom = new BoxGeometry()
const mat = new MeshNormalMaterial()
</script>

<template>
<TresCanvas clear-color="#4F4F4F">
<TresPerspectiveCamera :position="[1, 1, 1]" />
<OrbitControls />
<Fit>
<TresMesh
v-for="(p, i) in positions"
:key="i"
:position="p"
:args="[geom, mat]"
/>
</Fit>
<TresGridHelper :args="[1, 1]" />
</TresCanvas>
</template>
23 changes: 23 additions & 0 deletions docs/guide/staging/fit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Fit

<DocsDemo>
<FitDemo />
</DocsDemo>

`<Fit />` uniformly scales and positions its children as a group. By default, it fits its children into a <nobr>1 × 1 × 1 box</nobr> at the world origin.

Alternatively, the children can be fit into a `Box3` or an `Object3D`.

Or the children can simply be resized. With `<Fit />` the children are scaled relative to the center of their calculated bounding box.

## Usage

<<< @/.vitepress/theme/components/FitDemo.vue{3,20-27}

## Props

<CientosPropsTable :on-format-value="({valueFormatted, propName, fieldName, getFieldFormatted}) => {
if (fieldName === 'description') {
return valueFormatted + '<p>default:<br />' + getFieldFormatted('default') + '</p>'
}
}" :fields="['name', 'description']" component-path="src/core/staging/Fit.vue" />
204 changes: 204 additions & 0 deletions playground/src/pages/staging/FitDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
<script setup lang="ts">
import { TresCanvas, useRenderLoop } from '@tresjs/core'
import { OrbitControls, Fit } from '@tresjs/cientos'
import { BoxGeometry, Mesh, MeshBasicMaterial, Vector3, Box3 } from 'three'
import RandUtils from '../../../../src/core/abstractions/Lensflare/RandUtils'
function getPositions(seed: number, count = 40, radius = 10) {
const positions: Vector3[] = []
const rng = new RandUtils(seed)
const rand = () => rng.rand()
const offsetX = rand() * 10
const offsetY = rand() * 10
const offsetZ = rand() * 10
const radX = rand() * radius + 1
const radY = rand() * radius + 1
const radZ = rand() * radius + 1
for (let i = 0; i < count; i++) {
positions.push(
new Vector3(
rand() * radX + offsetX,
rand() * radY + offsetY,
rand() * radZ + offsetZ,
),
)
}
return positions
}
const object = new Mesh(new BoxGeometry(), new MeshBasicMaterial({ wireframe: true }))
const choices = [
{ label: 'null', value: null },
{ label: 'undefined', value: undefined },
{ label: 'Number', value: 2 },
{ label: 'Array', value: [5, 6, 7] },
{ label: 'Vector3', value: new Vector3(3, 2, 1) },
{ label: 'Box3', value: new Box3(new Vector3(-5, 0, -5), new Vector3(5, 10, 5)) },
{ label: 'Object', value: object },
]
const choice = shallowRef(choices[1])
const [ sx0, sy0, sz0, rx0, ry0, rz0, x0, y0, z0, sx1, sy1, sz1, rx1,
ry1, rz1, x1, y1, z1, sx2, sy2, sz2, rx2, ry2, rz2, x2, y2, z2,
x3, y3 ] = Array.from({ length: 30 })
.fill(0)
.map(_ => shallowRef(0))
const fit0 = shallowRef({ fit: () => {} })
const fit1 = shallowRef({ fit: () => {} })
const fit2 = shallowRef({ fit: () => {} })
const { sin, cos, PI } = Math
useRenderLoop().onLoop(({ delta, elapsed }) => {
rx0.value = sin(elapsed * 0.05) * PI
ry0.value = sin(elapsed * 0.11) * PI
rz0.value = sin(elapsed * 0.22) * PI
rx1.value = sin(elapsed * 0.66) * PI
ry1.value = sin(elapsed * 0.77) * PI
rz1.value = sin(elapsed * 0.88) * PI
rx2.value = sin(elapsed * 1.33) * PI
ry2.value = sin(elapsed * 1.44) * PI
rz2.value = sin(elapsed * 1.55) * PI
x0.value = sin(elapsed * 0.33)
y0.value = sin(elapsed * 0.44)
z0.value = sin(elapsed * 0.55)
x1.value = sin(elapsed * 0.99)
y1.value = sin(elapsed * 1.11)
z1.value = sin(elapsed * 1.22)
x2.value = sin(elapsed * 1.66)
y2.value = sin(elapsed * 1.77)
z2.value = sin(elapsed * 1.88)
x3.value = sin(elapsed)
y3.value = cos(elapsed)
sx0.value = cos(elapsed * 0.22)
sy0.value = cos(elapsed * 0.33)
sz0.value = cos(elapsed * 0.33)
sx1.value = cos(elapsed * 0.22)
sy1.value = cos(elapsed * 0.44)
sz1.value = cos(elapsed * 0.55)
sx2.value = cos(elapsed * 0.66)
sy2.value = cos(elapsed * 0.77)
sz2.value = cos(elapsed * 0.88)
sx0.value = 2
sy0.value = 2
sz0.value = 2
sx1.value = 1
sy1.value = 1
sz1.value = 1
sx2.value = 20
sy2.value = 30
sz2.value = 10
fit0.value.update()
fit1.value.update()
fit2.value.update()
})
</script>

<template>
<div class="overlay">
<h2><code>:into</code> value</h2>
<template
v-for="c, i of choices"
:key="i"
>
<div>
<input
:id="`id-${i}`"
:checked="c === choice"
type="radio"
value="c.label"
name="choice"
@change="() => { choice = c; }"
>
<label :for="`id-${i}`">{{ `${c.label} - ${JSON.stringify(c.value)?.substring(0, 25)}` }}</label>
</div>
</template>
<p>N.B.: <code>fit.update()</code> is called continuously in the update loop.</p>
</div>
<TresCanvas>
<TresPerspectiveCamera :position="[5, 5, 5]" />
<TresGroup
:rotation="[rx0, ry0, rz0]"
:position="[x0, y0, z0]"
:scale="[sx0, sy0, sz0]"
>
<TresGroup
:rotation="[rx1, ry1, rz1]"
:position="[x1, y1, z1]"
:scale="[sx1, sy1, sz1]"
>
<TresGroup
:rotation="[-1, 0, 0]"
:visible="choice.value === object"
>
<primitive :object="object" />
</TresGroup>
<TresGroup
:rotation="[rx2, ry2, rz2]"
:position="[x2, y2, z2]"
:scale="[sx0, sy0, sz0]"
>
<Fit
ref="fit0"
:into="choice.value"
>
<TresMesh
v-for="(p, ii) of getPositions(0)"
:key="ii"
:position="p"
>
<TresBoxGeometry />
<TresMeshBasicMaterial color="red" />
</TresMesh>
</Fit>
</TresGroup>
</TresGroup>
</TresGroup>
<Fit
ref="fit1"
:into="choice.value"
>
<TresMesh :position="[x3, y3, 3]">
<TresTorusGeometry />
<TresMeshBasicMaterial color="blue" />
</TresMesh>
<TresMesh :position="[x3, y3, 0]">
<TresTorusGeometry />
<TresMeshBasicMaterial color="blue" />
</TresMesh>
<TresMesh :position="[x3, y3, -3]">
<TresTorusGeometry />
<TresMeshBasicMaterial color="blue" />
</TresMesh>
</Fit>
<Fit
ref="fit2"
:into="choice.value"
>
<TresMesh :position="[0, 0, -5]">
<TresSphereGeometry />
<TresMeshBasicMaterial color="green" />
</TresMesh>
</Fit>
<OrbitControls />
<TresGridHelper />
</TresCanvas>
</template>

<style scoped>
.overlay {
z-index:2;
position: fixed;
width: 200px;
padding: 10px;
margin: 5px;
font-family: sans-serif;
font-size: 10px;
background-color: white;
border-radius: 5px;
}
</style>
5 changes: 5 additions & 0 deletions playground/src/router/routes/staging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ export const stagingRoutes = [
name: 'Ocean',
component: () => import('../../pages/staging/OceanDemo.vue'),
},
{
path: '/staging/fit',
name: 'Fit',
component: () => import('../../pages/staging/FitDemo.vue'),
},
]
Loading

0 comments on commit a521903

Please sign in to comment.