diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 019c6196..a997c9ec 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -38,6 +38,8 @@ export default defineConfig({
{ text: 'MouseParallax', link: '/guide/abstractions/mouse-parallax' },
{ text: 'Lensflare', link: '/guide/abstractions/lensflare' },
{ text: 'GlobalAudio', link: '/guide/abstractions/global-audio' },
+ { text: 'Fbo', link: '/guide/abstractions/fbo' },
+ { text: 'useFBO', link: '/guide/abstractions/use-fbo' },
],
},
{
diff --git a/docs/.vitepress/theme/components/FboCube.vue b/docs/.vitepress/theme/components/FboCube.vue
new file mode 100644
index 00000000..5b934e6f
--- /dev/null
+++ b/docs/.vitepress/theme/components/FboCube.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/FboDemo.vue b/docs/.vitepress/theme/components/FboDemo.vue
new file mode 100644
index 00000000..6d78f3d5
--- /dev/null
+++ b/docs/.vitepress/theme/components/FboDemo.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/UseFBODemo.vue b/docs/.vitepress/theme/components/UseFBODemo.vue
new file mode 100644
index 00000000..f6dd3f0c
--- /dev/null
+++ b/docs/.vitepress/theme/components/UseFBODemo.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/components.d.ts b/docs/components.d.ts
deleted file mode 100644
index a78cdc64..00000000
--- a/docs/components.d.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-/* eslint-disable */
-/* prettier-ignore */
-// @ts-nocheck
-// Generated by unplugin-vue-components
-// Read more: https://github.com/vuejs/core/pull/3399
-export {}
-
-declare module 'vue' {
- export interface GlobalComponents {
- BackdropDemo: typeof import('./.vitepress/theme/components/BackdropDemo.vue')['default']
- CameraControlsDemo: typeof import('./.vitepress/theme/components/CameraControlsDemo.vue')['default']
- CatmullRomCurve3Demo: typeof import('./.vitepress/theme/components/CatmullRomCurve3Demo.vue')['default']
- ContactShadowDemo: typeof import('./.vitepress/theme/components/ContactShadowDemo.vue')['default']
- DocsDemo: typeof import('./.vitepress/theme/components/DocsDemo.vue')['default']
- FBXModelDemo: typeof import('./.vitepress/theme/components/FBXModelDemo.vue')['default']
- Feather: typeof import('./.vitepress/theme/components/Feather.vue')['default']
- GlassMaterialDemo: typeof import('./.vitepress/theme/components/GlassMaterialDemo.vue')['default']
- GLTFModelDemo: typeof import('./.vitepress/theme/components/GLTFModelDemo.vue')['default']
- HtmlDemo: typeof import('./.vitepress/theme/components/HtmlDemo.vue')['default']
- HtmlLaptopDemo: typeof import('./.vitepress/theme/components/HtmlLaptopDemo.vue')['default']
- HtmlOccludeDemo: typeof import('./.vitepress/theme/components/HtmlOccludeDemo.vue')['default']
- LeviosoDemo: typeof import('./.vitepress/theme/components/LeviosoDemo.vue')['default']
- Line2Demo: typeof import('./.vitepress/theme/components/Line2Demo.vue')['default']
- LoveVueThreeJS: typeof import('./.vitepress/theme/components/LoveVueThreeJS.vue')['default']
- MapControlsDemo: typeof import('./.vitepress/theme/components/MapControlsDemo.vue')['default']
- MouseParallaxDemo: typeof import('./.vitepress/theme/components/MouseParallaxDemo.vue')['default']
- OrbitControlsDemo: typeof import('./.vitepress/theme/components/OrbitControlsDemo.vue')['default']
- PrecipitationBeamDemo: typeof import('./.vitepress/theme/components/PrecipitationBeamDemo.vue')['default']
- PrecipitationDemo: typeof import('./.vitepress/theme/components/PrecipitationDemo.vue')['default']
- PrecipitationRainDemo: typeof import('./.vitepress/theme/components/PrecipitationRainDemo.vue')['default']
- PrecipitationStormDemo: typeof import('./.vitepress/theme/components/PrecipitationStormDemo.vue')['default']
- RouterLink: typeof import('vue-router')['RouterLink']
- RouterView: typeof import('vue-router')['RouterView']
- ScrollControlsDemo: typeof import('./.vitepress/theme/components/ScrollControlsDemo.vue')['default']
- ScrollControlsHorizontalDemo: typeof import('./.vitepress/theme/components/ScrollControlsHorizontalDemo.vue')['default']
- ScrollControlsPagesDemo: typeof import('./.vitepress/theme/components/ScrollControlsPagesDemo.vue')['default']
- ScrollControlsProgressCameraDemo: typeof import('./.vitepress/theme/components/ScrollControlsProgressCameraDemo.vue')['default']
- ScrollControlsProgressDemo: typeof import('./.vitepress/theme/components/ScrollControlsProgressDemo.vue')['default']
- ScrollControlsSlotsDemo: typeof import('./.vitepress/theme/components/ScrollControlsSlotsDemo.vue')['default']
- SkyDemo: typeof import('./.vitepress/theme/components/SkyDemo.vue')['default']
- SmokeDemo: typeof import('./.vitepress/theme/components/SmokeDemo.vue')['default']
- StarsDemo: typeof import('./.vitepress/theme/components/StarsDemo.vue')['default']
- SVGDemo: typeof import('./.vitepress/theme/components/SVGDemo.vue')['default']
- Text3Demo: typeof import('./.vitepress/theme/components/Text3Demo.vue')['default']
- TransformControlsDemo: typeof import('./.vitepress/theme/components/TransformControlsDemo.vue')['default']
- VideoTextureDemo: typeof import('./.vitepress/theme/components/VideoTextureDemo.vue')['default']
- WobbleMaterialDemo: typeof import('./.vitepress/theme/components/WobbleMaterialDemo.vue')['default']
- }
-}
diff --git a/docs/guide/abstractions/fbo.md b/docs/guide/abstractions/fbo.md
new file mode 100644
index 00000000..1c4488e1
--- /dev/null
+++ b/docs/guide/abstractions/fbo.md
@@ -0,0 +1,22 @@
+# Fbo
+
+An FBO (or Frame Buffer Object) is generally used to render to a texture. This is useful for post-processing effects like blurring, or for rendering to a texture that will be used as a texture in a later draw call.
+
+Cientos provides an `` component make it easy to use FBOs in your application.
+
+
+
+
+
+## Usage
+
+<<< @/.vitepress/theme/components/FboDemo.vue{3,15,48,49,50,51,58}
+
+## Props
+
+| Prop | Description | Default |
+| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
+| **`width`** | `number` - The width of the FBO. | Width of the canvas |
+| **`height`** | `number` - the height of the FBO | Height of the canvas |
+| **`depth`** | `boolean` - Whether or not the FBO should render the depth to a [`depthTexture`](https://threejs.org/docs/?q=webglre#api/en/renderers/WebGLRenderTarget.depthTexture). | `false` |
+| **`settings`** | `WebGLRenderTargetOptions` - Every other configuration property for the [`WebGLRenderTarget` class](https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget) | `{}` |
diff --git a/docs/guide/abstractions/use-fbo.md b/docs/guide/abstractions/use-fbo.md
new file mode 100644
index 00000000..e3c85776
--- /dev/null
+++ b/docs/guide/abstractions/use-fbo.md
@@ -0,0 +1,32 @@
+# useFBO
+
+An FBO (or Frame Buffer Object) is generally used to render to a texture. This is useful for post-processing effects like blurring, or for rendering to a texture that will be used as a texture in a later draw call.
+
+Cientos provides a `useFBO` composable to make it easy to use FBOs in your application.
+
+::: warning
+The `useFBO` composable must be used inside of a child component since it needs the context of TresCanvas.
+:::
+
+
+
+
+
+## Usage
+
+`FboCube.vue`
+
+<<< @/.vitepress/theme/components/FboCube.vue{2,4,5,6,7,8,9,10,11,20}
+
+`Experience.vue`
+
+<<< @/.vitepress/theme/components/UseFBODemo.vue{40}
+
+## Props
+
+| Prop | Description | Default |
+| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
+| **`width`** | `number` - The width of the FBO. | Width of the canvas |
+| **`height`** | `number` - the height of the FBO | Height of the canvas |
+| **`depth`** | `boolean` - Whether or not the FBO should render the depth to a [`depthTexture`](https://threejs.org/docs/?q=webglre#api/en/renderers/WebGLRenderTarget.depthTexture). | `false` |
+| **`settings`** | `WebGLRenderTargetOptions` - Every other configuration property for the [`WebGLRenderTarget` class](https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget) | `{}` |
diff --git a/playground/components.d.ts b/playground/components.d.ts
index 57605e84..27b5c197 100644
--- a/playground/components.d.ts
+++ b/playground/components.d.ts
@@ -9,6 +9,7 @@ declare module 'vue' {
export interface GlobalComponents {
AkuAku: typeof import('./src/components/AkuAku.vue')['default']
DirectivesDemo: typeof import('./src/components/DirectivesDemo.vue')['default']
+ FboCube: typeof import('./src/components/FboCube.vue')['default']
Gltf: typeof import('./src/components/gltf/index.vue')['default']
ModelsDemo: typeof import('./src/components/ModelsDemo.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
diff --git a/playground/src/components/FboCube.vue b/playground/src/components/FboCube.vue
new file mode 100644
index 00000000..dc456c0d
--- /dev/null
+++ b/playground/src/components/FboCube.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
diff --git a/playground/src/pages/abstractions/FBODemo.vue b/playground/src/pages/abstractions/FBODemo.vue
new file mode 100644
index 00000000..dcdb43c3
--- /dev/null
+++ b/playground/src/pages/abstractions/FBODemo.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playground/src/pages/abstractions/useFBODemo.vue b/playground/src/pages/abstractions/useFBODemo.vue
new file mode 100644
index 00000000..62c52387
--- /dev/null
+++ b/playground/src/pages/abstractions/useFBODemo.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/playground/src/router/routes/abstractions.ts b/playground/src/router/routes/abstractions.ts
index 5070ba6c..5783ab10 100644
--- a/playground/src/router/routes/abstractions.ts
+++ b/playground/src/router/routes/abstractions.ts
@@ -24,4 +24,14 @@ export const abstractionsRoutes = [
name: 'GlobalAudio',
component: () => import('../../pages/abstractions/GlobalAudioDemo.vue'),
},
-]
\ No newline at end of file
+ {
+ path: '/abstractions/fbo',
+ name: 'Fbo',
+ component: () => import('../../pages/abstractions/FBODemo.vue'),
+ },
+ {
+ path: '/abstractions/use-fbo',
+ name: 'useFbo',
+ component: () => import('../../pages/abstractions/useFBODemo.vue'),
+ },
+]
diff --git a/src/core/abstractions/index.ts b/src/core/abstractions/index.ts
index bcf0a818..a00d958b 100644
--- a/src/core/abstractions/index.ts
+++ b/src/core/abstractions/index.ts
@@ -4,7 +4,9 @@ import Levioso from './Levioso.vue'
import MouseParallax from './MouseParallax.vue'
import { GlobalAudio } from './GlobalAudio'
import Lensflare from './Lensflare/component.vue'
+import Fbo from './useFBO/component.vue'
+export * from './useFBO/'
export * from '../staging/useEnvironment'
export {
Text3D,
@@ -13,4 +15,5 @@ export {
Levioso,
Lensflare,
GlobalAudio,
+ Fbo,
}
diff --git a/src/core/abstractions/useFBO/component.vue b/src/core/abstractions/useFBO/component.vue
new file mode 100644
index 00000000..75cd6d22
--- /dev/null
+++ b/src/core/abstractions/useFBO/component.vue
@@ -0,0 +1,15 @@
+
diff --git a/src/core/abstractions/useFBO/index.ts b/src/core/abstractions/useFBO/index.ts
new file mode 100644
index 00000000..ba123ca0
--- /dev/null
+++ b/src/core/abstractions/useFBO/index.ts
@@ -0,0 +1,84 @@
+import { useRenderLoop, useTresContext } from '@tresjs/core'
+import type { Camera, WebGLRenderTargetOptions } from 'three'
+import { DepthTexture, FloatType, HalfFloatType, LinearFilter, WebGLRenderTarget } from 'three'
+import type { Ref } from 'vue'
+import { isReactive, onBeforeUnmount, reactive, ref, toRefs, watchEffect } from 'vue'
+
+export interface FboOptions {
+ /*
+ * The width of the frame buffer object. Defaults to the width of the canvas.
+ *
+ * @type {number}
+ * @memberof FboProps
+ */
+ width?: number
+
+ /*
+ * The height of the frame buffer object. Defaults to the height of the canvas.
+ *
+ * @type {number}
+ * @memberof FboProps
+ */
+ height?: number
+
+ /*
+ * If set, the scene depth will be rendered into buffer.depthTexture.
+ *
+ * @default false
+ * @type {boolean}
+ * @memberof FboProps
+ */
+ depth?: boolean
+
+ /*
+ * Additional settings for the render target.
+ * See https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget for more information.
+ *
+ * @default {}
+ * @type {WebGLRenderTargetOptions}
+ * @memberof FboProps
+ */
+ settings?: WebGLRenderTargetOptions
+}
+
+export function useFBO(options: FboOptions) {
+ const target: Ref = ref(null)
+
+ const { height, width, settings, depth } = isReactive(options) ? toRefs(options) : toRefs(reactive(options))
+
+ const { onLoop } = useRenderLoop()
+ const { camera, renderer, scene, sizes } = useTresContext()
+
+ watchEffect(() => {
+ target.value?.dispose()
+
+ target.value = new WebGLRenderTarget(width?.value || sizes.width.value, height?.value || sizes.height.value, {
+ minFilter: LinearFilter,
+ magFilter: LinearFilter,
+ type: HalfFloatType,
+ ...settings?.value,
+ })
+
+ if (depth?.value) {
+ target.value.depthTexture = new DepthTexture(
+ width?.value || sizes.width.value,
+ height?.value || sizes.height.value,
+ FloatType,
+ )
+ }
+ })
+
+ onLoop(() => {
+ renderer.value.setRenderTarget(target.value)
+ renderer.value.clear()
+ renderer.value.render(scene.value, camera.value as Camera)
+
+ renderer.value.setRenderTarget(null)
+ })
+
+ onBeforeUnmount(() => {
+ target.value?.dispose()
+ })
+
+ return target
+}
diff --git a/src/core/staging/Sky.vue b/src/core/staging/Sky.vue
index a9713d15..209212e3 100644
--- a/src/core/staging/Sky.vue
+++ b/src/core/staging/Sky.vue
@@ -25,7 +25,9 @@ const props = withDefaults(defineProps(), {
})
const skyImpl = new SkyImpl()
-const sunPosition = computed(() => getSunPosition(props.azimuth, props.elevation))
+const sunPosition = computed(() =>
+ getSunPosition(props.azimuth, props.elevation),
+)
function getSunPosition(azimuth: number, elevation: number) {
const phi = MathUtils.degToRad(90 - elevation)
@@ -44,4 +46,4 @@ function getSunPosition(azimuth: number, elevation: number) {
:material-uniforms-sunPosition-value="sunPosition"
:scale="props.distance"
/>
-
\ No newline at end of file
+