Skip to content
This repository was archived by the owner on Feb 1, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
3 changes: 1 addition & 2 deletions docs/guide/staging/smoke.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ Notice that you can pass a texture in combination with props, to personalize yo
<table><thead><tr class="row-header"><th class="col-name">Name</th><th class="col-type">Type</th><th class="col-description">Description</th><th class="col-default">Default</th><th class="col-required">Required</th></tr></thead><tbody><tr class="row-color"><td class="col-name"><strong><nobr>color</nobr></strong></td><td class="col-type"><code>TresColor</code></td><td class="col-description">The color of the smoke.<br>
</td><td class="col-default"><code>'#ffffff'</code></td><td class="col-required">No</td></tr><tr class="row-opacity"><td class="col-name"><strong><nobr>opacity</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The strength of the opacity.<br>
</td><td class="col-default"><code>0.5</code></td><td class="col-required">No</td></tr><tr class="row-speed"><td class="col-name"><strong><nobr>speed</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The rotation speed of the smoke.<br>
</td><td class="col-default"><code>0.4</code></td><td class="col-required">No</td></tr><tr class="row-width"><td class="col-name"><strong><nobr>width</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The base width.<br>
</td><td class="col-default"><code>10</code></td><td class="col-required">No</td></tr><tr class="row-depth"><td class="col-name"><strong><nobr>depth</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The base depth.<br>
</td><td class="col-default"><code>0.4</code></td><td class="col-required">No</td></tr><tr class="row-depth"><td class="col-name"><strong><nobr>depth</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The base depth.<br>
</td><td class="col-default"><code>1.5</code></td><td class="col-required">No</td></tr><tr class="row-segments"><td class="col-name"><strong><nobr>segments</nobr></strong></td><td class="col-type"><code>number</code></td><td class="col-description">The number of smoke to render.<br>
</td><td class="col-default"><code>20</code></td><td class="col-required">No</td></tr><tr class="row-texture"><td class="col-name"><strong><nobr>texture</nobr></strong></td><td class="col-type"><code>string</code></td><td class="col-description">The texture of the smoke.<br>
</td><td class="col-default">default component texture</td><td class="col-required">No</td></tr><tr class="row-depth-test"><td class="col-name"><strong><nobr>depthTest</nobr></strong></td><td class="col-type"><code>boolean</code></td><td class="col-description">The depthTest.<br>
Expand Down
84 changes: 53 additions & 31 deletions playground/vue/src/pages/staging/SmokeDemo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@
import { Box, OrbitControls, Smoke } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { NoToneMapping, SRGBColorSpace } from 'three'
import { TresLeches, useControls } from '@tresjs/leches'
import '@tresjs/leches/styles'

const { segments, opacity, speed, depth, color, depthTest } = useControls({
segments: {
label: 'Segments',
value: 5,
min: 1,
max: 20,
step: 1,
},
opacity: {
label: 'Opacity',
value: 0.5,
min: 0,
max: 1,
step: 0.1,
},
speed: {
label: 'Speed',
value: 0.4,
min: 0,
max: 1,
step: 0.1,
},
depth: {
label: 'Depth',
value: 0.3,
min: 0,
max: 1,
step: 0.1,
},
color: {
type: 'color',
label: 'Color',
value: '#f7f7f7',
},
depthTest: {
type: 'boolean',
label: 'Depth Test',
value: false,
},
})

