Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Release v4.2 #563

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0506506
Merge pull request #18 from Tresjs/feature/17-reactive-3dtext-with-ne…
alvarosabu May 2, 2023
6ed4922
Merge branch 'main' into next
alvarosabu Dec 13, 2024
12e9748
docs: un-comment back the new features
alvarosabu Dec 13, 2024
63535a2
feat(Helper): add component, demo, docs (#543)
andretchen0 Dec 13, 2024
4528f64
feat(PointMaterial): add component, demo, docs (#545)
andretchen0 Dec 14, 2024
34a3db5
feat(ScreenQuad): add component, playground, docs (#530)
andretchen0 Dec 14, 2024
2ebc1e6
feat(MarchingCubes): add component, demo, docs (#553)
andretchen0 Dec 17, 2024
99c3a60
feat(CubicBezierLine): add component, demo, docs (#546)
andretchen0 Jan 2, 2025
4a9f006
feat(QuadraticBezierLine): add component, demo, docs (#548)
andretchen0 Jan 2, 2025
7e6b8d0
feat(AccumulativeShadows): add component, demo, docs (#558)
andretchen0 Jan 2, 2025
592ec68
feat(Bounds): add component, demo, docs (#408) (#568)
andretchen0 Jan 2, 2025
789110e
refactor(Align): change callback to emit, improve naming (#571)
andretchen0 Jan 2, 2025
32562b8
Merge branch 'main' into next
alvarosabu Jan 2, 2025
c0c1bcc
feat(CircleShadow): add component, demo, docs (#549)
andretchen0 Jan 2, 2025
9db8c78
feat(Stage): add component, demo, docs (#572)
andretchen0 Jan 3, 2025
000858f
chore(Outline): type material
andretchen0 Jan 3, 2025
ef6438c
feat(LOD): add component, playground, docs (#524)
andretchen0 Jan 4, 2025
d34411a
Merge branch 'main' into next
alvarosabu Jan 5, 2025
59e1888
refactor(Bounds): replace clamp import with MathUtils.clamp for consi…
alvarosabu Jan 5, 2025
b0ba621
feat(useIntersect): add function, demo, docs (#550)
andretchen0 Jan 6, 2025
4da0c42
chore: update dependencies in package.json and pnpm-lock.yaml
alvarosabu Jan 6, 2025
bc54a1d
fix: fixes to next components and docs (#586)
andretchen0 Jan 17, 2025
78d6745
Merge branch 'main' into next
alvarosabu Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(LOD): add component, playground, docs (#524)
Co-authored-by: Alvaro Saburido <alvaro.saburido@gmail.com>
andretchen0 and alvarosabu authored Jan 4, 2025
commit ef6438c46d43d83ee6bf5d1b4e36a9a7e69c8297
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -185,6 +185,7 @@ export default defineConfig({
{ text: 'StatsGl', link: '/guide/misc/stats-gl' },
{ text: 'useGLTFExporter', link: '/guide/misc/use-gltf-exporter' },
{ text: 'BakeShadows', link: '/guide/misc/bake-shadows' },
{ text: 'LOD', link: '/guide/misc/lod' },
],
},
],
55 changes: 55 additions & 0 deletions docs/.vitepress/theme/components/LODDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script setup lang="ts">
import { LOD } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { BoxGeometry, IcosahedronGeometry, MeshBasicMaterial, Vector3 } from 'three'
import { onMounted, onUnmounted, ref } from 'vue'

const COUNT = 1000
const positions = Array.from({ length: COUNT }).fill(0).map((_, i) => {
return new Vector3(
Math.cos(i) * 1000,
Math.sin(i) * 1000,
8000 * (2 * i / COUNT - 1),
)
})

const geometries = [
new IcosahedronGeometry(100, 4),
new IcosahedronGeometry(100, 0),
new BoxGeometry(100, 100, 100),
]

const materials = [
new MeshBasicMaterial({ color: '#fbb03b', wireframe: true }),
new MeshBasicMaterial({ color: '#82dbc5', wireframe: true }),
new MeshBasicMaterial({ color: '#4f4f4f', wireframe: true }),
]

const z = ref(0)
let intervalId: ReturnType<typeof setInterval>
let elapsed = 0

onMounted(() => {
intervalId = setInterval(() => {
elapsed += 0.005
z.value = Math.cos(elapsed) * 5000
}, 1000 / 30)
})

onUnmounted(() => {
clearInterval(intervalId)
})
</script>

<template>
<TresCanvas clear-color="gray">
<TresPerspectiveCamera :near="1" :far="25000" :position="[0, 0, 0]" />
<TresGroup :position-z="z">
<LOD v-for="position, i of positions" :key="i" :levels="[1500, 3000, 4000]" :position="position">
<TresMesh :geometry="geometries[0]" :material="materials[0]" />
<TresMesh :geometry="geometries[1]" :material="materials[1]" />
<TresMesh :geometry="geometries[2]" :material="materials[2]" />
</LOD>
</TresGroup>
</TresCanvas>
</template>
1 change: 1 addition & 0 deletions docs/component-list/components.ts
Original file line number Diff line number Diff line change
@@ -137,6 +137,7 @@ export default [
{ text: 'StatsGl', link: '/guide/misc/stats-gl' },
{ text: 'useGLTFExporter', link: '/guide/misc/use-gltf-exporter' },
{ text: 'BakeShadows', link: '/guide/misc/bake-shadows' },
{ text: 'LOD', link: '/guide/misc/lod' },
],
},
{
19 changes: 19 additions & 0 deletions docs/guide/misc/lod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# LOD

Level of Detail - show meshes with more or less geometry based on distance from the camera.

`<LOD />` is a wrapper for THREE's [LOD](https://threejs.org/docs/?q=LOD#api/en/objects/LOD) class.

<DocsDemo>
<LODDemo />
</DocsDemo>

## Usage
<<< @/.vitepress/theme/components/LODDemo.vue

## Props

| Prop | Description | Default |
| :----------------- | :--------------------------------------------------------------------- | ------- |
| **levels** | `number[]` - The distances at which to display each level of detail. There should be one `levels` value for each `LOD` child. | |
| **hysteresis** | Threshold used to avoid flickering at LOD boundaries, as a fraction of distance. | `0.0` |
78 changes: 78 additions & 0 deletions playground/vue/src/pages/misc/LODDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import { LOD } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { BoxGeometry, IcosahedronGeometry, MeshBasicMaterial, Vector3 } from 'three'

const COUNT = 1000
const positions = Array.from({ length: COUNT }).fill(0).map(() => {
return new Vector3(
10000 * (Math.random() * 2 - 1),
7500 * (Math.random() * 2 - 1),
10000 * (Math.random() * 2 - 1),
)
})

const geometries = [
new IcosahedronGeometry(100, 16),
new IcosahedronGeometry(100, 8),
new IcosahedronGeometry(100, 4),
new IcosahedronGeometry(100, 2),
new BoxGeometry(100, 100, 100),
]

const materials = [
new MeshBasicMaterial({ color: 'red', wireframe: true }),
new MeshBasicMaterial({ color: 'orange', wireframe: true }),
new MeshBasicMaterial({ color: 'yellow', wireframe: true }),
new MeshBasicMaterial({ color: 'green', wireframe: true }),
new MeshBasicMaterial({ color: 'blue', wireframe: true }),
]

const x = ref(0)
let intervalId: ReturnType<typeof setInterval>
let elapsed = 0

const levels = ref([1000, 2000, 3000, 4000, 5000])

onMounted(() => {
intervalId = setInterval(() => {
elapsed += 0.01
x.value = Math.cos(elapsed) * 5000
})
})

function resetLevels() {
const i = Math.random() * 10000
levels.value = [i, i * 2, i * 3, i * 4, i * 5]

// NOTE: Make `levels` too short sometimes.
if (Math.random() > 0.5) {
while (levels.value.length && Math.random() > 0.5) {
levels.value.pop()
}
}
else {
// NOTE: Reverse levels sometimes.
levels.value.reverse()
}
}

onUnmounted(() => {
clearInterval(intervalId)
})
</script>

<template>
<TresCanvas clear-color="gray" @pointerdown="resetLevels">
<TresPerspectiveCamera :near="1" :far="25000" :position="[0, 0, 0]" />
<TresGroup :position-z="x">
<LOD v-for="position, i of positions" :key="i" :levels="levels" :position="position">
<TresMesh :geometry="geometries[0]" :material="materials[0]" />
<TresMesh :geometry="geometries[1]" :material="materials[1]" />
<TresMesh :geometry="geometries[2]" :material="materials[2]" />
<TresMesh :geometry="geometries[3]" :material="materials[3]" />
<TresMesh :geometry="geometries[4]" :material="materials[4]" />
</LOD>
</TresGroup>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/vue/src/router/routes/misc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export const miscRoutes = [
{
path: '/misc/lod',
name: 'LOD',
component: () => import('../../pages/misc/LODDemo.vue'),
},
{
path: '/misc/html',
name: 'HTML',
76 changes: 76 additions & 0 deletions src/core/misc/LOD.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script setup lang="ts">
import type { Object3D } from 'three'
import { LOD } from 'three'
import { isReactive, onMounted, shallowRef, watch } from 'vue'

interface LODProps {
/**
* The distances at which to display each level of detail.
* There should be one `levels` value for each `LOD` child.
*/
levels: number[]
/**
* Threshold used to avoid flickering at LOD boundaries, as a fraction of distance
* @default 0.0
*/
hysteresis?: number
}

const props = withDefaults(
defineProps<LODProps>(),
{
hysteresis: 0.0,
},
)

const lodRef = shallowRef(new LOD())

function onChange() {
// NOTE: Check validity of `levels`.
// It should exist. It should be an array. Every value should be a number.
const distances = (props.levels && props.levels.length && props.levels.every(n => typeof n === 'number')) ? [...props.levels] : [1000]

// NOTE: Add `levels` values if there fewer `levels` values than `children`.
while (distances.length < lodRef.value.children.length) {
distances.push(Math.abs(distances[distances.length - 1]) * 2)
}

// NOTE: Levels can be in any order, but the THREE implementation doesn't work
// work properly unless the levels are pushed in ascending order of `distance`.
// So, construct ascending order of `distance`.
const levels = [] as { distance: number, hysteresis: number, object: Object3D }[]
for (let i = 0; i < lodRef.value.children.length; i++) {
const hysteresis = props.hysteresis
const distance = distances[i]
const object = lodRef.value.children[i]
levels.push({ hysteresis, distance, object })
}
levels.sort((a, b) => a.distance - b.distance)

// NOTE: Clear the current LOD levels.
lodRef.value.levels.length = 0

// NOTE: Push levels in ascending order of `distance`.
levels.forEach(level => lodRef.value.levels.push(level))
}

if (isReactive(props.levels)) {
watch(() => props.levels, onChange)
}

if (isReactive(props.hysteresis)) {
watch(() => props.hysteresis, onChange)
}

onMounted(onChange)

defineExpose({
instance: lodRef,
})
</script>

<template>
<TresLOD ref="lodRef">
<slot></slot>
</TresLOD>
</template>
3 changes: 2 additions & 1 deletion src/core/misc/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BakeShadows } from './BakeShadows'
import LOD from './LOD.vue'
import Html from './html/HTML.vue'
import { Stats } from './Stats'
import { StatsGl } from './StatsGl'
import { useGLTFExporter } from './useGLTFExporter'

export { BakeShadows, Html, Stats, StatsGl, useGLTFExporter }
export { BakeShadows, Html, LOD, Stats, StatsGl, useGLTFExporter }