| @@ -675,7 +675,7 @@ when the extension is registered or when the material is added to the scene. | |||
| Threepipe includes several built-in materials like | |||
| [PhysicalMaterial](https://threepipe.org/docs/classes/PhysicalMaterial.html), | |||
| [UnlitMaterial](https://threepipe.org/docs/classes/UnlitMaterial.html), | |||
| [ExtendedShaderMaterial](https://threepipe.org/docs/classes/ExtendedShaderMaterial.html) | |||
| [ExtendedShaderMaterial](https://threepipe.org/docs/classes/ExtendedShaderMaterial.html), [LegacyPhongMaterial](https://threepipe.org/docs/classes/LegacyPhongMaterial.html), | |||
| that include support for extending the material. | |||
| Any three.js material can be made extendable, | |||
| check the `ShaderPass2` class for a simple example that adds support for material extension to three.js ShaderPass. | |||
| @@ -2244,7 +2244,7 @@ Note: The animation is started when the animate or animateAsync function is call | |||
| Example: https://threepipe.org/examples/#camera-view-plugin/ | |||
| Source Code: [src/plugins/animation/CameraViewPlugin.ts](./src/plugins/ui/RenderTargetPreviewPlugin.ts) | |||
| Source Code: [src/plugins/animation/CameraViewPlugin.ts](./src/plugins/animation/CameraViewPlugin.ts) | |||
| API Reference: [CameraViewPlugin](https://threepipe.org/docs/classes/CameraViewPlugin.html) | |||
| @@ -0,0 +1,36 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>GLTF Transmission Test (MSAA)</title> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <!-- 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", | |||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/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> | |||
| @@ -0,0 +1,52 @@ | |||
| import {_testFinish, IObject3D, RenderTargetPreviewPlugin, ThreeViewer} from 'threepipe' | |||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||
| msaa: true, | |||
| 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) | |||
| @@ -295,7 +295,9 @@ | |||
| </ul> | |||
| <h2 class="category">Tests</h2> | |||
| <ul> | |||
| <li><a href="./multi-viewer-test/">Multiple Viewers Test </a></li> | |||
| <li><a href="./gltf-transmission-test/">glTF Transmission Test </a></li> | |||
| <li><a href="./gltf-transmission-test-msaa/">glTF Transmission Test + MSAA </a></li> | |||
| <li><a href="./uint8-rgbm-hdr-test/">Uint8 RGBM HDR Test </a></li> | |||
| <li><a href="./half-float-hdr-test/">Half-float HDR Test </a></li> | |||
| <li><a href="./sphere-rgbm-test/">RGBM Test </a></li> | |||
| @@ -0,0 +1,57 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>Multiple Viewers Test</title> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <!-- 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" | |||
| } | |||
| } | |||
| </script> | |||
| <style id="example-style"> | |||
| html, body, .mcanvas, .container { | |||
| width: 100%; | |||
| height: 100%; | |||
| margin: 0; | |||
| overflow: hidden; | |||
| } | |||
| .container{ | |||
| display: grid; | |||
| grid-template-columns: 1fr 1fr; | |||
| grid-template-rows: 1fr 1fr; | |||
| } | |||
| .canvas-container{ | |||
| position: relative; | |||
| width: 100%; | |||
| height: 100%; | |||
| overflow: hidden; | |||
| outline: 1px solid #464646; | |||
| } | |||
| </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 class="container"> | |||
| <div class="canvas-container"> | |||
| <canvas id="mcanvas1" class="mcanvas"></canvas> | |||
| </div> | |||
| <div class="canvas-container"> | |||
| <canvas id="mcanvas2" class="mcanvas"></canvas> | |||
| </div> | |||
| <div class="canvas-container"> | |||
| <canvas id="mcanvas3" class="mcanvas"></canvas> | |||
| </div> | |||
| <div class="canvas-container"> | |||
| <canvas id="mcanvas4" class="mcanvas"></canvas> | |||
| </div> | |||
| </div> | |||
| </body> | |||
| @@ -0,0 +1,37 @@ | |||
| import {_testFinish, ThreeViewer} from 'threepipe' | |||
| const models = [ | |||
| 'https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', | |||
| 'https://threejs.org/examples/models/fbx/Samba Dancing.fbx', | |||
| 'https://threejs.org/examples/models/draco/bunny.drc', | |||
| 'https://threejs.org/examples/models/gltf/kira.glb', | |||
| ] | |||
| async function init(i: number) { | |||
| const viewer = new ThreeViewer({ | |||
| canvas: document.getElementById('mcanvas' + (i + 1)) as HTMLCanvasElement, | |||
| msaa: true, | |||
| debug: true, | |||
| dropzone: { | |||
| allowedExtensions: ['gltf', 'glb', 'hdr', 'bin', 'png', 'jpeg', 'webp', 'jpg', 'exr'], | |||
| addOptions: { | |||
| disposeSceneObjects: true, | |||
| autoSetEnvironment: true, // when hdr is dropped | |||
| autoSetBackground: true, | |||
| }, | |||
| }, | |||
| }) | |||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', { | |||
| // setBackground: true, | |||
| }) | |||
| const result = await viewer.load(models[i], { | |||
| autoCenter: true, | |||
| autoScale: true, | |||
| }) | |||
| console.log(result) | |||
| } | |||
| Promise.all(new Array(4).fill(0).map(async(_, i) => init(i))).then(_testFinish) | |||
| @@ -9,7 +9,7 @@ | |||
| "version": "0.0.14", | |||
| "license": "Apache-2.0", | |||
| "dependencies": { | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz", | |||
| "@types/webxr": "^0.5.1", | |||
| "@types/wicg-file-system-access": "^2020.9.5", | |||
| "ts-browser-helpers": "^0.8.0" | |||
| @@ -684,9 +684,9 @@ | |||
| "dev": true | |||
| }, | |||
| "node_modules/@types/three": { | |||
| "version": "0.152.1016", | |||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||
| "integrity": "sha512-S4AczoUaWTfyh7ApgEXZWhhusqF9DGX8ynfIa8OzS0+ES0DmD1UQuyVQUmwOTxgTDGO10vc7zWrObZGPvM88NQ==", | |||
| "version": "0.152.1017", | |||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz", | |||
| "integrity": "sha512-iRThz0XfSleoy53jfLfos5bC1EyWc2dNrxXglVnIYU3ducMSjwS3iAdZehmlGMmiIpz3l1fc3xBpVOO4F8Z/Iw==", | |||
| "dependencies": { | |||
| "@tweenjs/tween.js": "~18.6.4", | |||
| "fflate": "~0.6.9", | |||
| @@ -10874,8 +10874,8 @@ | |||
| "dev": true | |||
| }, | |||
| "@types/three": { | |||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||
| "integrity": "sha512-S4AczoUaWTfyh7ApgEXZWhhusqF9DGX8ynfIa8OzS0+ES0DmD1UQuyVQUmwOTxgTDGO10vc7zWrObZGPvM88NQ==", | |||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz", | |||
| "integrity": "sha512-iRThz0XfSleoy53jfLfos5bC1EyWc2dNrxXglVnIYU3ducMSjwS3iAdZehmlGMmiIpz3l1fc3xBpVOO4F8Z/Iw==", | |||
| "requires": { | |||
| "@tweenjs/tween.js": "~18.6.4", | |||
| "fflate": "~0.6.9", | |||
| @@ -1,6 +1,6 @@ | |||
| { | |||
| "name": "threepipe", | |||
| "version": "0.0.14", | |||
| "version": "0.0.15", | |||
| "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", | |||
| "main": "src/index.ts", | |||
| "module": "dist/index.mjs", | |||
| @@ -102,7 +102,7 @@ | |||
| "popmotion": "^11.0.5" | |||
| }, | |||
| "dependencies": { | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz", | |||
| "@types/webxr": "^0.5.1", | |||
| "@types/wicg-file-system-access": "^2020.9.5", | |||
| "ts-browser-helpers": "^0.8.0" | |||
| @@ -113,8 +113,8 @@ | |||
| "ts-browser-helpers": "^0.8.0", | |||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2015/package.tgz", | |||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2015.tar.gz", | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1016.tar.gz", | |||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz", | |||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1017.tar.gz", | |||
| "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | |||
| }, | |||
| "local_dependencies": { | |||
| @@ -13,6 +13,7 @@ import { | |||
| import {downloadFile} from 'ts-browser-helpers' | |||
| import {MaterialExtension} from '../materials' | |||
| import {generateUUID, isInScene} from '../three' | |||
| import {LegacyPhongMaterial} from '../core/material/LegacyPhongMaterial' | |||
| /** | |||
| * Material Manager | |||
| @@ -25,6 +26,7 @@ export class MaterialManager<T = ''> extends EventDispatcher<BaseEvent, T> { | |||
| readonly templates: IMaterialTemplate[] = [ | |||
| PhysicalMaterial.MaterialTemplate, | |||
| UnlitMaterial.MaterialTemplate, | |||
| LegacyPhongMaterial.MaterialTemplate, | |||
| ] | |||
| private _materials: IMaterial[] = [] | |||
| @@ -54,7 +56,7 @@ export class MaterialManager<T = ''> extends EventDispatcher<BaseEvent, T> { | |||
| 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? | |||
| if (!t2) { | |||
| console.error('Template has no generator or materialType', template, nameOrType) | |||
| console.warn('Template has no generator or materialType', template, nameOrType) | |||
| return undefined | |||
| } | |||
| template = {...template, ...t2} | |||
| @@ -79,7 +79,7 @@ export interface IRenderManagerOptions { | |||
| alpha?: boolean, // default = true | |||
| targetOptions?: CreateRenderTargetOptions | |||
| rgbm?: boolean, | |||
| msaa?: boolean, | |||
| msaa?: boolean | number, | |||
| depthBuffer?: boolean, | |||
| renderScale?: number, | |||
| } | |||
| @@ -4,6 +4,7 @@ export {ExtendedShaderMaterial} from './material/ExtendedShaderMaterial' | |||
| export {PhysicalMaterial, type PhysicalMaterialEventTypes, MeshStandardMaterial2} from './material/PhysicalMaterial' | |||
| export {ShaderMaterial2} from './material/ShaderMaterial2' | |||
| export {UnlitMaterial, type UnlitMaterialEventTypes, MeshBasicMaterial2} from './material/UnlitMaterial' | |||
| export {LegacyPhongMaterial, type PhongMaterialEventTypes} from './material/LegacyPhongMaterial' | |||
| export {iObjectCommons} from './object/iObjectCommons' | |||
| export {iCameraCommons} from './object/iCameraCommons' | |||
| export {iGeometryCommons} from './geometry/iGeometryCommons' | |||
| @@ -28,6 +28,7 @@ import { | |||
| import {downloadBlob, uploadFile} from 'ts-browser-helpers' | |||
| import {PhysicalMaterial} from './PhysicalMaterial' | |||
| import {getEmptyMeta} from '../../utils/serialization' | |||
| import {LegacyPhongMaterial} from './LegacyPhongMaterial' | |||
| export const iMaterialUI = { | |||
| base: (material: IMaterial): UiObjectConfig[] => [ | |||
| @@ -279,7 +280,7 @@ export const iMaterialUI = { | |||
| ], | |||
| } | |||
| ), | |||
| bumpNormal: (material: PhysicalMaterial): UiObjectConfig => ( | |||
| bumpNormal: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => ( | |||
| { | |||
| type: 'folder', | |||
| label: 'Bump/Normal', | |||
| @@ -331,7 +332,7 @@ export const iMaterialUI = { | |||
| ], | |||
| } | |||
| ), | |||
| emission: (material: PhysicalMaterial): UiObjectConfig => ( | |||
| emission: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => ( | |||
| { | |||
| type: 'folder', | |||
| label: 'Emission', | |||
| @@ -0,0 +1,291 @@ | |||
| import { | |||
| Color, | |||
| IUniform, | |||
| Material, | |||
| MeshPhongMaterial, | |||
| MeshPhongMaterialParameters, | |||
| MultiplyOperation, | |||
| Shader, | |||
| Vector2, | |||
| WebGLRenderer, | |||
| } from 'three' | |||
| import {UiObjectConfig} from 'uiconfig.js' | |||
| import { | |||
| IMaterial, | |||
| IMaterialEvent, | |||
| IMaterialEventTypes, | |||
| IMaterialGenerator, | |||
| IMaterialParameters, | |||
| IMaterialTemplate, | |||
| } from '../IMaterial' | |||
| import {MaterialExtension} from '../../materials' | |||
| import {SerializationMetaType, shaderReplaceString, ThreeSerialization} from '../../utils' | |||
| import {ITexture} from '../ITexture' | |||
| import {iMaterialCommons, threeMaterialPropList} from './iMaterialCommons' | |||
| import {IObject3D} from '../IObject' | |||
| import {iMaterialUI} from './IMaterialUi' | |||
| import {makeSamplerUi} from '../../ui/image-ui' | |||
| export type PhongMaterialEventTypes = IMaterialEventTypes | '' | |||
| export class LegacyPhongMaterial extends MeshPhongMaterial<IMaterialEvent, PhongMaterialEventTypes> implements IMaterial<IMaterialEvent, PhongMaterialEventTypes> { | |||
| declare ['constructor']: typeof LegacyPhongMaterial | |||
| public static readonly TypeSlug = 'phongmat' | |||
| public static readonly TYPE = 'LegacyPhongMaterial' // not using .type because it is used by three.js | |||
| assetType = 'material' as const | |||
| public readonly isLegacyPhongMaterial = true | |||
| readonly appliedMeshes: Set<IObject3D> = new Set() | |||
| readonly setDirty = iMaterialCommons.setDirty | |||
| dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)} | |||
| clone(): this {return iMaterialCommons.clone(super.clone).call(this)} | |||
| dispatchEvent(event: IMaterialEvent): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)} | |||
| generator?: IMaterialGenerator | |||
| envMap: ITexture | null = null | |||
| constructor({customMaterialExtensions, ...parameters}: MeshPhongMaterialParameters & IMaterialParameters = {}) { | |||
| super(parameters) | |||
| !this.defines && (this.defines = {}) | |||
| this.fog = false | |||
| this.setDirty = this.setDirty.bind(this) | |||
| if (customMaterialExtensions) this.registerMaterialExtensions(customMaterialExtensions) | |||
| iMaterialCommons.upgradeMaterial.call(this) | |||
| } | |||
| // region Material Extension | |||
| materialExtensions: MaterialExtension[] = [] | |||
| extraUniformsToUpload: Record<string, IUniform> = {} | |||
| registerMaterialExtensions = iMaterialCommons.registerMaterialExtensions | |||
| unregisterMaterialExtensions = iMaterialCommons.unregisterMaterialExtensions | |||
| customProgramCacheKey(): string { | |||
| return super.customProgramCacheKey() + iMaterialCommons.customProgramCacheKey.call(this) | |||
| } | |||
| onBeforeCompile(shader: Shader, renderer: WebGLRenderer): void { // shader is not Shader but WebglUniforms.getParameters return value type so includes defines | |||
| const f = [ | |||
| ['vec3 outgoingLight = ', 'afterModulation'], // added markers before found substring | |||
| ['#include <aomap_fragment>', 'beforeModulation'], | |||
| ['ReflectedLight reflectedLight = ', 'beforeAccumulation'], | |||
| ['#include <clipping_planes_fragment>', 'mainStart'], | |||
| ] | |||
| const v = [ | |||
| ['#include <uv_vertex>', 'mainStart'], | |||
| ] | |||
| for (const vElement of v) shader.vertexShader = shaderReplaceString(shader.vertexShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0]) | |||
| for (const vElement of f) shader.fragmentShader = shaderReplaceString(shader.fragmentShader, vElement[0], '#glMarker ' + vElement[1] + '\n' + vElement[0]) | |||
| iMaterialCommons.onBeforeCompile.call(this, shader, renderer) | |||
| // ;(shader as any).defines.INVERSE_ALPHAMAP = this.userData.inverseAlphaMap ? 1 : 0 // todo | |||
| super.onBeforeCompile(shader, renderer) | |||
| } | |||
| // onBeforeRender(...args: Parameters<IMaterial['onBeforeRender']>): void { | |||
| // super.onBeforeRender(...args) | |||
| // iMaterialCommons.onBeforeRender.call(this, ...args) | |||
| // | |||
| // // const t = this.userData.inverseAlphaMap ? 1 : 0 // todo | |||
| // // if (t !== this.defines.INVERSE_ALPHAMAP) { | |||
| // // this.defines.INVERSE_ALPHAMAP = t | |||
| // // this.needsUpdate = true | |||
| // // } | |||
| // } | |||
| onBeforeRender = iMaterialCommons.onBeforeRenderOverride(super.onBeforeRender) | |||
| onAfterRender = iMaterialCommons.onAfterRenderOverride(super.onAfterRender) | |||
| // endregion | |||
| // region Serialization | |||
| /** | |||
| * Sets the values of this material based on the values of the passed material or an object with material properties | |||
| * The input is expected to be a valid material or a deserialized material parameters object(including the deserialized userdata) | |||
| * @param parameters - material or material parameters object | |||
| * @param allowInvalidType - if true, the type of the oldMaterial is not checked. Objects without type are always allowed. | |||
| * @param clearCurrentUserData - if undefined, then depends on material.isMaterial. if true, the current userdata is cleared before setting the new values, because it can have data which wont be overwritten if not present in the new material. | |||
| */ | |||
| setValues(parameters: Material|(MeshPhongMaterialParameters&{type?:string}), allowInvalidType = true, clearCurrentUserData: boolean|undefined = undefined): this { | |||
| if (!parameters) return this | |||
| if (parameters.type && !allowInvalidType && !['MeshPhongMaterial', 'MeshPhongMaterial2', this.constructor.TYPE].includes(parameters.type)) { | |||
| console.error('Material type is not supported:', parameters.type) | |||
| return this | |||
| } | |||
| if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial | |||
| if (clearCurrentUserData) this.userData = {} | |||
| iMaterialCommons.setValues(super.setValues).call(this, parameters) | |||
| this.userData.uuid = this.uuid | |||
| return this | |||
| } | |||
| copy(source: Material|any): this { | |||
| return this.setValues(source, false) | |||
| } | |||
| /** | |||
| * Serializes this material to JSON. | |||
| * @param meta - metadata for serialization | |||
| * @param _internal - Calls only super.toJSON, does internal three.js serialization and @serialize tags. Set it to true only if you know what you are doing. This is used in Serialization->serializer->material | |||
| */ | |||
| toJSON(meta?: SerializationMetaType, _internal = false): any { | |||
| if (_internal) return { | |||
| ...super.toJSON(meta), | |||
| ...ThreeSerialization.Serialize(this, meta, true), // this will serialize the properties of this class(like defined with @serialize and @serialize attribute) | |||
| } | |||
| return ThreeSerialization.Serialize(this, meta, false) // this will call toJSON again, but with baseOnly=true, that's why we set isThis to false. | |||
| } | |||
| /** | |||
| * Deserializes the material from JSON. | |||
| * Textures should be loaded and in meta.textures before calling this method. | |||
| * todo - needs to be tested | |||
| * @param data | |||
| * @param meta | |||
| * @param _internal | |||
| */ | |||
| fromJSON(data: any, meta?: SerializationMetaType, _internal = false): this | null { | |||
| if (_internal) { | |||
| ThreeSerialization.Deserialize(data, this, meta, true) | |||
| return this.setValues(data) | |||
| } | |||
| this.dispatchEvent({type: 'beforeDeserialize', data, meta, bubbleToObject: true, bubbleToParent: true}) | |||
| return this | |||
| } | |||
| // endregion | |||
| // region UI Config | |||
| // todo dispose ui config | |||
| uiConfig: UiObjectConfig = { | |||
| type: 'folder', | |||
| label: 'Phong Material', | |||
| uuid: 'MBM2_' + this.uuid, | |||
| expanded: true, | |||
| children: [ | |||
| ...iMaterialUI.base(this), | |||
| iMaterialUI.blending(this), | |||
| iMaterialUI.polygonOffset(this), | |||
| iMaterialUI.aoLightMap(this), | |||
| { | |||
| type: 'folder', | |||
| label: 'Specular', | |||
| children: [ | |||
| { | |||
| type: 'color', | |||
| property: [this, 'specular'], | |||
| }, | |||
| { | |||
| type: 'image', | |||
| property: [this, 'specularMap'], | |||
| }, | |||
| makeSamplerUi(this, 'specularMap'), | |||
| { | |||
| type: 'slider', | |||
| label: 'Shininess', | |||
| property: [this, 'shininess'], | |||
| bounds: [0, 100], | |||
| stepSize: 0.1, | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| label: 'Reflectivity', | |||
| property: [this, 'reflectivity'], | |||
| bounds: [0, 1], | |||
| stepSize: 0.01, | |||
| }, | |||
| { | |||
| type: 'slider', | |||
| label: 'Refraction Ratio', | |||
| property: [this, 'refractionRatio'], | |||
| bounds: [0, 3], | |||
| stepSize: 0.01, | |||
| }, | |||
| ], | |||
| }, | |||
| iMaterialUI.bumpNormal(this), | |||
| iMaterialUI.emission(this), | |||
| { | |||
| type: 'folder', | |||
| label: 'Env Map', | |||
| children: [ | |||
| { | |||
| type: 'image', | |||
| property: [this, 'envMap'], | |||
| }, | |||
| makeSamplerUi(this, 'envMap'), | |||
| { | |||
| type: 'slider', | |||
| label: 'Env Map Intensity', | |||
| property: [this, 'envMapIntensity'], | |||
| bounds: [0, 5], | |||
| stepSize: 0.01, | |||
| }, | |||
| ], | |||
| }, | |||
| ...iMaterialUI.misc(this), | |||
| ], | |||
| } | |||
| // endregion UI Config | |||
| // Class properties can also be listed with annotations like @serialize or @property | |||
| // used for serialization | |||
| static readonly MaterialProperties = { | |||
| ...threeMaterialPropList, | |||
| color: new Color(0xffffff), | |||
| specular: new Color(0x111111), | |||
| shininess: 30, | |||
| map: null, | |||
| lightMap: null, | |||
| lightMapIntensity: 1, | |||
| aoMap: null, | |||
| aoMapIntensity: 1, | |||
| emissive: new Color(0x000000), | |||
| emissiveIntensity: 1, | |||
| emissiveMap: null, | |||
| bumpMap: null, | |||
| bumpScale: 1, | |||
| normalMap: null, | |||
| normalMapType: 'TangentSpaceNormalMap', | |||
| normalScale: new Vector2(1, 1), | |||
| displacementMap: null, | |||
| displacementScale: 1, | |||
| displacementBias: 0, | |||
| specularMap: null, | |||
| alphaMap: null, | |||
| envMap: null, | |||
| combine: MultiplyOperation, | |||
| envMapIntensity: 1, | |||
| reflectivity: 1, | |||
| refractionRatio: 0.98, | |||
| wireframe: false, | |||
| wireframeLinewidth: 1, | |||
| wireframeLinecap: 'round', | |||
| wireframeLinejoin: 'round', | |||
| skinning: false, | |||
| fog: true, | |||
| flatShading: false, | |||
| } | |||
| static MaterialTemplate: IMaterialTemplate<LegacyPhongMaterial, Partial<typeof LegacyPhongMaterial.MaterialProperties>> = { | |||
| materialType: LegacyPhongMaterial.TYPE, | |||
| name: 'phong', | |||
| typeSlug: LegacyPhongMaterial.TypeSlug, | |||
| alias: ['phong', 'legacy-phong', LegacyPhongMaterial.TYPE, LegacyPhongMaterial.TypeSlug, 'MeshPhongMaterial', 'MeshPhongMaterial2', 'PhongMaterial'], | |||
| params: { | |||
| color: new Color(1, 1, 1), | |||
| }, | |||
| generator: (params) => { | |||
| return new LegacyPhongMaterial(params) | |||
| }, | |||
| } | |||
| } | |||
| @@ -211,6 +211,7 @@ export class PhysicalMaterial extends MeshPhysicalMaterial<IMaterialEvent, Physi | |||
| // endregion | |||
| // used for serialization | |||
| static readonly MaterialProperties = { | |||
| // keep updated with properties in MeshStandardMaterial.js | |||
| ...threeMaterialPropList, | |||
| @@ -18,8 +18,7 @@ import { | |||
| IMaterialTemplate, | |||
| } from '../IMaterial' | |||
| import {MaterialExtension} from '../../materials' | |||
| import {shaderReplaceString} from '../../utils/shader-helpers' | |||
| import {SerializationMetaType, ThreeSerialization} from '../../utils/serialization' | |||
| import {SerializationMetaType, shaderReplaceString, ThreeSerialization} from '../../utils' | |||
| import {ITexture} from '../ITexture' | |||
| import {iMaterialCommons, threeMaterialPropList} from './iMaterialCommons' | |||
| import {IObject3D} from '../IObject' | |||
| @@ -180,6 +179,7 @@ export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMateri | |||
| // Class properties can also be listed with annotations like @serialize or @property | |||
| // used for serialization | |||
| static readonly MaterialProperties = { | |||
| ...threeMaterialPropList, | |||
| @@ -202,7 +202,7 @@ export class UnlitMaterial extends MeshBasicMaterial<IMaterialEvent, UnlitMateri | |||
| wireframeLinejoin: 'round', | |||
| skinning: false, | |||
| fog: true, | |||
| flatShading: false, | |||
| } | |||
| static MaterialTemplate: IMaterialTemplate<UnlitMaterial, Partial<typeof UnlitMaterial.MaterialProperties>> = { | |||
| @@ -1,4 +1,6 @@ | |||
| import {AViewerPluginSync, ThreeViewer} from '../../viewer' | |||
| // noinspection ES6PreferShortImport | |||
| import {AViewerPluginSync} from '../../viewer/AViewerPlugin' | |||
| import type {ThreeViewer} from '../../viewer' | |||
| import {MaterialExtension} from '../../materials' | |||
| import {uiDropdown, uiFolderContainer, uiSlider, uiToggle} from 'uiconfig.js' | |||
| import { | |||
| @@ -134,7 +134,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren | |||
| // renderer.autoClearDepth = false | |||
| ud.transmissionRenderTarget = writeBuffer | |||
| ud.blurTransmissionTarget = this.blurTransmissionTarget | |||
| ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa | |||
| renderer.renderWithModes({ | |||
| shadowMapRender: false, | |||
| @@ -227,7 +227,7 @@ export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'ren | |||
| // renderer.autoClearDepth = false | |||
| ud.transmissionRenderTarget = needsSwap ? writeBuffer : readBuffer | |||
| ud.blurTransmissionTarget = this.blurTransmissionTarget | |||
| ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa | |||
| renderer.renderWithModes({ | |||
| shadowMapRender: false, | |||
| @@ -1,6 +1,7 @@ | |||
| import {IGeometry, IMaterial, IObject3D} from '../../core' | |||
| import {BufferAttribute, InstancedMesh} from 'three' | |||
| import {copyObject3DUserData} from '../../utils' | |||
| // noinspection ES6PreferShortImport | |||
| import {copyObject3DUserData} from '../../utils/serialization' | |||
| export function autoGPUInstanceMeshes(matOrGeom: IMaterial|IGeometry) { | |||
| if (!(<IMaterial>matOrGeom).isMaterial && !(<IGeometry>matOrGeom).isBufferGeometry) return | |||
| @@ -5,6 +5,7 @@ export class GLStatsJS { | |||
| constructor(private _container: HTMLElement) { | |||
| this._stats.dom.id = 'stats-js' | |||
| this._stats.dom.style.position = 'absolute' | |||
| this._stats.dom.style.left = 'unset' | |||
| this._stats.dom.style.right = '0' | |||
| @@ -1,4 +1,4 @@ | |||
| import {ISerializedConfig, ThreeViewer} from './ThreeViewer' | |||
| import type {ISerializedConfig, ThreeViewer} from './ThreeViewer' | |||
| import {Event, EventDispatcher} from 'three' | |||
| import {SerializationMetaType, ThreeSerialization} from '../utils' | |||
| import {IViewerPlugin, IViewerPluginAsync} from './IViewerPlugin' | |||
| @@ -48,12 +48,13 @@ import { | |||
| RootSceneImportResult, | |||
| } from '../assetmanager' | |||
| import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin' | |||
| // noinspection ES6PreferShortImport | |||
| import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | |||
| import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | |||
| import {IRenderTarget} from '../rendering' | |||
| import type {ProgressivePlugin} from '../plugins' | |||
| import {TonemapPlugin} from '../plugins' | |||
| // noinspection ES6PreferShortImport | |||
| import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin' | |||
| // noinspection ES6PreferShortImport | |||
| import {TonemapPlugin} from '../plugins/postprocessing/TonemapPlugin' | |||
| import {VERSION} from './version' | |||
| export type IViewerEvent = BaseEvent & { | |||
| @@ -270,7 +271,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes | |||
| * Create a viewer instance for using the webgi viewer SDK. | |||
| * @param options - {@link ThreeViewerOptions} | |||
| */ | |||
| constructor({debug = true, ...options}: ThreeViewerOptions) { | |||
| constructor({debug = false, ...options}: ThreeViewerOptions) { | |||
| super() | |||
| this.debug = debug | |||
| this._canvas = options.canvas || createCanvasElement() | |||
| @@ -1,12 +1,12 @@ | |||
| import {IRenderTarget, RenderManager} from '../rendering' | |||
| import {HalfFloatType, NoColorSpace, RGBM16ColorSpace, UnsignedByteType} from 'three' | |||
| import {HalfFloatType, LinearMipMapLinearFilter, NoColorSpace, RGBM16ColorSpace, UnsignedByteType} from 'three' | |||
| import {IRenderManagerOptions} from '../core' | |||
| import {ExtendedRenderPass, ScreenPass, TViewerScreenShader} from '../postprocessing' | |||
| import {uiFolderContainer} from 'uiconfig.js' | |||
| export interface ViewerRenderManagerOptions extends IRenderManagerOptions { | |||
| rgbm?: boolean, | |||
| msaa?: boolean, | |||
| msaa?: boolean | number, | |||
| depthBuffer?: boolean, | |||
| zPrepass?: boolean, | |||
| screenShader?: TViewerScreenShader | |||
| @@ -15,7 +15,7 @@ export interface ViewerRenderManagerOptions extends IRenderManagerOptions { | |||
| @uiFolderContainer('Render Manager') | |||
| export class ViewerRenderManager extends RenderManager { | |||
| readonly rgbm: boolean | |||
| readonly msaa: boolean | |||
| readonly msaa: boolean | number | |||
| readonly depthBuffer: boolean | |||
| readonly zPrepass: boolean | |||
| readonly renderPass: ExtendedRenderPass | |||
| @@ -25,10 +25,12 @@ export class ViewerRenderManager extends RenderManager { | |||
| super({ | |||
| ...options, | |||
| targetOptions: { | |||
| samples: msaa ? 4 : 0, | |||
| samples: msaa ? typeof msaa !== 'number' ? 4 : msaa : 0, | |||
| 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 | |||
| }, | |||
| }) | |||
| this.rgbm = rgbm | |||
| @@ -1 +1 @@ | |||
| export const VERSION = '0.0.14' | |||
| export const VERSION = '0.0.15' | |||