| color: #333; | color: #333; | ||||
| font-size: 2em; | font-size: 2em; | ||||
| font-family: sans-serif; | font-family: sans-serif; | ||||
| pointer-events: none; | |||||
| } | } | ||||
| </style> | </style> | ||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>GLTF Transmission Test</title> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "uiconfig-tweakpane": "https://unpkg.com/uiconfig-tweakpane@latest/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, IObject3D, RenderTargetPreviewPlugin, ThreeViewer, TweakpaneUiPlugin} from 'threepipe' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: false, | |||||
| rgbm: true, | |||||
| zPrepass: false, | |||||
| }) | |||||
| async function init() { | |||||
| const targetPreview = viewer.addPluginSync(RenderTargetPreviewPlugin) | |||||
| targetPreview.addTarget(()=>viewer.renderManager.composerTarget, 'composer-1', false, false) | |||||
| viewer.renderManager.renderPass.preserveTransparentTarget = true | |||||
| targetPreview.addTarget(()=>viewer.renderManager.renderPass.transparentTarget, 'transparent', true, true) | |||||
| targetPreview.addTarget(()=>viewer.renderManager.composerTarget2, 'composer-2', false, false) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| const [model, model2] = await Promise.all([ | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescenceLamp.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }), | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescentDishWithOlives.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }), | |||||
| ]) | |||||
| if (!model || !model2) { | |||||
| console.error('model not loaded') | |||||
| return | |||||
| } | |||||
| model.position.x = -1 | |||||
| model2.position.x = 1 | |||||
| model2.position.y = -1.2 | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(false)) | |||||
| const m1 = model?.getObjectByName('lamp_transmission') | |||||
| const m2 = model2?.getObjectByName('glassCover') | |||||
| const materials = [...m1?.materials || [], ...m2?.materials || []] | |||||
| for (const material of materials) { | |||||
| const config = material.uiConfig | |||||
| if (!config) continue | |||||
| ui.appendChild(config) | |||||
| } | |||||
| } | |||||
| init().then(_testFinish) |
| </ul> | </ul> | ||||
| <h2 class="category">Utils</h2> | <h2 class="category">Utils</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="./parallel-asset-import/">Parallel Asset Import </a></li> | |||||
| <li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li> | <li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li> | ||||
| </ul> | </ul> | ||||
| <h2 class="category">Tests</h2> | <h2 class="category">Tests</h2> | ||||
| <ul> | <ul> | ||||
| <li><a href="./import-test/">Import Test</a></li> | |||||
| <li><a href="./sphere-rgbm-test/">Sphere RGBM Test </a></li> | |||||
| <li><a href="./sphere-half-float-test/">Sphere Half Float Test </a></li> | |||||
| <li><a href="./sphere-msaa-test/">Sphere MSAA Test </a></li> | |||||
| <li><a href="./gltf-transmission-test/">GLTF Transmission Test </a></li> | |||||
| <li><a href="./sphere-rgbm-test/">RGBM Test </a></li> | |||||
| <li><a href="./sphere-half-float-test/">Half Float Test </a></li> | |||||
| <li><a href="./sphere-msaa-test/">MSAA Test </a></li> | |||||
| <li><a href="./z-prepass/">Z-Prepass Test </a></li> | <li><a href="./z-prepass/">Z-Prepass Test </a></li> | ||||
| <li><a href="./import-test/">Import Test</a></li> | |||||
| </ul> | </ul> | ||||
| </div> | </div> | ||||
| <div class="iframe-container"> | <div class="iframe-container"> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Parallel Asset Import/Download</title> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "uiconfig-tweakpane": "https://unpkg.com/uiconfig-tweakpane@latest/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, IObject3D, ThreeViewer} from 'threepipe' | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: false, | |||||
| rgbm: true, | |||||
| zPrepass: false, | |||||
| }) | |||||
| async function init() { | |||||
| const [env, model, model2] = await Promise.all([ | |||||
| viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr'), | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescenceLamp.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }), | |||||
| viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/IridescentDishWithOlives.glb', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }), | |||||
| ]) | |||||
| console.log(env, model, model2) | |||||
| if (!model || !model2) { | |||||
| console.error('model not loaded') | |||||
| return | |||||
| } | |||||
| model.position.x = -1 | |||||
| model2.position.x = 1 | |||||
| model2.position.y = -1.2 | |||||
| } | |||||
| init().then(_testFinish) |
| /** | /** | ||||
| * @param info: uuid or template name or material type | * @param info: uuid or template name or material type | ||||
| * @param params | |||||
| */ | */ | ||||
| public findOrCreate(info: string, params?: IMaterialParameters): IMaterial | undefined { | |||||
| public findOrCreate(info: string, params?: IMaterialParameters|Material): IMaterial | undefined { | |||||
| let mat = this.findMaterial(info) | let mat = this.findMaterial(info) | ||||
| if (!mat) mat = this.create(info, params) | if (!mat) mat = this.create(info, params) | ||||
| return mat | return mat | ||||
| * @param register | * @param register | ||||
| * @param params | * @param params | ||||
| */ | */ | ||||
| public create<TM extends IMaterial>(nameOrType: string, {register = true, ...params}: IMaterialParameters&{register?: boolean} = {}): TM | undefined { | |||||
| public create<TM extends IMaterial>(nameOrType: string, params: IMaterialParameters = {}, register = true): TM | undefined { | |||||
| let template: IMaterialTemplate<any> = {materialType: nameOrType, name: nameOrType} | let template: IMaterialTemplate<any> = {materialType: nameOrType, name: nameOrType} | ||||
| while (!template.generator) { // looping so that we can inherit templates, not fully implemented yet | while (!template.generator) { // looping so that we can inherit templates, not fully implemented yet | ||||
| const t2 = this.findTemplate(template.materialType) // todo add a baseTemplate property to the template? | const t2 = this.findTemplate(template.materialType) // todo add a baseTemplate property to the template? | ||||
| template = {...template, ...t2} | template = {...template, ...t2} | ||||
| } | } | ||||
| const material = this._create<TM>(template, params) | const material = this._create<TM>(template, params) | ||||
| if (material && register !== false) this.registerMaterial(material) | |||||
| if (material && register) this.registerMaterial(material) | |||||
| return material | return material | ||||
| } | } | ||||
| type: 'folder', | type: 'folder', | ||||
| label: 'Refraction', | label: 'Refraction', | ||||
| children: [ | children: [ | ||||
| // { | |||||
| // type: 'slider', | |||||
| // bounds: [0, 1], | |||||
| // property: [material, 'reflectivity'], | |||||
| // }, | |||||
| { | { | ||||
| type: 'slider', | type: 'slider', | ||||
| bounds: [0, 1], | |||||
| property: [material, 'reflectivity'], | |||||
| bounds: [0, 4], | |||||
| property: [material, 'ior'], | |||||
| }, | }, | ||||
| { | { | ||||
| type: 'slider', | type: 'slider', | ||||
| property: [material, 'thicknessMap'], | property: [material, 'thicknessMap'], | ||||
| }, | }, | ||||
| makeSamplerUi(material, 'thicknessMap'), | makeSamplerUi(material, 'thicknessMap'), | ||||
| { | |||||
| type: 'number', | |||||
| property: [material, 'attenuationDistance'], | |||||
| }, | |||||
| { | |||||
| type: 'color', | |||||
| property: [material, 'attenuationColor'], | |||||
| }, | |||||
| ], | ], | ||||
| } | } | ||||
| ), | ), | ||||
| ], | ], | ||||
| } | } | ||||
| ), | ), | ||||
| iridescence: (material: PhysicalMaterial): UiObjectConfig => ( | |||||
| { | |||||
| type: 'folder', | |||||
| label: 'Iridescence', | |||||
| children: [ | |||||
| { | |||||
| type: 'slider', | |||||
| bounds: [0, 3], | |||||
| label: 'Intensity', | |||||
| property: [material, 'iridescence'], | |||||
| }, | |||||
| { | |||||
| type: 'slider', | |||||
| bounds: [0, 3], | |||||
| label: 'IOR', | |||||
| property: [material, 'iridescenceIOR'], | |||||
| }, | |||||
| { | |||||
| type: 'slider', | |||||
| bounds: [0, 500], | |||||
| label: 'Thickness0', | |||||
| property: [material.iridescenceThicknessRange, '0'], | |||||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||||
| }, | |||||
| { | |||||
| type: 'slider', | |||||
| bounds: [0, 500], | |||||
| label: 'Thickness1', | |||||
| property: [material.iridescenceThicknessRange, '1'], | |||||
| onChange: (ev)=>material.setDirty({uiChangeEvent: ev}), | |||||
| }, | |||||
| { | |||||
| type: 'image', | |||||
| property: [material, 'iridescenceMap'], | |||||
| }, | |||||
| makeSamplerUi(material, 'iridescenceMap'), | |||||
| { | |||||
| type: 'image', | |||||
| property: [material, 'iridescenceThicknessMap'], | |||||
| }, | |||||
| makeSamplerUi(material, 'iridescenceThicknessMap'), | |||||
| ], | |||||
| } | |||||
| ), | |||||
| sheen: (material: PhysicalMaterial): UiObjectConfig => ( | sheen: (material: PhysicalMaterial): UiObjectConfig => ( | ||||
| { | { | ||||
| type: 'folder', | type: 'folder', |
| constructor({customMaterialExtensions, ...parameters}: MeshPhysicalMaterialParameters & IMaterialParameters = {}) { | constructor({customMaterialExtensions, ...parameters}: MeshPhysicalMaterialParameters & IMaterialParameters = {}) { | ||||
| super(parameters) | super(parameters) | ||||
| this.fog = false | this.fog = false | ||||
| this.attenuationDistance = 0 // infinite distance (for Ui) | |||||
| this.setDirty = this.setDirty.bind(this) | this.setDirty = this.setDirty.bind(this) | ||||
| if (customMaterialExtensions) this.registerMaterialExtensions(customMaterialExtensions) | if (customMaterialExtensions) this.registerMaterialExtensions(customMaterialExtensions) | ||||
| iMaterialCommons.upgradeMaterial.call(this) | iMaterialCommons.upgradeMaterial.call(this) | ||||
| iMaterialUI.emission(this), | iMaterialUI.emission(this), | ||||
| iMaterialUI.transmission(this), | iMaterialUI.transmission(this), | ||||
| iMaterialUI.clearcoat(this), | iMaterialUI.clearcoat(this), | ||||
| iMaterialUI.iridescence(this), | |||||
| iMaterialUI.sheen(this), | iMaterialUI.sheen(this), | ||||
| ...iMaterialUI.misc(this), | ...iMaterialUI.misc(this), | ||||
| ], | ], | ||||
| if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial | if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial | ||||
| if (clearCurrentUserData) this.userData = {} | if (clearCurrentUserData) this.userData = {} | ||||
| iMaterialCommons.setValues(super.setValues).call(this, parameters) | iMaterialCommons.setValues(super.setValues).call(this, parameters) | ||||
| if (!isFinite(this.attenuationDistance)) this.attenuationDistance = 0 // hack for ui | |||||
| this.userData.uuid = this.uuid // just in case | this.userData.uuid = this.uuid // just in case | ||||
| return this | return this | ||||
| } | } | ||||
| reflectivity: 0.5, // because this is used in Material.js->toJSON and fromJSON instead of ior | reflectivity: 0.5, // because this is used in Material.js->toJSON and fromJSON instead of ior | ||||
| iridescence: 0, | |||||
| iridescenceMap: null, | iridescenceMap: null, | ||||
| iridescenceIOR: 1.3, | iridescenceIOR: 1.3, | ||||
| iridescenceThicknessRange: [100, 400], | iridescenceThicknessRange: [100, 400], |
| import {IPipelinePass} from './Pass' | import {IPipelinePass} from './Pass' | ||||
| import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js' | import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js' | ||||
| import { | import { | ||||
| CanvasTexture, | |||||
| Color, | Color, | ||||
| HalfFloatType, | HalfFloatType, | ||||
| LinearFilter, | LinearFilter, | ||||
| this._transparentTarget = undefined | this._transparentTarget = undefined | ||||
| } | } | ||||
| canvasTexture: CanvasTexture | |||||
| constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) { | constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) { | ||||
| super(undefined, undefined, overrideMaterial, clearColor, clearAlpha) | super(undefined, undefined, overrideMaterial, clearColor, clearAlpha) | ||||
| this.renderManager = renderManager | this.renderManager = renderManager | ||||
| // this.canvasTexture = new CanvasTexture(renderManager.renderer.domElement) | |||||
| 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.);') | ||||
| this.setDirty = this.setDirty.bind(this) | this.setDirty = this.setDirty.bind(this) | ||||
| } | } | ||||
| this.clear = curClear | this.clear = curClear | ||||
| } | } | ||||
| // console.log(renderer.info.render.calls) | |||||
| if (renderer.info.render.calls > 0) { | if (renderer.info.render.calls > 0) { | ||||
| // console.log('missive blit', renderer.info.render.frame) | // console.log('missive blit', renderer.info.render.frame) |
| * @param setBackground - Set the background image of the scene from the same map. | * @param setBackground - Set the background image of the scene from the same map. | ||||
| * @param options - Options for importing the asset. See {@link ImportAssetOptions} | * @param options - Options for importing the asset. See {@link ImportAssetOptions} | ||||
| */ | */ | ||||
| async setEnvironmentMap(map: string | IAsset | null | ITexture, {setBackground = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<void> { | |||||
| async setEnvironmentMap(map: string | IAsset | null | ITexture, {setBackground = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<ITexture | null> { | |||||
| this._scene.environment = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null | this._scene.environment = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null | ||||
| if (setBackground) return this.setBackgroundMap(this._scene.environment) | if (setBackground) return this.setBackgroundMap(this._scene.environment) | ||||
| return this._scene.environment | |||||
| } | } | ||||
| /** | /** | ||||
| * @param setEnvironment - Set the environment map of the scene from the same map. | * @param setEnvironment - Set the environment map of the scene from the same map. | ||||
| * @param options - Options for importing the asset. See {@link ImportAssetOptions} | * @param options - Options for importing the asset. See {@link ImportAssetOptions} | ||||
| */ | */ | ||||
| async setBackgroundMap(map: string | IAsset | null | ITexture, {setEnvironment = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<void> { | |||||
| async setBackgroundMap(map: string | IAsset | null | ITexture, {setEnvironment = false, ...options}: ImportAssetOptions&{setBackground?: boolean} = {}): Promise<ITexture | null> { | |||||
| this._scene.background = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null | this._scene.background = map && !(<ITexture>map).isTexture ? await this.assetManager.importer.importSingle<ITexture>(map as string|IAsset, options) || null : <ITexture>map || null | ||||
| if (setEnvironment) return this.setEnvironmentMap(this._scene.background) | if (setEnvironment) return this.setEnvironmentMap(this._scene.background) | ||||
| return this._scene.background | |||||
| } | } | ||||
| /** | /** |