From 888b9e2e8ded784f3eb64a648312c620db4ab321 Mon Sep 17 00:00:00 2001 From: Kevin Levron Date: Mon, 3 May 2021 19:21:04 +0200 Subject: [PATCH 1/2] add 'props' --- src/core/Object3D.ts | 20 +++++++++++++------- src/core/Renderer.ts | 7 +++---- src/materials/Material.ts | 3 +++ src/tools.ts | 13 +++++++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/core/Object3D.ts b/src/core/Object3D.ts index b046b42..0863c8f 100644 --- a/src/core/Object3D.ts +++ b/src/core/Object3D.ts @@ -1,6 +1,6 @@ import { Object3D, Scene } from 'three' import { ComponentPublicInstance, defineComponent, PropType, watch } from 'vue' -import { bindProp } from '../tools' +import { bindOptions, bindProp } from '../tools' import { RendererInjectionKey, RendererInterface } from './Renderer' import { SceneInjectionKey } from './Scene' @@ -54,7 +54,9 @@ export default defineComponent({ lookAt: { type: Object as PropType, default: null }, userData: { type: Object, default: () => ({}) }, visible: { type: Boolean, default: true }, - autoRemove: { type: Boolean, default: true }, + props: { type: Object, default: () => ({}) }, + disableAdd: { type: Boolean, default: false }, + disableRemove: { type: Boolean, default: false }, }, setup(): Object3DSetupInterface { // return object3DSetup() @@ -69,26 +71,30 @@ export default defineComponent({ } }, unmounted() { - if (this.autoRemove) this.removeFromParent() + if (!this.disableRemove) this.removeFromParent() }, methods: { initObject3D(o3d: Object3D) { this.o3d = o3d - this.$emit('created', o3d) - bindProp(this, 'position', o3d) bindProp(this, 'rotation', o3d) bindProp(this, 'scale', o3d) bindProp(this, 'userData', o3d.userData) bindProp(this, 'visible', o3d) + bindOptions(o3d, this.props) + + this.$emit('created', o3d) + if (this.lookAt) o3d.lookAt(this.lookAt.x ?? 0, this.lookAt.y, this.lookAt.z) watch(() => this.lookAt, (v) => { o3d.lookAt(v.x ?? 0, v.y, v.z) }, { deep: true }) this.parent = this.getParent() - if (this.addToParent()) this.$emit('ready', this) - else console.error('Missing parent (Scene, Group...)') + if (!this.disableAdd) { + if (this.addToParent()) this.$emit('ready', this) + else console.error('Missing parent (Scene, Group...)') + } }, getParent(): undefined | ComponentPublicInstance { let parent = this.$parent diff --git a/src/core/Renderer.ts b/src/core/Renderer.ts index 452be16..e4f38df 100644 --- a/src/core/Renderer.ts +++ b/src/core/Renderer.ts @@ -2,7 +2,7 @@ import { Camera, NoToneMapping, PCFShadowMap, Scene, WebGLRenderer } from 'three' import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer' import { ComponentPublicInstance, defineComponent, InjectionKey, PropType } from 'vue' -import { bindProp } from '../tools' +import { bindOptions } from '../tools' import { PointerPublicConfigInterface } from './usePointer' import useThree, { SizeInterface, ThreeConfigInterface, ThreeInterface } from './useThree' @@ -107,11 +107,10 @@ export default defineComponent({ pointer: { type: [Boolean, Object] as PropType, default: false }, resize: { type: [Boolean, String] as PropType, default: false }, shadow: Boolean, - shadowType: { type: Number, default: PCFShadowMap }, - toneMapping: { type: Number, default: NoToneMapping }, width: String, height: String, xr: Boolean, + props: { type: Object, default: () => ({}) }, onReady: Function as PropType<(r: RendererInterface) => void>, onClick: Function as PropType<(this: HTMLCanvasElement, ev: MouseEvent) => any>, }, @@ -137,7 +136,7 @@ export default defineComponent({ if (props.height) config.height = parseInt(props.height) const three = useThree(config) - bindProp(props, 'toneMapping', three.renderer) + bindOptions(three.renderer, props.props) const renderFn: {(): void} = () => {} diff --git a/src/materials/Material.ts b/src/materials/Material.ts index ecbe438..e01847a 100644 --- a/src/materials/Material.ts +++ b/src/materials/Material.ts @@ -1,6 +1,7 @@ import { ComponentPublicInstance, defineComponent, InjectionKey, PropType, watch } from 'vue' import { FrontSide, Material, NormalBlending, Texture } from 'three' import { MeshInjectionKey, MeshInterface } from '../meshes/Mesh' +import { bindOptions } from '../tools' export interface MaterialSetupInterface { mesh?: MeshInterface @@ -33,6 +34,7 @@ export default defineComponent({ side: { type: Number, default: FrontSide }, transparent: Boolean, vertexColors: Boolean, + props: { type: Object, default: () => ({}) }, }, setup(): MaterialSetupInterface { return {} @@ -50,6 +52,7 @@ export default defineComponent({ if (this.createMaterial) { this.material = this.createMaterial() + bindOptions(this.material, this.props) this.mesh.setMaterial(this.material) this.addWatchers() } diff --git a/src/tools.ts b/src/tools.ts index 8792ec5..d8f1d72 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -1,5 +1,18 @@ import { toRef, watch } from 'vue' +export function applyOptions(dst: any, options: Record): void { + if (options instanceof Object) { + Object.entries(options).forEach(([key, value]) => { + dst[key] = value + }) + } +} + +export function bindOptions(dst: any, options: Record): void { + applyOptions(dst, options) + watch(() => options, (value) => { applyOptions(dst, value) }, { deep: true }) +} + export function setFromProp(o: Record, prop: Record): void { if (prop instanceof Object) { Object.entries(prop).forEach(([key, value]) => { From 19eaa22fc53742673c4ed3b75ab98447d9051509 Mon Sep 17 00:00:00 2001 From: Kevin Levron Date: Mon, 3 May 2021 23:11:59 +0200 Subject: [PATCH 2/2] simplify textures --- src/materials/CubeTexture.ts | 6 +++--- src/materials/Texture.ts | 42 +++++++++++++++--------------------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/materials/CubeTexture.ts b/src/materials/CubeTexture.ts index cbd903b..e5ec349 100644 --- a/src/materials/CubeTexture.ts +++ b/src/materials/CubeTexture.ts @@ -1,17 +1,17 @@ import { defineComponent, PropType, watch } from 'vue' -import { CubeReflectionMapping, CubeTextureLoader, RGBFormat } from 'three' +import { CubeReflectionMapping, CubeTextureLoader } from 'three' import Texture from './Texture' export default defineComponent({ extends: Texture, props: { + name: { type: String, default: 'envMap' }, path: { type: String, required: true }, urls: { type: Array as PropType, default: () => ['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'], }, - // format: { type: Number, default: RGBFormat }, - mapping: { type: Number, default: CubeReflectionMapping }, + props: { type: Object, default: () => ({ mapping: CubeReflectionMapping }) }, }, created() { watch(() => this.path, this.refreshTexture) diff --git a/src/materials/Texture.ts b/src/materials/Texture.ts index 9f16ecc..a73a8d7 100644 --- a/src/materials/Texture.ts +++ b/src/materials/Texture.ts @@ -1,8 +1,7 @@ import { defineComponent, PropType, watch } from 'vue' -import { ClampToEdgeWrapping, LinearEncoding, LinearFilter, LinearMipmapLinearFilter, ShaderMaterial, Texture, TextureLoader, UVMapping } from 'three' -import { bindProp } from '../tools' +import { ShaderMaterial, Texture, TextureLoader } from 'three' +import { bindOptions } from '../tools' import { MaterialInjectionKey, MaterialInterface } from './Material' -import { Vector2PropInterface } from '../core/Object3D' export interface TexureInterface { material?: MaterialInterface @@ -20,16 +19,7 @@ export default defineComponent({ onLoad: Function as PropType<(t: Texture) => void>, onProgress: Function as PropType<(e: ProgressEvent) => void>, onError: Function as PropType<(e: ErrorEvent) => void>, - encoding: { type: Number, default: LinearEncoding }, - // format: { type: Number, default: RGBAFormat }, - mapping: { type: Number, default: UVMapping }, - wrapS: { type: Number, default: ClampToEdgeWrapping }, - wrapT: { type: Number, default: ClampToEdgeWrapping }, - magFilter: { type: Number, default: LinearFilter }, - minFilter: { type: Number, default: LinearMipmapLinearFilter }, - repeat: { type: Object as PropType, default: () => ({ x: 1, y: 1 }) }, - rotation: { type: Number, default: 0 }, - center: { type: Object as PropType, default: () => ({ x: 0, y: 0 }) }, + props: { type: Object, default: () => ({}) }, }, setup(): TexureInterface { return {} @@ -45,21 +35,23 @@ export default defineComponent({ methods: { createTexture() { if (!this.src) return undefined - const texture = new TextureLoader().load(this.src, this.onLoaded, this.onProgress, this.onError) - // use format ? TextureLoader will automatically set format to THREE.RGBFormat for JPG images. - const wathProps = ['encoding', 'mapping', 'wrapS', 'wrapT', 'magFilter', 'minFilter', 'repeat', 'rotation', 'center'] - wathProps.forEach(prop => { bindProp(this, prop, texture) }) - return texture + return new TextureLoader().load(this.src, this.onLoaded, this.onProgress, this.onError) + }, + initTexture() { + if (!this.texture) return + + bindOptions(this.texture, this.props) + if (!this.material) return + + this.material.setTexture(this.texture, this.name) + if (this.material.material instanceof ShaderMaterial && this.uniform) { + (this.material as any).uniforms[this.uniform] = { value: this.texture } + } }, refreshTexture() { + this.texture?.dispose() this.texture = this.createTexture() - - if (this.texture && this.material) { - this.material.setTexture(this.texture, this.name) - if (this.material.material instanceof ShaderMaterial && this.uniform) { - (this.material as any).uniforms[this.uniform] = { value: this.texture } - } - } + this.initTexture() }, onLoaded(t: Texture) { this.onLoad?.(t)