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: 503 conditional rendering of primitives #514

Merged
merged 10 commits into from
Feb 21, 2024
1 change: 1 addition & 0 deletions playground/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ declare module 'vue' {
DanielTest: typeof import('./src/components/DanielTest.vue')['default']
DebugUI: typeof import('./src/components/DebugUI.vue')['default']
DeleteMe: typeof import('./src/components/DeleteMe.vue')['default']
DynamicModel: typeof import('./src/components/DynamicModel.vue')['default']
FBXModels: typeof import('./src/components/FBXModels.vue')['default']
Gltf: typeof import('./src/components/gltf/index.vue')['default']
LocalOrbitControls: typeof import('./src/components/LocalOrbitControls.vue')['default']
Expand Down
21 changes: 21 additions & 0 deletions playground/src/components/DynamicModel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { useControls } from '@tresjs/leches'
import { useGLTF } from '@tresjs/cientos'

const { nodes }
= await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/blender-cube.glb',
{ draco: true })

const { scene: AkuAku, nodes: akukuNodes } = await useGLTF(
'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf',
{ draco: true },
)

const { isCube } = useControls({
isCube: false,
})
</script>

<template>
<primitive :object="isCube ? nodes.Cube : AkuAku" />
</template>
32 changes: 15 additions & 17 deletions playground/src/components/TheExperience.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { BasicShadowMap, SRGBColorSpace, NoToneMapping } from 'three'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { TresLeches, useControls } from '@tresjs/leches'
import '@tresjs/leches/styles'
import TheSphere from './TheSphere.vue'
import '@tresjs/leches/styles'

