| @@ -117,7 +117,7 @@ | |||
| "@types/wicg-file-system-access": "^2020.9.5", | |||
| "stats.js": "^0.17.0", | |||
| "ts-browser-helpers": "^0.16.0", | |||
| "uiconfig.js": "^0.1.1" | |||
| "uiconfig.js": "0.1.1" | |||
| }, | |||
| "//": { | |||
| "dependencies": { | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-blend-importer", | |||
| "version": "0.0.2", | |||
| "version": "0.0.3", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-blend-importer", | |||
| "version": "0.0.2", | |||
| "version": "0.0.3", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-blueprintjs", | |||
| "version": "0.2.0", | |||
| "version": "0.2.1", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-blueprintjs", | |||
| "version": "0.2.0", | |||
| "version": "0.2.1", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-configurator", | |||
| "version": "0.1.1", | |||
| "version": "0.1.2", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-configurator", | |||
| "version": "0.1.1", | |||
| "version": "0.1.2", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/", | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugins-extra-importers", | |||
| "version": "0.2.0", | |||
| "version": "0.2.1", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugins-extra-importers", | |||
| "version": "0.2.0", | |||
| "version": "0.2.1", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-gaussian-splatting", | |||
| "version": "0.2.1", | |||
| "version": "0.2.2", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-gaussian-splatting", | |||
| "version": "0.2.1", | |||
| "version": "0.2.2", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-geometry-generator", | |||
| "version": "0.3.0", | |||
| "version": "0.3.1", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-geometry-generator", | |||
| "version": "0.3.0", | |||
| "version": "0.3.1", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-gltf-transform", | |||
| "version": "0.1.0", | |||
| "version": "0.1.1", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-gltf-transform", | |||
| "version": "0.1.0", | |||
| "version": "0.1.1", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-network", | |||
| "version": "0.1.0", | |||
| "version": "0.1.1", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-network", | |||
| "version": "0.1.0", | |||
| "version": "0.1.1", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "aws4fetch": "^1.0.18", | |||
| @@ -1,12 +1,12 @@ | |||
| { | |||
| "name": "@threepipe/plugin-svg-renderer", | |||
| "version": "0.2.1", | |||
| "version": "0.2.2", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-svg-renderer", | |||
| "version": "0.2.1", | |||
| "version": "0.2.2", | |||
| "license": "GPLV3", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| @@ -1,50 +1,45 @@ | |||
| { | |||
| "name": "@threepipe/plugin-tweakpane", | |||
| "version": "0.5.0", | |||
| "version": "0.4.2", | |||
| "lockfileVersion": 3, | |||
| "requires": true, | |||
| "packages": { | |||
| "": { | |||
| "name": "@threepipe/plugin-tweakpane", | |||
| "version": "0.5.0", | |||
| "version": "0.4.2", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "threepipe": "file:./../../src/" | |||
| }, | |||
| "devDependencies": { | |||
| "tweakpane-image-plugin": "https://github.com/repalash/tweakpane-image-plugin/releases/download/v1.1.404/package.tgz", | |||
| "uiconfig-tweakpane": "^0.0.10" | |||
| } | |||
| }, | |||
| "../../../uiconfig-react/packages/uiconfig-tweakpane": { | |||
| "version": "0.0.0", | |||
| "extraneous": true, | |||
| "devDependencies": { | |||
| "typescript": "~5.6.2", | |||
| "vite": "^6.0.3" | |||
| "uiconfig-tweakpane": "^0.0.8" | |||
| } | |||
| }, | |||
| "../../src": {}, | |||
| "node_modules/@tweakpane/core": { | |||
| "version": "1.1.8", | |||
| "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-1.1.8.tgz", | |||
| "integrity": "sha512-psvBf6Cbm3YSZOTmDFWkcGzHYMnw7gVZM3jw+TfbzErIC+sMXPQb85h4ayW04w2u7AGg8jD0gHXSCg5wd+rafg==", | |||
| "dev": true | |||
| }, | |||
| "node_modules/@tweenjs/tween.js": { | |||
| "version": "18.6.4", | |||
| "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz", | |||
| "integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "dev": true | |||
| }, | |||
| "node_modules/@types/stats.js": { | |||
| "version": "0.17.3", | |||
| "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", | |||
| "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "dev": true | |||
| }, | |||
| "node_modules/@types/three": { | |||
| "version": "0.152.1", | |||
| "resolved": "https://registry.npmjs.org/@types/three/-/three-0.152.1.tgz", | |||
| "integrity": "sha512-PMOCQnx9JRmq+2OUGTPoY9h1hTWD2L7/nmuW/SyNq1Vbq3Lwt3MNdl3wYSa4DvLTGv62NmIXD9jYdAOwohwJyw==", | |||
| "dev": true, | |||
| "license": "MIT", | |||
| "dependencies": { | |||
| "@tweenjs/tween.js": "~18.6.4", | |||
| "@types/stats.js": "*", | |||
| @@ -54,25 +49,22 @@ | |||
| } | |||
| }, | |||
| "node_modules/@types/webxr": { | |||
| "version": "0.5.20", | |||
| "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.20.tgz", | |||
| "integrity": "sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "version": "0.5.12", | |||
| "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.12.tgz", | |||
| "integrity": "sha512-+6LV7bN17XUWy4wIMILsGQX6ucawf64lYLG9jaGKSvOnKaJzWjcKXAkO0dZaC8MfoEqYQC7gl1GQnfITjBcazw==", | |||
| "dev": true | |||
| }, | |||
| "node_modules/fflate": { | |||
| "version": "0.6.10", | |||
| "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", | |||
| "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "dev": true | |||
| }, | |||
| "node_modules/lil-gui": { | |||
| "version": "0.17.0", | |||
| "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz", | |||
| "integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "dev": true | |||
| }, | |||
| "node_modules/threepipe": { | |||
| "resolved": "../../src", | |||
| @@ -88,30 +80,21 @@ | |||
| "@tweakpane/core": "1.1.8" | |||
| } | |||
| }, | |||
| "node_modules/tweakpane-image-plugin/node_modules/@tweakpane/core": { | |||
| "version": "1.1.8", | |||
| "resolved": "https://registry.npmjs.org/@tweakpane/core/-/core-1.1.8.tgz", | |||
| "integrity": "sha512-psvBf6Cbm3YSZOTmDFWkcGzHYMnw7gVZM3jw+TfbzErIC+sMXPQb85h4ayW04w2u7AGg8jD0gHXSCg5wd+rafg==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| }, | |||
| "node_modules/uiconfig-tweakpane": { | |||
| "version": "0.0.10", | |||
| "resolved": "https://registry.npmjs.org/uiconfig-tweakpane/-/uiconfig-tweakpane-0.0.10.tgz", | |||
| "integrity": "sha512-VF67oUg7M9EXKR3IO+TXS6jP28qfT1ci/C4Inu8CjruJk8qBfUjuxKBU5kLXH97rE5dM0xLvLg/rYxRlpJ8mog==", | |||
| "version": "0.0.8", | |||
| "resolved": "https://registry.npmjs.org/uiconfig-tweakpane/-/uiconfig-tweakpane-0.0.8.tgz", | |||
| "integrity": "sha512-BZE/+6pW7qlywu4nhMjvzJ47IUORWn8rJsPpmcGqJgAz8G6MZjMXEW3Ey8EL41cVsDf5QSb0E/eTK8OWwuRfbA==", | |||
| "dev": true, | |||
| "license": "MIT", | |||
| "dependencies": { | |||
| "@types/three": "^0.152.1", | |||
| "uiconfig.js": "^0.1.1" | |||
| "uiconfig.js": "^0.0.8" | |||
| } | |||
| }, | |||
| "node_modules/uiconfig.js": { | |||
| "version": "0.1.1", | |||
| "resolved": "https://registry.npmjs.org/uiconfig.js/-/uiconfig.js-0.1.1.tgz", | |||
| "integrity": "sha512-JzJyAgtFOfWVg964mmKKByULnhg4d5QpfsvXzj0T/Mncs1pK3/FACM+pAteLmT1xDeVDwwIU5s86UzlTiYwR/A==", | |||
| "dev": true, | |||
| "license": "MIT" | |||
| "version": "0.0.8", | |||
| "resolved": "https://registry.npmjs.org/uiconfig.js/-/uiconfig.js-0.0.8.tgz", | |||
| "integrity": "sha512-0H1OO4CNHP5O0LBy82YWWFCzDK+Yf/GtXnR3i968FkMkf0+3/JsW7MC8ea2CcPtsi8ni4TA1FrMOC+KrYmMnCQ==", | |||
| "dev": true | |||
| } | |||
| } | |||
| } | |||
| @@ -49,6 +49,7 @@ export class GLTFMaterialExtrasExtension { | |||
| // if (ext.transparent !== undefined) o.transparent = ext.transparent // this is set by GLTFLoader based on alpha mode | |||
| if (ext.envMapIntensity !== undefined) o.envMapIntensity = ext.envMapIntensity // for when separateEnvMapIntensity is true | |||
| // if (ext.envMapSlotKey !== undefined) o.envMapSlotKey = ext.envMapSlotKey // in userdata | |||
| // if (ext.stencilWrite !== undefined) o.stencilWrite = ext.stencilWrite | |||
| // if (ext.stencilWriteMask !== undefined) o.stencilWriteMask = ext.stencilWriteMask | |||
| @@ -159,6 +160,7 @@ export class GLTFMaterialExtrasExtension { | |||
| if (material.alphaTest !== undefined) dat.alphaTest = material.alphaTest | |||
| if (material.envMapIntensity !== undefined) dat.envMapIntensity = material.envMapIntensity // for when separateEnvMapIntensity is true | |||
| // if (material.envMapSlotKey !== undefined) dat.envMapSlotKey = material.envMapSlotKey // in userData | |||
| // if (material.stencilWrite !== undefined) dat.stencilWrite = material.stencilWrite | |||
| // if (material.stencilWriteMask !== undefined) dat.stencilWriteMask = material.stencilWriteMask | |||
| @@ -47,8 +47,17 @@ export interface IMaterialUserData extends IImportResultUserData{ | |||
| */ | |||
| renderToDepth?: boolean | |||
| // only for materials that have envMapIntensity | |||
| /** | |||
| * Flag to tell the scene to prefer `material.envMapIntensity` over `scene.envMapIntensity` | |||
| * only for materials that have envMapIntensity | |||
| */ | |||
| separateEnvMapIntensity?: boolean // default: false | |||
| /** | |||
| * The environment map to use in the `RootScene`. To use this, object with the material must be in the RootScene, and the key should exist in the `RootScene`'s `textureSlots`. | |||
| * | |||
| * only for materials that have envMap | |||
| */ | |||
| envMapSlotKey?: string | |||
| cloneId?: string | |||
| cloneCount?: number | |||
| @@ -152,7 +152,19 @@ export const iMaterialUI = { | |||
| // hidden: ()=>!material.transparent && material.transmission < 0.001, | |||
| getValue: ()=>material.userData.renderToGBuffer === true, | |||
| setValue: (v: boolean)=>{ | |||
| material.userData.renderToGBuffer = v ? v : undefined | |||
| if (!v && !material.userData.renderToGBuffer) return | |||
| material.userData.renderToGBuffer = v | |||
| material.setDirty() | |||
| }, | |||
| }, | |||
| { | |||
| type: 'checkbox', | |||
| label: 'Render to Depth', | |||
| hidden: ()=>material.userData.renderToDepth !== undefined, | |||
| getValue: ()=>material.userData.renderToDepth === true, | |||
| setValue: (v: boolean)=>{ | |||
| if (!v && !material.userData.renderToDepth) return | |||
| material.userData.renderToDepth = v | |||
| material.setDirty() | |||
| }, | |||
| }, | |||
| @@ -222,6 +234,44 @@ export const iMaterialUI = { | |||
| ], | |||
| } | |||
| ), | |||
| environment: (material: IMaterial): UiObjectConfig => ( | |||
| { | |||
| type: 'folder', | |||
| label: 'Environment', | |||
| children: [ | |||
| { | |||
| type: 'checkbox', | |||
| label: 'Override Environment', | |||
| // property: [this.userData, 'separateEnvMapIntensity'], | |||
| getValue: ()=>material.userData.separateEnvMapIntensity === true, | |||
| setValue: (v: boolean)=>{ | |||
| material.userData.separateEnvMapIntensity = v | |||
| if (!v) delete material.userData.separateEnvMapIntensity | |||
| }, | |||
| // onChange: material.setDirty, | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| bounds: [0, 20], | |||
| hidden: ()=>!material.userData.separateEnvMapIntensity, | |||
| label: 'Environment Intensity', | |||
| property: [material, 'envMapIntensity'], | |||
| }, | |||
| { | |||
| type: 'dropdown', | |||
| hidden: ()=>!material.userData.separateEnvMapIntensity && !material.userData.envMapSlotKey, | |||
| label: 'Environment Map', | |||
| children: ['', 'environment1', 'environment2'].map((i)=>({label: i || 'default', value: i})), | |||
| getValue: ()=>material.userData.envMapSlotKey || '', | |||
| setValue: (v: string)=>{ | |||
| material.userData.envMapSlotKey = v | |||
| if (!v) delete material.userData.envMapSlotKey | |||
| material.setDirty() | |||
| }, | |||
| }, | |||
| ], | |||
| } | |||
| ), | |||
| misc: (material: IMaterial): UiObjectConfig[] => [ | |||
| ()=>material.materialExtensions?.map(v=>{ | |||
| v.uuid = v.uuid || generateUUID() | |||
| @@ -139,6 +139,7 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| iMaterialUI.bumpNormal(this), | |||
| iMaterialUI.emission(this), | |||
| iMaterialUI.transmission(this), | |||
| iMaterialUI.environment(this), | |||
| iMaterialUI.clearcoat(this), | |||
| iMaterialUI.iridescence(this), | |||
| iMaterialUI.sheen(this), | |||
| @@ -180,6 +180,7 @@ export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMateri | |||
| iMaterialUI.blending(this), | |||
| iMaterialUI.polygonOffset(this), | |||
| iMaterialUI.aoLightMap(this), | |||
| // iMaterialUI.environment(this), | |||
| ...iMaterialUI.misc(this), | |||
| ], | |||
| } | |||
| @@ -58,6 +58,11 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| @serialize() @onChange2(RootScene.prototype._onEnvironmentChange) | |||
| environment: ITexture | null = null | |||
| /** | |||
| * Extra textures/envmaps that can be used by objects/materials/plugins and will be serialized. | |||
| */ | |||
| @serialize() | |||
| public textureSlots: Record<string, ITexture> = {} | |||
| /** | |||
| * The intensity for the environment light. | |||
| */ | |||
| @@ -126,7 +131,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| iObjectCommons.upgradeObject3D.call(this, undefined, objectProcessor) | |||
| // this is called from parentDispatch since scene is a parent. | |||
| this.addEventListener('materialUpdate', ()=>this.dispatchEvent({type: 'sceneMaterialUpdate'})) | |||
| this.addEventListener('materialUpdate', (e: any)=>this.dispatchEvent({...e, type: 'sceneMaterialUpdate'})) | |||
| this.addEventListener('objectUpdate', this.refreshScene) | |||
| this.addEventListener('geometryUpdate', this.refreshScene) | |||
| this.addEventListener('geometryChanged', this.refreshScene) | |||
| @@ -341,11 +346,11 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I | |||
| } | |||
| private _mainCameraUpdate = () => { | |||
| private _mainCameraUpdate = (e: any) => { | |||
| this.setDirty({refreshScene: false}) | |||
| this.refreshActiveCameraNearFar() | |||
| this.dispatchEvent({type: 'mainCameraUpdate'}) | |||
| this.dispatchEvent({type: 'activeCameraUpdate'}) // deprecated | |||
| this.dispatchEvent({...e, type: 'mainCameraUpdate'}) | |||
| this.dispatchEvent({...e, type: 'activeCameraUpdate'}) // deprecated | |||
| } | |||
| // cached values | |||
| @@ -1,13 +1,14 @@ | |||
| import {AViewerPluginSync, ThreeViewer} from '../../viewer' | |||
| import {IGeometry, iGeometryCommons, IMaterial, ISceneEvent, Mesh2, PhysicalMaterial, UnlitMaterial} from '../../core' | |||
| import {IGeometry, iGeometryCommons, IMaterial, ISceneEvent, Mesh2, PhysicalMaterial} from '../../core' | |||
| import {BufferAttribute, BufferGeometry, Euler, InterleavedBufferAttribute, PlaneGeometry, Vector3} from 'three' | |||
| import {onChange, onChange2, serialize} from 'ts-browser-helpers' | |||
| import {OrbitControls3} from '../../three' | |||
| import {bindToValue, OrbitControls3} from '../../three' | |||
| import {uiConfig, uiFolderContainer, uiNumber, uiToggle} from 'uiconfig.js' | |||
| @uiFolderContainer('Ground') | |||
| export class BaseGroundPlugin<TEvent extends string = ''> extends AViewerPluginSync<TEvent> { | |||
| public static readonly PluginType: string = 'BaseGroundPlugin' | |||
| public static readonly OldPluginType: string = 'Ground' | |||
| get enabled() { | |||
| return this.visible | |||
| @@ -77,6 +78,7 @@ export class BaseGroundPlugin<TEvent extends string = ''> extends AViewerPluginS | |||
| @serialize('material') | |||
| @uiConfig() | |||
| @bindToValue({obj: 'mesh', key: 'material'}) | |||
| protected _material?: PhysicalMaterial | |||
| onAdded(viewer: ThreeViewer): void { | |||
| @@ -223,7 +225,7 @@ export class BaseGroundPlugin<TEvent extends string = ''> extends AViewerPluginS | |||
| protected _createMesh(mesh?: Mesh2<IGeometry&PlaneGeometry, IMaterial>): Mesh2<IGeometry&PlaneGeometry, IMaterial> { | |||
| if (!mesh) mesh = new Mesh2(this._geometry, new UnlitMaterial()) | |||
| if (!mesh) mesh = new Mesh2(this._geometry, this._createMaterial()) | |||
| else mesh.geometry = this._geometry | |||
| if (mesh) { | |||
| mesh.userData.physicsMass = 0 | |||
| @@ -252,6 +254,8 @@ export class BaseGroundPlugin<TEvent extends string = ''> extends AViewerPluginS | |||
| if (!material) material = new PhysicalMaterial({ | |||
| name: 'BaseGroundMaterial', | |||
| color: 0xffffff, | |||
| roughness: 0.8, | |||
| metalness: 0.5, | |||
| }) | |||
| material.userData.runtimeMaterial = true | |||
| return material | |||
| @@ -261,18 +265,16 @@ export class BaseGroundPlugin<TEvent extends string = ''> extends AViewerPluginS | |||
| if (!this._viewer) return false | |||
| if (this.isDisabled()) return false | |||
| const mat = this._material ?? this._createMaterial() | |||
| const isNewMaterial = mat !== this._material | |||
| const isNewMaterial = this._mesh.material !== this._material | |||
| if (isNewMaterial) { // new material | |||
| this._removeMaterial() | |||
| // this._removeMaterial() | |||
| this._material = mat | |||
| const id = this._material?.uuid | |||
| if (!id) console.warn('No material found for ground') | |||
| // const id = this._material?.uuid | |||
| // if (!id) console.warn('No material found for ground') | |||
| this._viewer.scene.setDirty() | |||
| if (this._mesh && this._material) { | |||
| this._material.roughness = 0.2 | |||
| this._material.metalness = 0.5 | |||
| this._mesh.material = this._material // for update event handlers. | |||
| } | |||
| // if (this._mesh && this._material) { | |||
| // this._mesh.material = this._material // must be set even if same, for update event handlers. | |||
| // } | |||
| } | |||
| if (this._material) { | |||
| if (this._material.userData.__renderToDepth === undefined) { | |||
| @@ -167,8 +167,8 @@ export class InteractionPromptPlugin extends AViewerPluginSync<''> { | |||
| private _mainCameraUpdate = (e: any)=>{ | |||
| if (this.isDisabled()) return | |||
| if (e.change === 'deserialize') { | |||
| this.stopAnimation() | |||
| if (e.change === 'deserialize' && this.animationRunning) { | |||
| this.stopAnimation({reset: false}) // reset is false so that the new camera position is not reset | |||
| this.startAnimation() | |||
| } else { | |||
| this.lastActionTime = now() | |||
| @@ -148,7 +148,7 @@ export class FrameFadePlugin | |||
| } | |||
| protected _createPass() { | |||
| return new FrameFadeBlendPass(this.passId, this) | |||
| return new FrameFadeBlendPass(this.passId, this, this._viewer?.renderManager.maxHDRIntensity) | |||
| } | |||
| get canFrameFade() { | |||
| @@ -189,17 +189,16 @@ export class FrameFadeBlendPass extends AddBlendTexturePass implements IPipeline | |||
| required = ['render', 'progressive'] | |||
| dirty: ValOrFunc<boolean> = () => false | |||
| fadeTime = 0 // ms | |||
| fadeTimeState = 0 | |||
| toSaveFrame = false | |||
| private _lastTime = 0 | |||
| constructor(public readonly passId: IPassID, public plugin: FrameFadePlugin) { | |||
| super() | |||
| constructor(public readonly passId: IPassID, public plugin: FrameFadePlugin, maxIntensity = 120) { | |||
| super(undefined, maxIntensity) | |||
| } | |||
| render(renderer: IWebGLRenderer, writeBuffer: WebGLRenderTarget, readBuffer: WebGLRenderTarget, deltaTime: number, maskActive: boolean) { | |||
| this.needsSwap = false | |||
| const target = this.plugin.target | |||
| @@ -107,7 +107,7 @@ export class ProgressivePlugin | |||
| protected _createPass() { | |||
| // this._createTarget(true) | |||
| const pass = new ProgressiveBlendPass(this.passId, ()=>this.target ?? this._createTarget()) // todo: disposeTarget somewhere | |||
| const pass = new ProgressiveBlendPass(this.passId, ()=>this.target ?? this._createTarget(), this._viewer?.renderManager.maxHDRIntensity) // todo: disposeTarget somewhere | |||
| pass.dirty = () => (this._viewer?.renderManager.frameCount || 0) < this.maxFrameCount // todo use isConverged function | |||
| return pass | |||
| } | |||
| @@ -180,8 +180,8 @@ export class ProgressiveBlendPass extends AddBlendTexturePass implements IPipeli | |||
| after = ['render'] | |||
| required = ['render'] | |||
| dirty: ValOrFunc<boolean> = () => false | |||
| constructor(public readonly passId: IPassID, public target?: ValOrFunc<WebGLRenderTarget|undefined>) { | |||
| super() | |||
| constructor(public readonly passId: IPassID, public target?: ValOrFunc<WebGLRenderTarget|undefined>, maxIntensity = 120) { | |||
| super(undefined, maxIntensity) | |||
| } | |||
| render(renderer: IWebGLRenderer, writeBuffer: WebGLRenderTarget, readBuffer: WebGLRenderTarget, deltaTime: number, maskActive: boolean) { | |||
| if (!this.enabled) return | |||
| @@ -3,7 +3,7 @@ bool doTonemap = true; | |||
| #ifdef GBUFFER_HAS_FLAGS | |||
| doTonemap = getToneMapBit(getGBufferFlags(vUv).a) > 0; | |||
| #endif | |||
| #if TONEMAP_BACKGROUND < 1 | |||
| #if TONEMAP_BACKGROUND < 1 // todo - || (defined(CLIP_BACKGROUND) && CLIP_BACKGROUND > 0) || defined(CLIP_BACKGROUND_FORCE) | |||
| if(isBackground) doTonemap = false; // isBackground defined in ScreenPass | |||
| #endif | |||
| #endif | |||
| @@ -5,7 +5,7 @@ import {IPass} from './Pass' | |||
| import {glsl} from 'ts-browser-helpers' | |||
| export class AddBlendTexturePass extends ExtendedShaderPass implements IPass { | |||
| constructor(texture?: Texture) { | |||
| constructor(texture?: Texture, maxIntensity = 120) { | |||
| super({ | |||
| vertexShader: CopyShader.vertexShader, | |||
| fragmentShader: glsl` | |||
| @@ -13,7 +13,7 @@ export class AddBlendTexturePass extends ExtendedShaderPass implements IPass { | |||
| uniform vec4 weight2; | |||
| varying vec2 vUv; | |||
| void main() { | |||
| vec4 texel = clamp(weight * tDiffuseTexelToLinear ( texture2D( tDiffuse, vUv ) ) + weight2 * tDiffuse2TexelToLinear ( texture2D( tDiffuse2, vUv ) ), vec4(0), vec4(8)); | |||
| vec4 texel = clamp(weight * tDiffuseTexelToLinear ( texture2D( tDiffuse, vUv ) ) + weight2 * tDiffuse2TexelToLinear ( texture2D( tDiffuse2, vUv ) ), vec4(0), vec4(MAX_INTENSITY)); | |||
| gl_FragColor = texel; | |||
| #include <encodings_fragment> | |||
| } | |||
| @@ -24,6 +24,9 @@ export class AddBlendTexturePass extends ExtendedShaderPass implements IPass { | |||
| 'weight': {value: new Vector4(1, 1, 1, 1)}, | |||
| 'weight2': {value: new Vector4(1, 1, 1, 1)}, | |||
| }, | |||
| defines: { | |||
| ['MAX_INTENSITY']: maxIntensity, | |||
| }, | |||
| }, 'tDiffuse', 'tDiffuse2') | |||
| this.clear = false | |||
| this.needsSwap = true | |||
| @@ -55,7 +55,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren | |||
| constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) { | |||
| super(undefined, undefined, overrideMaterial, clearColor, clearAlpha) | |||
| this.renderManager = renderManager | |||
| this._blendPass = new GenericBlendTexturePass({}, 'c = vec4(a.rgb * (1. - b.a) + b.rgb * b.a, 1.);') | |||
| this._blendPass = new GenericBlendTexturePass({}, 'c = vec4(a.rgb * (1. - b.a) + b.rgb * b.a, 1.);', '', undefined, renderManager.maxHDRIntensity) | |||
| this.setDirty = this.setDirty.bind(this) | |||
| } | |||
| @@ -27,7 +27,7 @@ export class GBufferRenderPass<TP extends IPassID=IPassID, T extends WebGLMultip | |||
| renderToGBuffer = renderToGBuffer ?? material.userData.renderToGBuffer | |||
| if (material.userData.pluginsDisabled) renderToGBuffer = false | |||
| if ( | |||
| material.transparent && (renderToGBuffer || material.opacity > 0.99) || // transparent and render to gbuffer | |||
| material.transparent && (renderToGBuffer || material.opacity > 0.99 && !material.map && !material.alphaMap) || // transparent and render to gbuffer | |||
| !material.transparent && !material.transmission && renderToGBuffer === false // opaque and dont render to gbuffer | |||
| ) { | |||
| this._transparentMats.add(material) | |||
| @@ -5,7 +5,7 @@ import {ExtendedShaderPass} from './ExtendedShaderPass' | |||
| import {IPass} from './Pass' | |||
| export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass { | |||
| constructor(uniforms: {[uniform: string]: IUniform}, blendFunc = 'c = a + b;', extraFrag = '', texture?: Texture) { | |||
| constructor(uniforms: {[uniform: string]: IUniform}, blendFunc = 'c = a + b;', extraFrag = '', texture?: Texture, maxIntensity = 120) { | |||
| super({ | |||
| vertexShader: CopyShader.vertexShader, | |||
| fragmentShader: ` | |||
| @@ -16,7 +16,7 @@ export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass | |||
| vec4 b = tDiffuse2TexelToLinear ( texture2D( tDiffuse2, vUv ) ); | |||
| vec4 c = vec4(0); | |||
| ${blendFunc} | |||
| c = clamp(c, vec4(0), vec4(8)); | |||
| c = clamp(c, vec4(0), vec4(MAX_INTENSITY)); | |||
| gl_FragColor = c; | |||
| #include <encodings_fragment> | |||
| } | |||
| @@ -26,6 +26,9 @@ export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass | |||
| 'tDiffuse2': {value: texture}, | |||
| ...uniforms, | |||
| }, | |||
| defines: { | |||
| ['MAX_INTENSITY']: maxIntensity, | |||
| }, | |||
| }, 'tDiffuse', 'tDiffuse2') | |||
| this.clear = false | |||
| this.needsSwap = true | |||
| @@ -81,7 +81,7 @@ export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'scr | |||
| @matDefineBool('CLIP_BACKGROUND_FORCE', undefined, undefined, ScreenPass.prototype.setDirty, true) | |||
| clipBackgroundForce = false | |||
| // todo: this is not serialized anymore? | |||
| // todo: this is not serialized anymore? we should serialize this in some plugin... | |||
| @matDefineBool('CLIP_BACKGROUND', undefined, undefined, ScreenPass.prototype.setDirty) | |||
| @uiToggle() clipBackground = false | |||
| @@ -183,6 +183,9 @@ export interface ThreeViewerOptions { | |||
| target?: Vector3, | |||
| } | |||
| // values above this might be clamped in post processing | |||
| maxHDRIntensity?: number | |||
| /** | |||
| * Options for the asset manager. | |||
| @@ -428,6 +431,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes | |||
| renderScale: typeof options.renderScale === 'string' ? options.renderScale === 'auto' ? | |||
| Math.min(2, window.devicePixelRatio) : parseFloat(options.renderScale) : | |||
| options.renderScale, | |||
| maxHDRIntensity: options.maxHDRIntensity, | |||
| }) | |||
| this.renderManager.addEventListener('animationLoop', this._animationLoop as any) | |||
| this.renderManager.addEventListener('resize', ()=> this._scene.mainCamera.refreshAspect()) | |||
| @@ -1,5 +1,12 @@ | |||
| import {IRenderTarget, RenderManager} from '../rendering' | |||
| import {HalfFloatType, LinearMipMapLinearFilter, NoColorSpace, RGBM16ColorSpace, UnsignedByteType} from 'three' | |||
| import { | |||
| HalfFloatType, | |||
| LinearFilter, | |||
| LinearMipMapLinearFilter, | |||
| NoColorSpace, | |||
| RGBM16ColorSpace, | |||
| UnsignedByteType, | |||
| } from 'three' | |||
| import {IRenderManagerEvent, IRenderManagerOptions, IScene} from '../core' | |||
| import {ExtendedRenderPass, ScreenPass, TViewerScreenShader} from '../postprocessing' | |||
| import {uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | |||
| @@ -12,6 +19,7 @@ export interface ViewerRenderManagerOptions extends IRenderManagerOptions { | |||
| depthBuffer?: boolean, | |||
| zPrepass?: boolean, | |||
| screenShader?: TViewerScreenShader | |||
| maxHDRIntensity?: number | |||
| } | |||
| @uiFolderContainer('Render Manager') | |||
| @@ -20,6 +28,7 @@ export class ViewerRenderManager extends RenderManager<IRenderManagerEvent, 'gbu | |||
| readonly msaa: boolean | number | |||
| readonly depthBuffer: boolean | |||
| readonly zPrepass: boolean | |||
| readonly maxHDRIntensity: number | |||
| readonly renderPass: ExtendedRenderPass | |||
| readonly screenPass: ScreenPass | |||
| declare uiConfig: UiObjectConfig | |||
| @@ -32,14 +41,15 @@ export class ViewerRenderManager extends RenderManager<IRenderManagerEvent, 'gbu | |||
| colorSpace: rgbm ? RGBM16ColorSpace : NoColorSpace, | |||
| type: rgbm ? UnsignedByteType : HalfFloatType, | |||
| depthBuffer: depthBuffer, | |||
| generateMipmaps: msaa ? true : undefined, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||
| minFilter: msaa ? LinearMipMapLinearFilter : undefined, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||
| generateMipmaps: msaa ? true : false, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||
| minFilter: msaa ? LinearMipMapLinearFilter : LinearFilter, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||
| }, | |||
| }) | |||
| this.rgbm = rgbm | |||
| this.msaa = msaa && this.isWebGL2 | |||
| this.depthBuffer = depthBuffer | |||
| this.zPrepass = options.zPrepass || false | |||
| this.maxHDRIntensity = options.maxHDRIntensity ?? (rgbm ? 16 : 72) | |||
| let doTransmissionFix = true // const for debugging, todo could be made into a static prop maybe? | |||
| if (!this._renderer.userData) { | |||