Peter 7 månader sedan
förälder
incheckning
d9281b670c

+ 1 - 1
playground/vue/src/pages/advanced/WebGPU.vue

@@ -4,7 +4,7 @@ import { WebGPURenderer } from 'three/webgpu'
 </script>
 
 <template>
-  <TresCanvas :renderer="async (context) => await new WebGPURenderer(context.props)">
+  <TresCanvas :renderer="async (ctx) => { const r = new WebGPURenderer({ canvas: ctx.canvas.value }); r.setSize(200, 200); await r.init(); return r }">
     <TresPerspectiveCamera
       :position="[3, 3, 3]"
       :look-at="[0, 0, 0]"

+ 5 - 1
playground/vue/src/pages/basic/OnCallbacks.vue

@@ -36,7 +36,11 @@ const materialOnBeforeCompile = () => { materialNumOnBeforeCompiles.value++ }
       <li># onBeforeCompile calls: {{ materialNumOnBeforeCompiles }}</li>
     </ul>
   </div>
-  <TresCanvas>
+
+  <TresCanvas
+    :output-color-space="undefined"
+    @ready="({ renderer }) => console.log(renderer.value.outputColorSpace)"
+  >
     <TresMesh
       :position="[1, 0, 0]"
       :scale="0.5"

+ 6 - 4
playground/vue/src/pages/events/TargetEnabled.vue

