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 +