diff --git a/apps/playground/public/lowpoly-planet.png b/apps/playground/public/lowpoly-planet.png new file mode 100644 index 000000000..c7a3f1dc0 Binary files /dev/null and b/apps/playground/public/lowpoly-planet.png differ diff --git a/apps/playground/src/components/lowpoly-planet/Airplane.vue b/apps/playground/src/components/lowpoly-planet/Airplane.vue new file mode 100644 index 000000000..7a965790c --- /dev/null +++ b/apps/playground/src/components/lowpoly-planet/Airplane.vue @@ -0,0 +1,72 @@ +<script setup lang="ts"> +import { useGLTF, useTweakPane } from '@tresjs/cientos' +import { useRenderLoop } from '@tresjs/core' +import { Object3D, Sphere } from 'three' +import { shallowRef, watch } from 'vue' + +const props = defineProps<{ + planet: Object3D +}>() + +const { scene } = await useGLTF( + 'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/low-poly/airplane.gltf', +) + +const airplaneRef = shallowRef() + +const airplane = scene +airplane.rotation.set(0, Math.PI, 0) +scene.traverse(child => { + if (child.isMesh) { + child.castShadow = true + } +}) +airplane.updateMatrixWorld() + +const { onLoop } = useRenderLoop() + +watch( + () => props.planet, + planet => { + if (!planet) return + const radius = Math.abs(planet.geometry.boundingSphere?.radius | 1) + 0.5 + airplane.position.set(radius, 0, 0) + + airplane.lookAt(planet.position) + }, +) + +const { pane } = useTweakPane() + +const folder = pane.addFolder({ + title: 'Airplane', + expanded: true, +}) + +watch( + () => airplaneRef.value, + planet => { + if (!planet) return + folder.addInput(airplaneRef.value, 'visible', { label: 'Visible' }) + }, +) + +let angle = 0 +let speed = 0.2 +onLoop(({ delta }) => { + if (!airplane) return + + const radius = Math.abs(props.planet.geometry.boundingSphere.radius) + 0.5 + angle += delta * speed + let x = radius * Math.cos(angle) + let z = radius * Math.sin(angle) + airplane.position.x = x + airplane.position.z = z + airplane.rotation.z = -Math.PI / 2 + airplane.rotation.y = -angle + airplane.updateMatrixWorld() +}) +</script> +<template> + <TresMesh ref="airplaneRef" v-bind="airplane" /> +</template> diff --git a/apps/playground/src/components/lowpoly-planet/Cloud.vue b/apps/playground/src/components/lowpoly-planet/Cloud.vue new file mode 100644 index 000000000..a19f3bfbe --- /dev/null +++ b/apps/playground/src/components/lowpoly-planet/Cloud.vue @@ -0,0 +1,57 @@ +<script setup lang="ts"> +import { useGLTF } from '@tresjs/cientos' +import { useRenderLoop } from '@tresjs/core' +import { Object3D } from 'three' +import { shallowRef, watch } from 'vue' + +const props = defineProps<{ + planet: Object3D +}>() + +const { scene } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/low-poly/cloud.gltf') +const cloudRef = shallowRef() + +const cloud = scene.children[0] as Object3D +cloud.castShadow = true +// create a function to return a random number between two values with random sign +function random(min: number, max: number): number { + const randomNumber = Math.random() * (max - min) + min + return Math.random() < 0.5 ? -randomNumber : randomNumber +} + +cloud.position.set(random(0.5, 8), random(0.5, 1), random(0.5, 8)) + +const size = random(0.5, 1) +cloud.scale.set(size, size, size) +cloud.updateMatrixWorld() + +watch( + () => props.planet, + planet => { + if (!planet) return + cloud.lookAt(planet.position) + cloud.updateMatrixWorld() + }, +) + +const { onLoop } = useRenderLoop() + +let angle = random(0.5, 1) * Math.PI +let speed = Math.random() / 10 +onLoop(({ delta }) => { + if (!cloud) return + + const radius = Math.abs(props.planet.geometry.boundingSphere.radius) + 0.5 + angle += delta * speed + let x = radius * Math.cos(angle) + let z = radius * Math.sin(angle) + cloud.position.x = x + cloud.position.z = z + cloud.rotation.y = -angle + cloud.lookAt(props.planet.position) + cloud.updateMatrixWorld() +}) +</script> +<template> + <TresMesh ref="cloudRef" v-bind="scene" cast-shadow /> +</template> diff --git a/apps/playground/src/components/lowpoly-planet/Planet.vue b/apps/playground/src/components/lowpoly-planet/Planet.vue new file mode 100644 index 000000000..8e1cf12c0 --- /dev/null +++ b/apps/playground/src/components/lowpoly-planet/Planet.vue @@ -0,0 +1,44 @@ +<script setup lang="ts"> +import { useGLTF, useTweakPane } from '@tresjs/cientos' +import { useRenderLoop } from '@tresjs/core' +import { shallowRef, watch } from 'vue' +import Airplane from './Airplane.vue' +import Cloud from './Cloud.vue' + +const { scene: planet } = await useGLTF( + 'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/low-poly/planet.gltf', +) + +const { pane } = useTweakPane() + +const planetRef = shallowRef() + +planet.traverse(child => { + if (child.isMesh) { + child.receiveShadow = true + } +}) + +watch( + () => planetRef.value, + planet => { + if (!planet) return + pane.addInput(planetRef.value, 'visible', { label: 'Planet' }) + }, +) + +const { onLoop } = useRenderLoop() + +onLoop(({ delta }) => { + if (!planet) return + planet.rotation.y += delta * 0.04 + planet.rotation.z += delta * 0.02 + planet.rotation.x += delta * 0.05 + planet.updateMatrixWorld() +}) +</script> +<template> + <TresMesh ref="planetRef" v-bind="planet" /> + <Airplane :planet="planetRef" /> + <Cloud v-for="cloud of [1, 2, 3, 4, 5, 6, 7, 8, 9]" :key="cloud" :planet="planetRef" /> +</template> diff --git a/apps/playground/src/components/lowpoly-planet/TheExperience.vue b/apps/playground/src/components/lowpoly-planet/TheExperience.vue new file mode 100644 index 000000000..681f0c7fe --- /dev/null +++ b/apps/playground/src/components/lowpoly-planet/TheExperience.vue @@ -0,0 +1,45 @@ +<script setup lang="ts"> +import { PCFSoftShadowMap, sRGBEncoding } from 'three' +import { OrbitControls } from '@tresjs/cientos' + +import Planet from './Planet.vue' +import { shallowRef, watch } from 'vue' +import { TresInstance } from '@tresjs/core/dist/types' + +const state = { + clearColor: '#11101B', + shadows: true, + alpha: false, + outputEncoding: sRGBEncoding, + shadowMapType: PCFSoftShadowMap, +} +const directionalLightRef = shallowRef<TresInstance>() + +watch( + () => directionalLightRef.value, + directionalLight => { + if (!directionalLight) return + + directionalLight.shadow.mapSize.width = 2048 + directionalLight.shadow.mapSize.height = 2048 + }, +) +</script> + +<template> + <Suspense> + <TresCanvas v-bind="state"> + <OrbitControls /> + <TresPerspectiveCamera :position="[0, 1, 3]" :fov="75" :near="0.1" :far="1000" /> + <TresScene> + <TresFog color="#11101B" :near="0.1" :far="1000" /> + <TresAmbientLight :color="0x484068" :intensity="1" /> + <Planet /> + + <TresAxesHelper /> + <TresPointLight color="#1BFFEF" :position="[0, 8, -16]" :intensity="8" cast-shadow /> + <TresDirectionalLight ref="directionalLightRef" :position="[0, 2, 4]" :intensity="1" cast-shadow /> + </TresScene> + </TresCanvas> + </Suspense> +</template> diff --git a/apps/playground/src/pages/vue/lowpoly-planet.mdx b/apps/playground/src/pages/vue/lowpoly-planet.mdx new file mode 100644 index 000000000..ca754e767 --- /dev/null +++ b/apps/playground/src/pages/vue/lowpoly-planet.mdx @@ -0,0 +1,40 @@ +--- +layout: /@/layouts/ExperimentLayout.astro +thumbnail: /lowpoly-planet.png +title: Low Poly Planet +author: Alvarosabu +description: Low Poly Planet exported from Blender +tags: ['basic', 'cientos', 'useGLTF'] +--- + +import LowpolyPlanet from '/@/components/lowpoly-planet/TheExperience.vue' +import TheInfo from '/@/components/TheInfo.astro' + +<LowpolyPlanet client:only /> + +<TheInfo > +# { frontmatter.title } + +```vue +<script setup lang="ts"> +import { sRGBEncoding } from 'three' + +import { OrbitControls, GLTFModel } from '@tresjs/cientos' +</script> + +<template> + <Suspense> + <TresCanvas clear-color="#82DBC5" shadows alpha window-size :output-encoding="sRGBEncoding"> + <OrbitControls /> + <TresPerspectiveCamera :position="[5, 5, 5]" :fov="75" :near="0.1" :far="1000" /> + <TresScene :fog="'#82DBC5'"> + <TresAmbientLight :color="0xffffff" :intensity="0.25" /> + <TresDirectionalLight :position="[0, 8, 4]" :intensity="0.7" cast-shadow /> + <GLTFModel path="https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/aku-aku/AkuAku.gltf" draco /> + </TresScene> + </TresCanvas> + </Suspense> +</template> +``` + +</TheInfo>