@@ -118,12 +118,14 @@ function onChangeEventsEnabled(b: boolean) {
   z-index: 1;
 }
 .checkered.red {
-  background-image: linear-gradient(45deg, #000 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #000 75%),
-    linear-gradient(45deg, transparent 75%, #000 75%), linear-gradient(45deg, #000 25%, #f00 25%);
+  background-image: linear-gradient(45deg, #000 25%, transparent 25%),
+    linear-gradient(45deg, transparent 75%, #000 75%), linear-gradient(45deg, transparent 75%, #000 75%),
+    linear-gradient(45deg, #000 25%, #f00 25%);
 }
 .checkered.blue {
-  background-image: linear-gradient(45deg, #00f 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #00f 75%),
-    linear-gradient(45deg, transparent 75%, #00f 75%), linear-gradient(45deg, #00f 25%, #000 25%);
+  background-image: linear-gradient(45deg, #00f 25%, transparent 25%),
+    linear-gradient(45deg, transparent 75%, #00f 75%), linear-gradient(45deg, transparent 75%, #00f 75%),
+    linear-gradient(45deg, #00f 25%, #000 25%);
 }
 .checkered {
   opacity: 0.25;

+ 5 - 5
src/components/TresCanvas.vue

@@ -27,6 +27,7 @@ import {
   watchEffect,
 } from 'vue'
 import pkg from '../../package.json'
+import * as is from '../utils/is'
 import {
   type TresContext,
   useTresContextProvider,
@@ -155,9 +156,10 @@ const mountCustomRenderer = (context: TresContext, empty = false) => {
 
 const dispose = (context: TresContext, force = false) => {
   disposeObject3D(context.scene.value as unknown as TresObject)
+  const r = context.renderer.value
+  'dispose' in r && is.fun(r.dispose) && r.dispose()
   if (force) {
-    context.renderer.value.dispose();
-    (context.renderer.value as Record<string, any>).forceContextLoss?.()
+    'forceContextLoss' in r && is.fun(r.forceContextLoss) && r.forceContextLoss()
   }
   (scene.value as TresScene).__tres = {
     root: context,
@@ -179,11 +181,9 @@ const unmountCanvas = () => {
 }
 
 onMounted(async () => {
-  const existingCanvas = canvas as Ref<HTMLCanvasElement>
-
   context.value = await useTresContextProvider({
     scene: scene.value as TresScene,
-    canvas: existingCanvas,
+    canvas: canvas as Ref<HTMLCanvasElement>,
     windowSize: props.windowSize ?? false,
     props,
     emit,

+ 0 - 1
src/composables/useRenderer/index.ts

@@ -24,7 +24,6 @@ import { rendererPresets } from './const'
 type TransformToMaybeRefOrGetter<T> = {
   [K in keyof T]: MaybeRefOrGetter<T[K]> | MaybeRefOrGetter<T[K]>;
 }
-
 export interface UseRendererOptions extends TransformToMaybeRefOrGetter<WebGLRendererParameters> {
   /**
    * Enable shadows in the Renderer

+ 6 - 5
src/composables/useTresContextProvider/index.ts

@@ -1,9 +1,9 @@
 import type { Camera } from 'three'
-import type { ComputedRef, DeepReadonly, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
+import type { ComputedRef, DeepReadonly, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
 import type { RendererLoop } from '../../core/loop'
 import type { EmitEventFn, Renderer, TresControl, TresScene } from '../../types'
 import { Raycaster } from 'three'
-import { computed, inject, onUnmounted, provide, readonly, ref, shallowRef, toValue } from 'vue'
+import { computed, inject, onUnmounted, provide, readonly, ref, shallowRef } from 'vue'
 import { extend } from '../../core/catalogue'
 import { createRenderLoop } from '../../core/loop'
 import { type Events, useEventsOptions as withEventsProps } from '../../utils/createEvents'
@@ -47,6 +47,7 @@ export interface PerformanceState {
 }
 
 export interface TresContext {
+  canvas: ShallowRef<HTMLCanvasElement>
   events: Events
   scene: ShallowRef<TresScene>
   sizes: SizesType
@@ -87,11 +88,10 @@ export async function useTresContextProvider({
   emit,
 }: {
   scene: TresScene
-  canvas: MaybeRef<HTMLCanvasElement>
+  canvas: ShallowRef<HTMLCanvasElement>
   windowSize: MaybeRefOrGetter<boolean>
   props: TresCanvasProps
   emit: EmitEventFn
-
 }): Promise<TresContext> {
   const localScene = shallowRef<TresScene>(scene)
   const sizes = useSizes(windowSize, canvas)
@@ -158,11 +158,12 @@ export async function useTresContextProvider({
     loop: createRenderLoop(),
     props,
     emit,
+    canvas,
   }
 
   provide('useTres', ctx)
 
-  const r = (await withRendererProps(ctx as TresContext, { canvas: toValue(canvas) }))
+  const r = (await withRendererProps(ctx as TresContext))
   ctx.renderer = r.renderer
   ctx.events = withEventsProps(ctx as TresContext).events
 

+ 1 - 1
src/types/index.ts

@@ -26,7 +26,7 @@ export interface TresCatalogue {
 export type EmitEventName = 'render' | 'ready'
 export type EmitEventFn = (event: EmitEventName, ...args: any[]) => void
 export type TresCamera = THREE.OrthographicCamera | THREE.PerspectiveCamera
-export interface Renderer { render: (scene: THREE.Scene, camera: THREE.Camera) => any }
+export type Renderer = { render: (scene: THREE.Scene, camera: THREE.Camera) => any } & Record<string | number | symbol, any>
 
 /**
  * Represents the properties of an instance.

+ 1 - 1
src/utils/createEvents/eventsRaycast.test.ts

@@ -2043,7 +2043,7 @@ function mockTresUsingEventsProps(props = eventsRaycast) {
       camera: { value: new THREE.PerspectiveCamera() },
     } as unknown as TresContext
 
-    context.events = createEvents(props, context, () => {})
+    context.events = createEvents(props, context)
     context.events.config.raycaster.intersectObjects = (pool: any[]) => {
       // NOTE:
       // We are not testing raycast "hits", but we do want to test `pool`,

+ 8 - 3
src/utils/createRenderer/createRenderer.ts

@@ -1,18 +1,23 @@
 import type { TresContext } from 'src/composables'
 import type { Renderer } from 'src/types'
 import { ACESFilmicToneMapping, WebGLRenderer } from 'three'
+import * as is from '../is'
 
-export async function createRenderer(ctx: TresContext, rendererParameters: Record<string, unknown> = {}) {
+export async function createRenderer(ctx: TresContext) {
   if (ctx?.props?.renderer) {
     const fnOrRenderer = ctx.props.renderer
     if (typeof fnOrRenderer === 'function') {
-      return await fnOrRenderer(ctx, rendererParameters)
+      return await fnOrRenderer(ctx)
     }
     else {
       return fnOrRenderer
     }
   }
-  const renderer = new WebGLRenderer({ ...rendererParameters })
+  const rendererConstructorArgs = {
+    ...(is.obj(ctx.props?.renderer) ? ctx.props.renderer : {}),
+    canvas: ctx.canvas.value,
+  }
+  const renderer = new WebGLRenderer(rendererConstructorArgs)
   renderer.toneMapping = ACESFilmicToneMapping
   return renderer as Renderer
 }

+ 4 - 4
src/utils/createRenderer/withRendererProps.ts

@@ -7,16 +7,16 @@ import * as is from '../is'
 import { normalizeColor } from '../normalize'
 import type { Renderer } from '../../types'
 
-export async function withRendererProps(context: TresContext, rendererParameters: Record<string, unknown> = {}): Promise<{ renderer: ShallowRef<Renderer>, stop: () => void }> {
+export async function withRendererProps(context: TresContext): Promise<{ renderer: ShallowRef<Renderer>, stop: () => void }> {
   const renderer = shallowRef({ render: () => {}, dispose: () => {} } as Renderer)
   const defaults = shallowRef({} as Record<string, any>)
 
   const stopRenderer = watch(() => context.props.renderer, () => {
-    renderer.value.dispose?.()
-    renderer.value.forceContextLoss?.()
+    'dispose' in renderer.value && is.fun(renderer.value.dispose) && renderer.value.dispose()
+    'forceContextLoss' in renderer.value && is.fun(renderer.value.forceContextLoss) && renderer.value.forceContextLoss()
     renderer.value = { render: () => {}, dispose: () => {} }
 
-    createRenderer(context, rendererParameters).then((r) => {
+    createRenderer(context).then((r) => {
       defaults.value = Object.entries(r).filter(([_, v]) => !is.obj(v) && !is.fun(v) && !is.arr(v)).reduce((defaults, [k, v]) => { defaults[k] = v; return defaults }, {} as Record<string, any>)
       if (r.shadowMap) {
         defaults.value.shadowMap = Object.entries(r.shadowMap).filter(([_, v]) => !is.obj(v) && !is.fun(v) && !is.arr(v)).reduce((shadowMap, [k, v]) => { shadowMap[k] = v; return shadowMap }, {} as Record<string, any>)