const gl = {
clearColor: '#333',
Expand All @@ -12,46 +55,25 @@ const gl = {
</script>

<template>
<TresCanvas
v-bind="gl"
>
<TresLeches />
<TresCanvas v-bind="gl">
<TresPerspectiveCamera :position="[0, 2, 5]" />
<Suspense>
<Smoke
:position="[-4, -2, 0]"
:segments="8"
/>
</Suspense>
<Suspense>
<Smoke
:position="[-4, 2, 0]"
:segments="8"
/>
</Suspense>
<Suspense>
<Smoke :segments="8" />
</Suspense>
<Suspense>
<Smoke
:position="[4, -2, 0]"
:segments="8"
/>
</Suspense>
<Suspense>
<Smoke
:position="[4, 2, 0]"
:segments="8"
:segments="segments.value"
:opacity="opacity.value"
:speed="speed.value"
:depth="depth.value"
:color="color.value"
:depth-test="depthTest.value"
/>
</Suspense>
<Box :args="[2, 2]">
<TresMeshToonMaterial color="#82DBC5" />
<TresMeshToonMaterial color="#82DBC5" wireframe />
</Box>
<TresGridHelper :args="[10, 10]" />
<TresAmbientLight :intensity="1" />
<TresDirectionalLight
:intensity="1"
:position="[2, 2, 2]"
/>
<TresDirectionalLight :intensity="1" :position="[2, 2, 2]" />
<OrbitControls />
</TresCanvas>
</template>
63 changes: 23 additions & 40 deletions src/core/staging/Smoke.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ export interface SmokeProps {
* @see https://threejs.org/docs/#api/en/materials/MeshStandardMaterial
*/
speed?: number
/**
* The base width.
* @default 4
* @type {number}
* @memberof SmokeProps
* @see https://threejs.org/docs/#api/en/materials/MeshBasicMaterial
*/
width?: number
/**
* The base depth.
* @default 10
Expand Down Expand Up @@ -75,15 +67,17 @@ export interface SmokeProps {
const props = withDefaults(defineProps<SmokeProps>(), {
opacity: 0.5,
speed: 0.4,
width: 10,
depth: 1.5,
segments: 20,
texture: 'https://raw.githubusercontent.com/Tresjs/assets/main/textures/clouds/defaultCloud.png',
color: '#ffffff',
depthTest: true,
depth: 0.3,
segments: 10,
texture:
'https://raw.githubusercontent.com/Tresjs/assets/main/textures/clouds/defaultCloud.png',
color: '#f7f7f7',
depthTest: false,
})

const { width, depth, segments, texture, color, depthTest, opacity, speed } = toRefs(props)
const { depth, segments, texture, color, depthTest, opacity, speed } = toRefs(
props,
)

const smokeRef = shallowRef()
const groupRef = shallowRef()
Expand All @@ -92,15 +86,13 @@ defineExpose({
instance: smokeRef,
})

const smoke = [...[segments]].map((_, index) => ({
x: width.value / 2 - Math.random() * width.value,
y: width.value / 2 - Math.random() * width.value,
scale: 0.4 + Math.sin(((index + 1) / segments.value) * Math.PI) * ((0.2 + Math.random()) * 10),
density: Math.max(0.2, Math.random()),
rotation: Math.max(0.002, 0.005 * Math.random()) * speed.value,
}))

const calculateOpacity = (scale: number, density: number): number => (scale / 6) * density * opacity.value
const smoke = computed(() =>
Array.from({ length: segments.value }, (_, index) => ({
x: (Math.random() - 0.5) * 0.5,
y: (Math.random() - 0.5) * 0.1,
scale: Math.sin((index + 1) / segments.value),
})),
)

const { state: map } = useTexture(texture.value)

Expand All @@ -111,8 +103,8 @@ const { onBeforeRender } = useLoop()

onBeforeRender(() => {
if (smokeRef.value && camera.activeCamera.value && groupRef.value) {
groupRef.value?.children.forEach((child: Object3D, index: number) => {
child.rotation.z += smoke[index].rotation
groupRef.value?.children.forEach((child: Object3D) => {
child.rotation.z += Math.max(0.002, 0.005 * Math.random()) * speed.value
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

question: Is this a known math formula or just to introduce variation/randomness? Do you think it could be interesting for users to be able to tweak the hardcoded values?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Just introduce randomness/variation
I don't know, we can for instance make the "speed" prop as the whole math formula. But currently, you can control the randomness with the speed prop.

What is your advice? If you ask me I would say is fine (don't put all the weight on the user to create their random, just a simple prop, in my experience most user use the random or don't, set as 0)

})
smokeRef.value.lookAt(camera.activeCamera.value?.position)
// TODO: comment this until invalidate is back in the loop callback on v5
Expand All @@ -122,31 +114,22 @@ onBeforeRender(() => {
</script>

<template>
<TresGroup
ref="smokeRef"
v-bind="$attrs"
>
<TresGroup
ref="groupRef"
:position="[0, 0, (segments / 2) * depth]"
>
<TresGroup ref="smokeRef">
<TresGroup ref="groupRef" :position="[0, 0, (segments / 2) * depth]">
<TresMesh
v-for="({ scale, x, y, density }, index) in smoke"
v-for="({ x, y }, index) in smoke"
:key="`${index}`"
:position="[x, y, -index * depth]"
>
<TresPlaneGeometry
:scale="[scale, scale, scale]"
:rotation="[0, 0, 0]"
/>
<TresPlaneGeometry />
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

question: What's the reasoning behind removing with and scale?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The big problem with the width and the scale was that, the randomness was wrong too large, this creates unstable component difficult to use and understand. I think with the previous comment (adding props to controls it) we solve it.

The new implementation, treat it different but without actually removing it

<TresMeshStandardMaterial
:map="map"
:depth-test="depthTest"
:color-space="colorSpace"
:color="color"
:depth-write="false"
transparent
:opacity="calculateOpacity(scale, density)"
:opacity="opacity"
/>
</TresMesh>
</TresGroup>
Expand Down
Loading