const gl = {
clearColor: '#82DBC5',
Expand All @@ -17,17 +17,14 @@ const gl = {
}

const wireframe = ref(true)

const canvas = ref()
const meshRef = ref()

const { isVisible } = useControls({
isVisible: true,
})
const canvas = ref()

watchEffect(() => {
if (meshRef.value) {
console.log(meshRef.value)
if (canvas.value) {
console.log(canvas.value.context)
}
})
</script>
Expand All @@ -37,7 +34,6 @@ watchEffect(() => {
<TresCanvas
v-bind="gl"
ref="canvas"
window-size
class="awiwi"
:style="{ background: '#008080' }"
>
Expand All @@ -46,16 +42,21 @@ watchEffect(() => {
:look-at="[0, 4, 0]"
/>
<OrbitControls />
<TresFog
:color="gl.clearColor"
:near="5"
:far="15"
/>
<TresMesh
:position="[-2, 6, 0]"
:rotation="[0, Math.PI, 0]"
name="cone"
cast-shadow
>
<TresConeGeometry :args="[1, 1.5, 3]" />
<TresMeshToonMaterial color="#82DBC5" />
</TresMesh>
<TresMesh
v-if="isVisible"
:position="[0, 4, 0]"
cast-shadow
>
Expand All @@ -66,22 +67,19 @@ watchEffect(() => {
/>
</TresMesh>
<TresMesh
ref="meshRef"
:rotation="[-Math.PI / 2, 0, Math.PI / 2]"
name="floor"
:rotation="[-Math.PI / 2, 0, 0]"
receive-shadow
>
<TresPlaneGeometry :args="[20, 20, 20]" />
<TresMeshToonMaterial
color="#D3FC8A"
/>
<TresPlaneGeometry :args="[10, 10, 10, 10]" />
<TresMeshToonMaterial color="#D3FC8A" />
</TresMesh>
<TheSphere v-if="isVisible" />
<TheSphere />
<TresAxesHelper :args="[1]" />
<TresDirectionalLight
:position="[0, 2, 4]"
:intensity="2"
cast-shadow
/>
<TresOrthographicCamera />
</TresCanvas>
</template>
103 changes: 103 additions & 0 deletions playground/src/pages/primitives.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
import {
BasicShadowMap,
SRGBColorSpace,
NoToneMapping,
Mesh,
TorusGeometry,
MeshToonMaterial,
TorusKnotGeometry,
PlaneGeometry,
Group,
SphereGeometry,
} from 'three'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
import { TresLeches, useControls } from '@tresjs/leches'
import '@tresjs/leches/styles'

const gl = {
clearColor: '#82DBC5',
shadows: true,
alpha: false,
shadowMapType: BasicShadowMap,
outputColorSpace: SRGBColorSpace,
toneMapping: NoToneMapping,
}
const canvas = ref()
const meshRef = ref()

const { knot } = useControls({
knot: false,
})

const { isVisible } = useControls({
isVisible: true,
})

watchEffect(() => {
if (meshRef.value) {
console.log(meshRef.value)
}
})

const torus = new Mesh(
new TorusGeometry(1, 0.5, 16, 100),
new MeshToonMaterial({
color: '#82DBC5',
}),
)

const torusKnot = new Mesh(
new TorusKnotGeometry(1, 0.5, 100, 16),
new MeshToonMaterial({
color: '#ff00ff',
}),
)

const sphere = new Mesh(
new SphereGeometry(1, 32, 32),
new MeshToonMaterial({
color: '#82DBC5',
}),
)

Copy link
Contributor

@andretchen0 andretchen0 Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In nodeOps.ts, I mentioned that cloning means that setup references are lost. Below is some demonstration code that can be pasted here.

useRenderLoop().onLoop(() => {
  torus.rotateX(0.01)
  torusKnot.rotateY(0.01)
})

Both torus and torusKnot continue to exist after the clone, but they no longer point to the on-screen objects, so the on-screen objects don't update.

If the objects aren't clone()d in nodeOps, the on-screen shapes will rotate – but other errors pop up.

I don't know if there's a workaround here. Just pointing it out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andretchen0 This argument makes me think we should abandon the idea of trying to make :object prop reactive, swiping instances without losing the ref is getting too complicated.

Users could still use primitives with conditional rendering, I wanted primitive to work similar to component but honestly at this point I don't know how to achieve it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alvarosabu

I don't understand the internals of Tres well enough to have an opinion on the feasibility here.

I'll start reading the source after I finish <AnimatedSprite /> for Cientos.

I wanted primitive to work similar to component but honestly at this point I don't know how to achieve it.

I agree that this is a worthwhile goal. It'd be great if it "just works".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andretchen0 let me know if you are up to a pair-programming call to discuss the internals when you get free let me know, we definitely can use your knowledge and your quality feedback inside of the custom renderer code. 💚

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alvarosabu

Sure thing. That could be fun!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @andretchen0 I created a thread on the core team discord channel discussing this but to give a summary:

I found a way of making it work (animations), the only constraint is that the object passed through :object needs to be of the same type (mesh -> mesh) (group -> group). If we do (mesh -> group), it doesn't work anymore.

Screen_Recording_2024-02-02_at_12.43.44.mov

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll go read the Discord.

sphere.position.set(2, -2, 0)

const firstGroup = new Group()
firstGroup.add(torus)
firstGroup.add(torusKnot)

const secondGroup = new Group()
secondGroup.add(sphere)
</script>

<template>
<TresLeches />
<TresCanvas
v-bind="gl"
ref="canvas"
window-size
class="awiwi"
:style="{ background: '#008080' }"
>
<TresPerspectiveCamera
:position="[7, 7, 7]"
/>
<OrbitControls />
<primitive
v-if="isVisible"
:object="knot ? firstGroup : sphere"
/>
<Suspense>
<DynamicModel />
</Suspense>
<TresAxesHelper :args="[1]" />
<TresDirectionalLight
:position="[0, 2, 4]"
:intensity="2"
cast-shadow
/>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ const routes = [
name: 'Perf',
component: () => import('./pages/perf/index.vue'),
},
{
path: '/primitives',
name: 'Primitives',
component: () => import('./pages/primitives.vue'),
},
{
path: '/empty',
name: 'empty',
Expand Down
Loading