| "rollup-plugin-glsl": "^1.3.0", | "rollup-plugin-glsl": "^1.3.0", | ||||
| "rollup-plugin-license": "^3.0.1", | "rollup-plugin-license": "^3.0.1", | ||||
| "rollup-plugin-postcss": "^4.0.2", | "rollup-plugin-postcss": "^4.0.2", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2020/package.tgz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "tslib": "^2.5.0", | "tslib": "^2.5.0", | ||||
| "typedoc": "^0.25.7", | "typedoc": "^0.25.7", | ||||
| "typescript": "^5.3.3", | "typescript": "^5.3.3", | ||||
| "dependencies": { | "dependencies": { | ||||
| "uiconfig.js": "^0.0.12", | "uiconfig.js": "^0.0.12", | ||||
| "ts-browser-helpers": "^0.12.0", | "ts-browser-helpers": "^0.12.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2020/package.tgz", | |||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2020.tar.gz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2021/package.tgz", | |||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2021.tar.gz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1020/package.tgz", | ||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1020.tar.gz", | "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1020.tar.gz", | ||||
| "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" | "@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three" |
| const scenes = result.scenes || (result.scene ? [result.scene] : []) | const scenes = result.scenes || (result.scene ? [result.scene] : []) | ||||
| scenes.forEach(s=>{ | scenes.forEach(s=>{ | ||||
| s.traverse((o: any)=>{ | s.traverse((o: any)=>{ | ||||
| if (!o.isObject3D) return | |||||
| if (!o || !o.isObject3D) return | |||||
| const ext = o.userData?.gltfExtensions?.[this.WebGiObject3DExtrasExtension] | const ext = o.userData?.gltfExtensions?.[this.WebGiObject3DExtrasExtension] | ||||
| if (!ext) { | if (!ext) { | ||||
| if (o.isLight && !o.isAmbientLight) o.castShadow = true | if (o.isLight && !o.isAmbientLight) o.castShadow = true |
| const getDependency = parser.getDependency | const getDependency = parser.getDependency | ||||
| parser.getDependency = async(type: string, index: number) => { | parser.getDependency = async(type: string, index: number) => { | ||||
| const res = await getDependency.call(parser, type, index) | const res = await getDependency.call(parser, type, index) | ||||
| if (res.userData) { | |||||
| if (res && res.userData) { | |||||
| const gltfExtensions = res.userData.gltfExtensions | const gltfExtensions = res.userData.gltfExtensions | ||||
| delete res.userData.gltfExtensions | delete res.userData.gltfExtensions | ||||
| res.userData = ThreeSerialization.Deserialize(res.userData, {}) | res.userData = ThreeSerialization.Deserialize(res.userData, {}) |
| // // todo gizmos | // // todo gizmos | ||||
| // } | // } | ||||
| render(scene: IScene, renderToScreen = true): void { | |||||
| /** | |||||
| * Default value for renderToScreen in {@link render} | |||||
| */ | |||||
| defaultRenderToScreen = true | |||||
| render(scene: IScene, renderToScreen?: boolean): void { | |||||
| if (this._passesNeedsUpdate) { | if (this._passesNeedsUpdate) { | ||||
| this._refreshPipeline() | this._refreshPipeline() | ||||
| this.refreshPasses() | this.refreshPasses() | ||||
| for (const pass of this._passes) { | for (const pass of this._passes) { | ||||
| if (pass.enabled && pass.beforeRender) pass.beforeRender(scene, scene.renderCamera, this) | if (pass.enabled && pass.beforeRender) pass.beforeRender(scene, scene.renderCamera, this) | ||||
| } | } | ||||
| this._composer.renderToScreen = renderToScreen | |||||
| this._composer.renderToScreen = renderToScreen ?? this.defaultRenderToScreen | |||||
| this._composer.render() | this._composer.render() | ||||
| this._composer.renderToScreen = true | this._composer.renderToScreen = true | ||||
| if (renderToScreen) { | if (renderToScreen) { |
| if (meta?.textures[obj.uuid]) return {uuid: obj.uuid, resource: 'textures'} | if (meta?.textures[obj.uuid]) return {uuid: obj.uuid, resource: 'textures'} | ||||
| const imgData = obj.source.data | const imgData = obj.source.data | ||||
| const hasRootPath = !obj.isRenderTargetTexture && obj.userData.rootPath | const hasRootPath = !obj.isRenderTargetTexture && obj.userData.rootPath | ||||
| if (hasRootPath) { | |||||
| if (obj.source.data) { | |||||
| if (!obj.userData.embedUrlImagePreviews) // todo make sure its only Texture, check for svg etc | |||||
| obj.source.data = null // handled in GLTFWriter2.processImage | |||||
| else { | |||||
| obj.source.data = textureToCanvas(obj, 16, obj.flipY) // todo: check flipY | |||||
| let res = {} as any | |||||
| const ud = obj.userData | |||||
| try { // need try catch here because of hasRootPath | |||||
| if (hasRootPath) { | |||||
| if (obj.source.data) { | |||||
| if (!obj.userData.embedUrlImagePreviews) // todo make sure its only Texture, check for svg etc | |||||
| obj.source.data = null // handled in GLTFWriter2.processImage | |||||
| else { | |||||
| obj.source.data = textureToCanvas(obj, 16, obj.flipY) // todo: check flipY | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| obj.userData = {} // toJSON will call JSON.stringify, which will serialize userData | |||||
| const meta2 = {images: {} as any} // in-case meta is undefined | |||||
| res = obj.toJSON(meta || meta2) | |||||
| if (!meta && res.image) res.image = hasRootPath && !obj.userData.embedUrlImagePreviews ? undefined : meta2.images[res.image] | |||||
| res.userData = Serialization.Serialize(copyTextureUserData({}, ud), meta, false) | |||||
| } catch (e) { | |||||
| console.error('Threepipe Serialization: Unable to serialize texture') | |||||
| console.error(e) | |||||
| } | } | ||||
| const ud = obj.userData | |||||
| obj.userData = {} // toJSON will call JSON.stringify, which will serialize userData | |||||
| const meta2 = {images: {} as any} // in-case meta is undefined | |||||
| let res = obj.toJSON(meta || meta2) | |||||
| if (!meta && res.image) res.image = hasRootPath && !obj.userData.embedUrlImagePreviews ? undefined : meta2.images[res.image] | |||||
| obj.userData = ud | |||||
| res.userData = Serialization.Serialize(copyTextureUserData({}, ud), meta, false) | |||||
| obj.userData = ud // should be outside try catch | |||||
| if (hasRootPath) { | if (hasRootPath) { | ||||
| if (meta && !obj.userData.embedUrlImagePreviews) delete meta.images[obj.source.uuid] // because its empty. uuid still stored in the texture.image | if (meta && !obj.userData.embedUrlImagePreviews) delete meta.images[obj.source.uuid] // because its empty. uuid still stored in the texture.image | ||||
| obj.source.data = imgData | obj.source.data = imgData | ||||
| } | } | ||||
| if (meta?.textures && !res.resource) { | |||||
| if (meta?.textures && res && !res.resource) { | |||||
| if (!meta.textures[res.uuid]) | if (!meta.textures[res.uuid]) | ||||
| meta.textures[res.uuid] = res | meta.textures[res.uuid] = res | ||||
| res = {uuid: res.uuid, resource: 'textures'} | res = {uuid: res.uuid, resource: 'textures'} | ||||
| // Serialize without userData because three.js tries to convert it to string. We are serializing it separately | // Serialize without userData because three.js tries to convert it to string. We are serializing it separately | ||||
| const userData = obj.userData | const userData = obj.userData | ||||
| obj.userData = {} | obj.userData = {} | ||||
| let res = obj.toJSON(meta, true) // copying userData is handled in toJSON, see MeshStandardMaterial2 | |||||
| let res = {} as any | |||||
| try { | |||||
| res = obj.toJSON(meta, true) // copying userData is handled in toJSON, see MeshStandardMaterial2 | |||||
| serializeMaterialUserData(res, userData, meta) | |||||
| res.userData.uuid = userData.uuid | |||||
| // todo: override generator to mention that this is a custom serializer? | |||||
| if (obj.constructor.TYPE) res.type = obj.constructor.TYPE // override type if specified as static property in the class | |||||
| // Remove undefined values. Note that null values are kept. | |||||
| for (const key of Object.keys(res)) if (res[key] === undefined) delete res[key] | |||||
| } catch (e) { | |||||
| console.error('Threepipe Serialization: Unable to serialize material') | |||||
| console.error(e) | |||||
| } | |||||
| obj.userData = userData | obj.userData = userData | ||||
| serializeMaterialUserData(res, userData, meta) | |||||
| // todo: override generator to mention that this is a custom serializer? | |||||
| res.userData.uuid = obj.userData.uuid | |||||
| if (obj.constructor.TYPE) res.type = obj.constructor.TYPE // override type if specified as static property in the class | |||||
| // Remove undefined values. Note that null values are kept. | |||||
| for (const key of Object.keys(res)) if (res[key] === undefined) delete res[key] | |||||
| // Restore textures | // Restore textures | ||||
| for (const [k, v] of Object.entries(tempTextures)) { | for (const [k, v] of Object.entries(tempTextures)) { | ||||
| obj[k] = v | obj[k] = v | ||||
| } | } | ||||
| // Add material, textures, images to meta | // Add material, textures, images to meta | ||||
| // serialize textures are already added to meta by the texture serializer | // serialize textures are already added to meta by the texture serializer | ||||
| if (meta) { | |||||
| for (const [k, v] of Object.entries(objTextures)) { | |||||
| if (v) res[k] = v // can be undefined because of RenderTargetTexture... | |||||
| } | |||||
| if (meta.materials) { | |||||
| if (!meta.materials[res.uuid]) | |||||
| meta.materials[res.uuid] = res | |||||
| res = {uuid: res.uuid, resource: 'materials'} | |||||
| } | |||||
| } else { | |||||
| for (const [k, v] of Object.entries(objTextures)) { | |||||
| if (v) res[k] = (v as any).uuid // to remain compatible with how three.js saves | |||||
| if (res) { | |||||
| if (meta) { | |||||
| for (const [k, v] of Object.entries(objTextures)) { | |||||
| if (v) res[k] = v // can be undefined because of RenderTargetTexture... | |||||
| } | |||||
| if (meta.materials) { | |||||
| if (!meta.materials[res.uuid]) | |||||
| meta.materials[res.uuid] = res | |||||
| res = {uuid: res.uuid, resource: 'materials'} | |||||
| } | |||||
| } else { | |||||
| for (const [k, v] of Object.entries(objTextures)) { | |||||
| if (v) res[k] = (v as any).uuid // to remain compatible with how three.js saves | |||||
| } | |||||
| res.textures = Object.values(meta2.textures) | |||||
| res.images = Object.values(meta2.images) | |||||
| } | } | ||||
| res.textures = Object.values(meta2.textures) | |||||
| res.images = Object.values(meta2.images) | |||||
| } | } | ||||
| return res | return res | ||||
| }, | }, |
| import { | import { | ||||
| BaseEvent, | BaseEvent, | ||||
| CanvasTexture, | |||||
| Color, | Color, | ||||
| Event, | Event, | ||||
| EventDispatcher, | EventDispatcher, | ||||
| * Use rendered gbuffer as depth-prepass / z-prepass. | * Use rendered gbuffer as depth-prepass / z-prepass. | ||||
| */ | */ | ||||
| zPrepass?: boolean | zPrepass?: boolean | ||||
| /** | |||||
| * Force z-prepass even if there are transparent/transmissive objects with render to depth buffer enabled. | |||||
| */ | |||||
| forceZPrepass?: boolean // todo | |||||
| /* | /* | ||||
| * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | * Render scale, 1 = full resolution, 0.5 = half resolution, 2 = double resolution. | ||||
| public maxFramePerLoop = 1 | public maxFramePerLoop = 1 | ||||
| readonly debug: boolean | readonly debug: boolean | ||||
| /** | |||||
| * Number of times to run composer render. If set to more than 1, preRender and postRender events will also be called multiple times. | |||||
| */ | |||||
| rendersPerFrame = 1 | |||||
| /** | /** | ||||
| * Get the HTML Element containing the canvas | * Get the HTML Element containing the canvas | ||||
| * @returns {HTMLElement} | * @returns {HTMLElement} | ||||
| // Check if the renderManger is dirty, which happens when it's reset above or if any pass in the composer is dirty | // Check if the renderManger is dirty, which happens when it's reset above or if any pass in the composer is dirty | ||||
| const needsRender = this.renderManager.needsRender | const needsRender = this.renderManager.needsRender | ||||
| if (needsRender) { | if (needsRender) { | ||||
| for (let j = 0; j < this.rendersPerFrame; j++) { | |||||
| this.dispatchEvent({type: 'preRender', target: this}) | |||||
| try { | |||||
| this._scene.renderCamera = this._scene.mainCamera | |||||
| this.renderManager.render(this._scene, this.renderManager.defaultRenderToScreen) | |||||
| } catch (e) { | |||||
| this.console.error(e) | |||||
| if (this.debug) throw e | |||||
| // this.enabled = false | |||||
| } | |||||
| this.dispatchEvent({type: 'preRender', target: this}) | |||||
| try { | |||||
| this._scene.renderCamera = this._scene.mainCamera | |||||
| this.renderManager.render(this._scene) | |||||
| } catch (e) { | |||||
| this.console.error(e) | |||||
| if (this.debug) throw e | |||||
| // this.enabled = false | |||||
| this.dispatchEvent({type: 'postRender', target: this}) | |||||
| } | } | ||||
| this.dispatchEvent({type: 'postRender', target: this}) | |||||
| } | } | ||||
| this.dispatchEvent({type: 'postFrame', target: this}) | this.dispatchEvent({type: 'postFrame', target: this}) | ||||
| await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: ((<OrbitControls3> this.scene.mainCamera.controls)?.minDistance ?? 0.5) + 0.5, max: 1000.0}) | await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: ((<OrbitControls3> this.scene.mainCamera.controls)?.minDistance ?? 0.5) + 0.5, max: 1000.0}) | ||||
| } | } | ||||
| private _canvasTexture?: CanvasTexture&ITexture | |||||
| /** | |||||
| * Create and get a three.js CanvasTexture from the viewer's canvas. | |||||
| */ | |||||
| get canvasTexture(): CanvasTexture { | |||||
| if (!this._canvas) throw new Error('Canvas not found') | |||||
| if (!this._canvasTexture) { | |||||
| this._canvasTexture = new CanvasTexture(this._canvas) | |||||
| this._canvasTexture.flipY = false | |||||
| this._canvasTexture.needsUpdate = true | |||||
| } | |||||
| return this._canvasTexture | |||||
| } | |||||
| // todo: create/load texture utils | // todo: create/load texture utils | ||||
| // region legacy creation functions | // region legacy creation functions |