Sfoglia il codice sorgente

Simplify gltf extension registration for plugins

master
Palash Bansal 1 anno fa
parent
commit
3dddf9c87a
Nessun account collegato all'indirizzo email del committer

+ 2
- 2
package-lock.json Vedi File

{ {
"name": "threepipe", "name": "threepipe",
"version": "0.0.35-dev",
"version": "0.0.35",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "threepipe", "name": "threepipe",
"version": "0.0.35-dev",
"version": "0.0.35",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz", "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.153.1002/package.tgz",

+ 1
- 1
package.json Vedi File

{ {
"name": "threepipe", "name": "threepipe",
"version": "0.0.35-dev",
"version": "0.0.35",
"description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.", "description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/index.mjs", "module": "dist/index.mjs",

+ 89
- 48
plugins/gltf-transform/src/GLTFDracoExportPlugin.ts Vedi File

import { import {
AssetExporterPlugin, AssetExporterPlugin,
AViewerPluginSync, AViewerPluginSync,
ClearcoatTintPlugin,
CustomBumpMapPlugin,
DRACOLoader2, DRACOLoader2,
generateUUID, generateUUID,
GLTFLightExtrasExtension, GLTFLightExtrasExtension,
GLTFMaterialsDisplacementMapExtension, GLTFMaterialsDisplacementMapExtension,
GLTFMaterialsLightMapExtension, GLTFMaterialsLightMapExtension,
GLTFObject3DExtrasExtension, GLTFObject3DExtrasExtension,
NoiseBumpMaterialPlugin,
IExporter,
ThreeViewer, ThreeViewer,
clearCoatTintGLTFExtension,
customBumpMapGLTFExtension,
noiseBumpMaterialGLTFExtension,
fragmentClippingGLTFExtension,
} from 'threepipe' } from 'threepipe'
import {GLTFDracoExporter} from './GLTFDracoExporter' import {GLTFDracoExporter} from './GLTFDracoExporter'
import {UiObjectConfig} from 'uiconfig.js' import {UiObjectConfig} from 'uiconfig.js'
public static readonly PluginType = 'GLTFDracoExportPlugin' public static readonly PluginType = 'GLTFDracoExportPlugin'
enabled = true enabled = true


/**
* These are added here, but also added as plugins. Added here by default so that the data is not lost if some plugin is not added in an app.
* To explicitly remove the data, use `removeExtension` with the name of the extension
*/
extraExtensions = [
[GLTFMaterialsBumpMapExtension.WebGiMaterialsBumpMapExtension, GLTFMaterialsBumpMapExtension.Textures],
[GLTFMaterialsLightMapExtension.WebGiMaterialsLightMapExtension, GLTFMaterialsLightMapExtension.Textures],
[GLTFMaterialsAlphaMapExtension.WebGiMaterialsAlphaMapExtension, GLTFMaterialsAlphaMapExtension.Textures],
[GLTFMaterialsDisplacementMapExtension.WebGiMaterialsDisplacementMapExtension, GLTFMaterialsDisplacementMapExtension.Textures],
[customBumpMapGLTFExtension.name, customBumpMapGLTFExtension.textures],
[GLTFLightExtrasExtension.WebGiLightExtrasExtension, GLTFLightExtrasExtension.Textures],
[GLTFObject3DExtrasExtension.WebGiObject3DExtrasExtension, GLTFObject3DExtrasExtension.Textures],
[GLTFMaterialExtrasExtension.WebGiMaterialExtrasExtension, GLTFMaterialExtrasExtension.Textures],
[clearCoatTintGLTFExtension.name, clearCoatTintGLTFExtension.textures],
[noiseBumpMaterialGLTFExtension.name, noiseBumpMaterialGLTFExtension.textures],
[fragmentClippingGLTFExtension.name, fragmentClippingGLTFExtension.textures],

// extenal plugins

// AnisotropyMaterialExtension
['WEBGI_materials_anisotropy', {
anisotropyDirection: 'RGB',
}],
// todo port
// DiamondMaterialExtension
// AnimationMarkersExtension
// ThinFilmLayerMaterialExtension
// TriplanarMappingMaterialExtension
// SSBevelMaterialExtension
] as [string, Record<string, string|number>|undefined][]

addExtension(name: string, textures?: Record<string, string|number>) {
const ext = this.extraExtensions.findIndex(e => e[0] === name)
if (ext >= 0) this.extraExtensions[ext] = [name, textures]
else this.extraExtensions.push([name, textures])
}

/**
* Note - don't remove an extension when removing a plugin.
*
* extensions can be removed if you don't want to save the data of some plugin when transforming glb. But since this is not desirable in most cases, it is not recommended.
* @param name
*/
removeExtension(name: string) {
const ext = this.extraExtensions.findIndex(e => e[0] === name)
if (ext >= 0) this.extraExtensions.splice(ext, 1)
}

private _lastExporter?: IExporter['ctor'] = undefined

protected _ctor: IExporter['ctor'] = (_, _exporter) => {
if (!this._viewer) throw new Error('Viewer not set')
const tempFile = generateUUID() + '.drc' // dummy
const ex = new GLTFDracoExporter({},
// todo unregister on dispose
this._viewer.assetManager.importer.registerFile(tempFile) as DRACOLoader2)
ex.setup(this._viewer, _exporter.extensions)
for (const [ext, config] of this.extraExtensions) {
ex.createAndAddExtension(ext, config)
}
return ex
}

onAdded(viewer: ThreeViewer): void { onAdded(viewer: ThreeViewer): void {
super.onAdded(viewer) super.onAdded(viewer)
const importer = viewer.assetManager.importer
const exporter = viewer.assetManager.exporter const exporter = viewer.assetManager.exporter


const glbExporter = exporter.getExporter('glb')
if (glbExporter) exporter.removeExporter(glbExporter)

// todo remove exporter and add back the old one on plugin remove.
exporter.addExporter({
...glbExporter || {
let glbExporter = exporter.getExporter('glb')
this._lastExporter = glbExporter?.ctor
if (!glbExporter) {
console.error('GLTFDracoExportPlugin: GLB exporter not found in AssetManager.exporter, creating a new one.')
glbExporter = {
ext: ['glb', 'gltf'], ext: ['glb', 'gltf'],
extensions: [], extensions: [],
}, // for extensions
ctor: (_, _exporter) => {
const tempFile = generateUUID() + '.drc' // dummy
const ex = new GLTFDracoExporter({},
// todo unregister on dispose
importer.registerFile(tempFile) as DRACOLoader2)
ex.setup(viewer, _exporter.extensions)
ex.createAndAddExtension(GLTFMaterialsBumpMapExtension.WebGiMaterialsBumpMapExtension, {
bumpTexture: 'R',
})
ex.createAndAddExtension(GLTFMaterialsLightMapExtension.WebGiMaterialsLightMapExtension, {
lightMapTexture: 'RGB',
})
ex.createAndAddExtension(GLTFMaterialsAlphaMapExtension.WebGiMaterialsAlphaMapExtension, {
alphaTexture: 'G',
})
ex.createAndAddExtension(GLTFMaterialsDisplacementMapExtension.WebGiMaterialsDisplacementMapExtension, {
displacementTexture: 'R',
})
ex.createAndAddExtension(CustomBumpMapPlugin.CUSTOM_BUMP_MAP_GLTF_EXTENSION, {
customBumpMap: 'RGB',
})
ex.createAndAddExtension(GLTFLightExtrasExtension.WebGiLightExtrasExtension)
ex.createAndAddExtension(GLTFObject3DExtrasExtension.WebGiObject3DExtrasExtension)
ex.createAndAddExtension(GLTFMaterialExtrasExtension.WebGiMaterialExtrasExtension)
ex.createAndAddExtension(ClearcoatTintPlugin.CLEARCOAT_TINT_GLTF_EXTENSION)
ex.createAndAddExtension(NoiseBumpMaterialPlugin.NOISE_BUMP_MATERIAL_GLTF_EXTENSION)
// todo port
// DiamondMaterialExtension
// AnimationMarkersExtension
// AnisotropyMaterialExtension
// ThinFilmLayerMaterialExtension
// TriplanarMappingMaterialExtension
// SSBevelMaterialExtension
return ex
},
})
ctor: this._ctor,
}
exporter.addExporter(glbExporter)
} else {
glbExporter.ctor = this._ctor
}


// for ui
// for ui. todo use viewer.forPlugin
const exportPlugin = viewer.getPlugin(AssetExporterPlugin) const exportPlugin = viewer.getPlugin(AssetExporterPlugin)
if (exportPlugin) { if (exportPlugin) {
Object.assign(exportPlugin.exportOptions, { Object.assign(exportPlugin.exportOptions, {
} }
} }


onRemove(viewer: ThreeViewer) {
const exporter = viewer.assetManager.exporter
const glbExporter = exporter.getExporter('glb')
if (glbExporter && this._lastExporter) {
glbExporter.ctor = this._lastExporter
}
super.onRemove(viewer)
}

protected _makeUi = (exporter: AssetExporterPlugin)=>[ protected _makeUi = (exporter: AssetExporterPlugin)=>[
{ {
type: 'checkbox', type: 'checkbox',

+ 68
- 11
src/assetmanager/AssetManager.ts Vedi File

import {ILoader} from './IImporter' import {ILoader} from './IImporter'
import {AssetExporter} from './AssetExporter' import {AssetExporter} from './AssetExporter'
import {IExporter} from './IExporter' import {IExporter} from './IExporter'
import {GLTFExporter2} from './export'
import {GLTFExporter2, GLTFWriter2} from './export'
import {legacySeparateMapSamplerUVFix} from '../utils/legacy' import {legacySeparateMapSamplerUVFix} from '../utils/legacy'
import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader'
import {GLTFExporterPlugin} from 'three/examples/jsm/exporters/GLTFExporter'


export interface AssetManagerOptions{ export interface AssetManagerOptions{
/** /**
this._sceneUpdated = this._sceneUpdated.bind(this) this._sceneUpdated = this._sceneUpdated.bind(this)
this.addAsset = this.addAsset.bind(this) this.addAsset = this.addAsset.bind(this)
this.addRaw = this.addRaw.bind(this) this.addRaw = this.addRaw.bind(this)
this._loaderCreate = this._loaderCreate.bind(this)
this.addImported = this.addImported.bind(this) this.addImported = this.addImported.bind(this)


this.importer = new AssetImporter(!!viewer.getPlugin('debug')) this.importer = new AssetImporter(!!viewer.getPlugin('debug'))
this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated) this.viewer.scene.addEventListener('beforeDeserialize', this._sceneUpdated)
this._initCacheStorage(simpleCache, storage ?? true) this._initCacheStorage(simpleCache, storage ?? true)


this._setupGltfExtensions()
this._setupObjectProcess() this._setupObjectProcess()
this._setupProcessState() this._setupProcessState()
this._addImporters() this._addImporters()


} }


private _gltfExporter = {
ext: ['gltf', 'glb'],
extensions: [] as (typeof GLTFExporter2.ExportExtensions)[number][],
ctor: (_, exporter) => {
const ex = new GLTFExporter2()
// This should be added at the end.
ex.setup(this.viewer, exporter.extensions)
return ex
},
} satisfies IExporter

protected _addExporters() { protected _addExporters() {
const exporters: IExporter[] = [
{
ext: ['gltf', 'glb'], extensions: [], ctor: (_, exporter) => {
const ex = new GLTFExporter2()
// This should be added at the end.
ex.setup(this.viewer, exporter.extensions)
return ex
},
},
]
const exporters: IExporter[] = [this._gltfExporter]


this.exporter.addExporter(...exporters) this.exporter.addExporter(...exporters)
} }
}) })
} }


// region glTF extensions registration helpers

gltfExtensions: {
name: string
import: (parser: GLTFParser) => GLTFLoaderPlugin,
export: (parser: GLTFWriter2) => GLTFExporterPlugin,
textures?: Record<string, string|number> // see GLTFDracoExportPlugin
}[] = []

protected _setupGltfExtensions() {
this.importer.addEventListener('loaderCreate', this._loaderCreate as any)
this.viewer.forPlugin('GLTFDracoExportPlugin', (p)=> {
if (!p.addExtension) return
for (const gltfExtension of this.gltfExtensions) {
p.addExtension(gltfExtension.name, gltfExtension.textures)
}
})
}

protected _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
for (const gltfExtension of this.gltfExtensions) {
loader.register(gltfExtension.import)
}
}

registerGltfExtension(ext: AssetManager['gltfExtensions'][number]) {
const ext1 = this.gltfExtensions.findIndex(e => e.name === ext.name)
if (ext1 >= 0) this.gltfExtensions.splice(ext1, 1)
this.gltfExtensions.push(ext)
this._gltfExporter.extensions.push(ext.export)
const exporter2 = this.exporter.getExporter('gltf', 'glb')
if (exporter2 && exporter2 !== this._gltfExporter)
exporter2.extensions?.push(ext.export)
}

unregisterGltfExtension(name: string) {
const ind = this.gltfExtensions.findIndex(e => e.name === name)
if (ind < 0) return
this.gltfExtensions.splice(ind, 1)
const ind1 = this._gltfExporter.extensions.findIndex(e => e.name === name)
if (ind1 >= 0) this._gltfExporter.extensions.splice(ind1, 1)
const exporter2 = this.exporter.getExporter('gltf', 'glb')
if (exporter2?.extensions && exporter2 !== this._gltfExporter) {
const ind2 = exporter2.extensions.findIndex(e => e.name === name)
if (ind2 >= 0) exporter2.extensions?.splice(ind2, 1)
}
}

// endregion



// region deprecated // region deprecated



+ 3
- 0
src/assetmanager/gltf/GLTFLightExtrasExtension.ts Vedi File

} }
}, },
}) })

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number>|undefined = undefined
} }

+ 3
- 0
src/assetmanager/gltf/GLTFMaterialExtrasExtension.ts Vedi File

// console.log(w) // console.log(w)
}, },
}) })

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number>|undefined = undefined
} }

+ 5
- 0
src/assetmanager/gltf/GLTFMaterialsAlphaMapExtension.ts Vedi File

static readonly WebGiMaterialsAlphaMapExtension = 'WEBGI_materials_alphamap' static readonly WebGiMaterialsAlphaMapExtension = 'WEBGI_materials_alphamap'
static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsAlphaMapExtensionImport(parser) static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsAlphaMapExtensionImport(parser)
static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsAlphaMapExtensionExport(writer) static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsAlphaMapExtensionExport(writer)

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number> = {
alphaTexture: 'G',
}
} }


class GLTFMaterialsAlphaMapExtensionImport { class GLTFMaterialsAlphaMapExtensionImport {

+ 5
- 0
src/assetmanager/gltf/GLTFMaterialsBumpMapExtension.ts Vedi File

static readonly WebGiMaterialsBumpMapExtension = 'WEBGI_materials_bumpmap' static readonly WebGiMaterialsBumpMapExtension = 'WEBGI_materials_bumpmap'
static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsBumpMapExtensionImport(parser) static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsBumpMapExtensionImport(parser)
static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsBumpMapExtensionExport(writer) static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsBumpMapExtensionExport(writer)

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number> = {
bumpTexture: 'R',
}
} }


class GLTFMaterialsBumpMapExtensionImport { class GLTFMaterialsBumpMapExtensionImport {

+ 5
- 0
src/assetmanager/gltf/GLTFMaterialsDisplacementMapExtension.ts Vedi File

static readonly WebGiMaterialsDisplacementMapExtension = 'WEBGI_materials_displacementmap' static readonly WebGiMaterialsDisplacementMapExtension = 'WEBGI_materials_displacementmap'
static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsDisplacementMapExtensionImport(parser) static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsDisplacementMapExtensionImport(parser)
static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsDisplacementMapExtensionExport(writer) static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsDisplacementMapExtensionExport(writer)

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number> = {
displacementTexture: 'R',
}
} }


class GLTFMaterialsDisplacementMapExtensionImport { class GLTFMaterialsDisplacementMapExtensionImport {

+ 5
- 0
src/assetmanager/gltf/GLTFMaterialsLightMapExtension.ts Vedi File

static readonly WebGiMaterialsLightMapExtension = 'WEBGI_materials_lightmap' static readonly WebGiMaterialsLightMapExtension = 'WEBGI_materials_lightmap'
static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsLightMapExtensionImport(parser) static Import = (parser: GLTFParser): GLTFLoaderPlugin=> new GLTFMaterialsLightMapExtensionImport(parser)
static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsLightMapExtensionExport(writer) static Export = (writer: GLTFWriter): GLTFExporterPlugin => new GLTFMaterialsLightMapExtensionExport(writer)

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number> = {
lightMapTexture: 'RGB',
}
} }


class GLTFMaterialsLightMapExtensionImport { class GLTFMaterialsLightMapExtensionImport {

+ 3
- 0
src/assetmanager/gltf/GLTFObject3DExtrasExtension.ts Vedi File

} }
}, },
}) })

// see GLTFDracoExportPlugin
static Textures: Record<string, string|number>|undefined = undefined
} }

+ 1
- 1
src/core/light/DirectionalLight2.ts Vedi File



@uiColor('Color', (that: DirectionalLight2)=>({onChange: ()=>that.setDirty()})) @uiColor('Color', (that: DirectionalLight2)=>({onChange: ()=>that.setDirty()}))
declare color: Color declare color: Color
@uiSlider('Intensity', [0, 30], 0.01)
@uiSlider('Intensity', [0, 100], 0.01)
@onChange3('setDirty') @onChange3('setDirty')
declare intensity: number declare intensity: number
@uiVector('Position', undefined, undefined, (that: DirectionalLight2)=>({onChange: ()=>that.setDirty()})) @uiVector('Position', undefined, undefined, (that: DirectionalLight2)=>({onChange: ()=>that.setDirty()}))

+ 10
- 13
src/plugins/extras/GLTFKHRMaterialVariantsPlugin.ts Vedi File

import {AViewerPluginSync, ThreeViewer} from '../../viewer' import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {GLTFLoader2} from '../../assetmanager'
import {AssetManager} from '../../assetmanager'
import {onChange, serialize} from 'ts-browser-helpers' import {onChange, serialize} from 'ts-browser-helpers'
import {IMaterial, IObject3D} from '../../core' import {IMaterial, IObject3D} from '../../core'
import {UiObjectConfig} from 'uiconfig.js' import {UiObjectConfig} from 'uiconfig.js'


constructor() { constructor() {
super() super()
this._loaderCreate = this._loaderCreate.bind(this)
} }


onAdded(v: ThreeViewer): void { onAdded(v: ThreeViewer): void {
super.onAdded(v) super.onAdded(v)
// v.addEventListener('preRender', this._preRender) // v.addEventListener('preRender', this._preRender)
v.scene.addEventListener('addSceneObject', this._objectAdded) v.scene.addEventListener('addSceneObject', this._objectAdded)
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(gltfExporterMaterialsVariantsExtensionExport)
}

private _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
loader.register((p) => new GLTFMaterialsVariantsExtensionImport(p))
v.assetManager.registerGltfExtension(khrMaterialVariantsGLTFExtension)
} }


onRemove(v: ThreeViewer): void { onRemove(v: ThreeViewer): void {
v.scene.removeEventListener('addSceneObject', this._objectAdded) v.scene.removeEventListener('addSceneObject', this._objectAdded)
v.assetManager.importer.removeEventListener('loaderCreate', this._loaderCreate as any)
const exportExts = v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions || []
const i = exportExts.indexOf(gltfExporterMaterialsVariantsExtensionExport)
if (i !== -1) exportExts.splice(i, 1)
v.assetManager.unregisterGltfExtension(khrMaterialVariantsGLTFExtension.name)
this.variants = {} this.variants = {}
return super.onRemove(v) return super.onRemove(v)
} }
_originalMaterial?: IObject3D['material'] _originalMaterial?: IObject3D['material']
} }
} }

export const khrMaterialVariantsGLTFExtension = {
name: khrMaterialsVariantsGLTF,
import: (p) => new GLTFMaterialsVariantsExtensionImport(p),
export: gltfExporterMaterialsVariantsExtensionExport,
// textures: undefined,
} satisfies AssetManager['gltfExtensions'][number]

+ 4
- 4
src/plugins/index.ts Vedi File

export {CameraViewPlugin, type CameraViewPluginOptions} from './animation/CameraViewPlugin' export {CameraViewPlugin, type CameraViewPluginOptions} from './animation/CameraViewPlugin'


// material // material
export {ClearcoatTintPlugin} from './material/ClearcoatTintPlugin'
export {NoiseBumpMaterialPlugin} from './material/NoiseBumpMaterialPlugin'
export {CustomBumpMapPlugin} from './material/CustomBumpMapPlugin'
export {ClearcoatTintPlugin, clearCoatTintGLTFExtension} from './material/ClearcoatTintPlugin'
export {NoiseBumpMaterialPlugin, noiseBumpMaterialGLTFExtension} from './material/NoiseBumpMaterialPlugin'
export {CustomBumpMapPlugin, customBumpMapGLTFExtension} from './material/CustomBumpMapPlugin'
export {ParallaxMappingPlugin} from './material/ParallaxMappingPlugin' export {ParallaxMappingPlugin} from './material/ParallaxMappingPlugin'
export {FragmentClippingExtensionPlugin, FragmentClippingMode} from './material/FragmentClippingExtensionPlugin'
export {FragmentClippingExtensionPlugin, FragmentClippingMode, fragmentClippingGLTFExtension} from './material/FragmentClippingExtensionPlugin'


// rendering // rendering
export {VirtualCamerasPlugin, type VirtualCamera} from './rendering/VirtualCamerasPlugin' export {VirtualCamerasPlugin, type VirtualCamera} from './rendering/VirtualCamerasPlugin'

+ 17
- 21
src/plugins/material/ClearcoatTintPlugin.ts Vedi File

import {IMaterialUserData, PhysicalMaterial} from '../../core' import {IMaterialUserData, PhysicalMaterial} from '../../core'
import {MaterialExtension, updateMaterialDefines} from '../../materials' import {MaterialExtension, updateMaterialDefines} from '../../materials'
import {shaderReplaceString, ThreeSerialization} from '../../utils' import {shaderReplaceString, ThreeSerialization} from '../../utils'
import {GLTFLoader2, GLTFWriter2} from '../../assetmanager'
import {AssetManager, GLTFWriter2} from '../../assetmanager'
import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader' import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader'


/** /**
this._viewer?.setDirty() this._viewer?.setDirty()
} }


private _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
loader.register((p) => new GLTFMaterialsClearcoatTintExtensionImport(p))
}

constructor() { constructor() {
super() super()
this._loaderCreate = this._loaderCreate.bind(this)
Object.assign(this.materialExtension.extraUniforms!, this._uniforms) Object.assign(this.materialExtension.extraUniforms!, this._uniforms)
} }


onAdded(v: ThreeViewer) { onAdded(v: ThreeViewer) {
super.onAdded(v) super.onAdded(v)
// v.addEventListener('preRender', this._preRender)
v.assetManager.materials.registerMaterialExtension(this.materialExtension) v.assetManager.materials.registerMaterialExtension(this.materialExtension)
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFMaterialsClearcoatTintExtensionExport)

v.assetManager.registerGltfExtension(clearCoatTintGLTFExtension)
} }


onRemove(v: ThreeViewer) { onRemove(v: ThreeViewer) {
v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension) v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension)
v.assetManager.importer?.removeEventListener('loaderCreate', this._loaderCreate as any)
const exporter = v.assetManager.exporter.getExporter('gltf', 'glb')
if (exporter) {
const index = exporter.extensions?.indexOf(glTFMaterialsClearcoatTintExtensionExport)
if (index !== undefined && index >= 0) exporter.extensions?.splice(index, 1)
}
v.assetManager.unregisterGltfExtension(clearCoatTintGLTFExtension.name)
return super.onRemove(v) return super.onRemove(v)
} }


/**
* @deprecated - use {@link clearCoatTintGLTFExtension}
*/
public static readonly CLEARCOAT_TINT_GLTF_EXTENSION = 'WEBGI_materials_clearcoat_tint' public static readonly CLEARCOAT_TINT_GLTF_EXTENSION = 'WEBGI_materials_clearcoat_tint'


} }
/** /**
* ClearcoatTint Materials Extension * ClearcoatTint Materials Extension
* *
* Specification: https://webgi.xyz/docs/gltf-extensions/WEBGI_materials_clearcoat_tint.html
* Specification: https://webgi.xyz/docs/gltf-extensions/WEBGI_materials_clearcoat_tint.html (todo - fix link)
*/ */
class GLTFMaterialsClearcoatTintExtensionImport implements GLTFLoaderPlugin { class GLTFMaterialsClearcoatTintExtensionImport implements GLTFLoaderPlugin {
public name: string public name: string


constructor(parser: GLTFParser) { constructor(parser: GLTFParser) {
this.parser = parser this.parser = parser
this.name = ClearcoatTintPlugin.CLEARCOAT_TINT_GLTF_EXTENSION
this.name = clearCoatTintGLTFExtension.name
} }


async extendMaterialParams(materialIndex: number, materialParams: any) { async extendMaterialParams(materialIndex: number, materialParams: any) {


const extensionDef: any = ThreeSerialization.Serialize(material.userData._clearcoatTint) const extensionDef: any = ThreeSerialization.Serialize(material.userData._clearcoatTint)


materialDef.extensions[ ClearcoatTintPlugin.CLEARCOAT_TINT_GLTF_EXTENSION ] = extensionDef
w.extensionsUsed[ ClearcoatTintPlugin.CLEARCOAT_TINT_GLTF_EXTENSION ] = true
materialDef.extensions[ clearCoatTintGLTFExtension.name ] = extensionDef
w.extensionsUsed[ clearCoatTintGLTFExtension.name ] = true
}, },
}) })

export const clearCoatTintGLTFExtension = {
name: 'WEBGI_materials_clearcoat_tint',
import: (p) => new GLTFMaterialsClearcoatTintExtensionImport(p),
export: glTFMaterialsClearcoatTintExtensionExport,
textures: undefined,
} satisfies AssetManager['gltfExtensions'][number]

+ 22
- 23
src/plugins/material/CustomBumpMapPlugin.ts Vedi File

import {IMaterial, IObject3D, ITexture, PhysicalMaterial} from '../../core' import {IMaterial, IObject3D, ITexture, PhysicalMaterial} from '../../core'
import {MaterialExtension, updateMaterialDefines} from '../../materials' import {MaterialExtension, updateMaterialDefines} from '../../materials'
import {shaderReplaceString} from '../../utils' import {shaderReplaceString} from '../../utils'
import {GLTFLoader2, GLTFWriter2} from '../../assetmanager'
import {AssetManager, GLTFWriter2} from '../../assetmanager'
import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader' import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader'
import CustomBumpMapPluginShader from './shaders/CustomBumpMapPlugin.glsl' import CustomBumpMapPluginShader from './shaders/CustomBumpMapPlugin.glsl'
import {matDefine} from '../../three' import {matDefine} from '../../three'
if (v === state._hasCustomBump) return if (v === state._hasCustomBump) return
if (v) { if (v) {
if (!enableCustomBump(material)) if (!enableCustomBump(material))
viewer.dialog.alert('Cannot add CustomBumpMap.')
viewer.dialog.alert('CustomBumpMapPlugin - Cannot add CustomBumpMap.')
} else { } else {
state._hasCustomBump = false state._hasCustomBump = false
if (material.setDirty) material.setDirty() if (material.setDirty) material.setDirty()
bounds: [-1, 1], bounds: [-1, 1],
hidden: () => !state._hasCustomBump, hidden: () => !state._hasCustomBump,
property: [state, '_customBumpScale'], property: [state, '_customBumpScale'],
onChange: this.setDirty,
// onChange: this.setDirty,
}, },
{ {
type: 'image', type: 'image',
hidden: () => !state._hasCustomBump, hidden: () => !state._hasCustomBump,
property: [state, '_customBumpMap'], property: [state, '_customBumpMap'],
onChange: ()=>{ onChange: ()=>{
material.setDirty()
if (material.setDirty) material.setDirty()
}, },
}, },
makeSamplerUi(state as any, '_customBumpMap'),
makeSamplerUi(state as any, '_customBumpMap', 'Sampler', ()=>!state._hasCustomBump, ()=>material.setDirty && material.setDirty()),
], ],
} }
return config return config
this._viewer?.setDirty() this._viewer?.setDirty()
} }


private _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
loader.register((p) => new GLTFMaterialsCustomBumpMapImport(p))
}

constructor() { constructor() {
super() super()
this._loaderCreate = this._loaderCreate.bind(this)
Object.assign(this.materialExtension.extraUniforms!, this._uniforms) Object.assign(this.materialExtension.extraUniforms!, this._uniforms)
} }


super.onAdded(v) super.onAdded(v)
// v.addEventListener('preRender', this._preRender) // v.addEventListener('preRender', this._preRender)
v.assetManager.materials.registerMaterialExtension(this.materialExtension) v.assetManager.materials.registerMaterialExtension(this.materialExtension)
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFMaterialsCustomBumpMapExport)
v.assetManager.registerGltfExtension(customBumpMapGLTFExtension)
// v.getPlugin(GBufferPlugin)?.material?.registerMaterialExtensions([this.materialExtension]) // v.getPlugin(GBufferPlugin)?.material?.registerMaterialExtensions([this.materialExtension])

} }


onRemove(v: ThreeViewer) { onRemove(v: ThreeViewer) {
v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension) v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension)
v.assetManager.importer?.removeEventListener('loaderCreate', this._loaderCreate as any)
const exporter = v.assetManager.exporter.getExporter('gltf', 'glb')
if (exporter) {
const index = exporter.extensions?.indexOf(glTFMaterialsCustomBumpMapExport)
if (index !== undefined && index >= 0) exporter.extensions?.splice(index, 1)
}
v.assetManager.unregisterGltfExtension(customBumpMapGLTFExtension.name)
// v.getPlugin(GBufferPlugin)?.material?.unregisterMaterialExtensions([this.materialExtension]) // v.getPlugin(GBufferPlugin)?.material?.unregisterMaterialExtensions([this.materialExtension])
return super.onRemove(v) return super.onRemove(v)
} }


/**
* @deprecated use {@link customBumpMapGLTFExtension}
*/
public static readonly CUSTOM_BUMP_MAP_GLTF_EXTENSION = 'WEBGI_materials_custom_bump_map' public static readonly CUSTOM_BUMP_MAP_GLTF_EXTENSION = 'WEBGI_materials_custom_bump_map'


} }


constructor(parser: GLTFParser) { constructor(parser: GLTFParser) {
this.parser = parser this.parser = parser
this.name = CustomBumpMapPlugin.CUSTOM_BUMP_MAP_GLTF_EXTENSION
this.name = customBumpMapGLTFExtension.name
} }


async extendMaterialParams(materialIndex: number, materialParams: any) { async extendMaterialParams(materialIndex: number, materialParams: any) {


} }


materialDef.extensions[ CustomBumpMapPlugin.CUSTOM_BUMP_MAP_GLTF_EXTENSION ] = extensionDef
w.extensionsUsed[ CustomBumpMapPlugin.CUSTOM_BUMP_MAP_GLTF_EXTENSION ] = true
materialDef.extensions[ customBumpMapGLTFExtension.name ] = extensionDef
w.extensionsUsed[ customBumpMapGLTFExtension.name ] = true
}, },
}) })

export const customBumpMapGLTFExtension = {
name: 'WEBGI_materials_custom_bump_map',
import: (p) => new GLTFMaterialsCustomBumpMapImport(p),
export: glTFMaterialsCustomBumpMapExport,
textures: {
customBumpMap: 'RGB',
},
} satisfies AssetManager['gltfExtensions'][number]

+ 16
- 18
src/plugins/material/FragmentClippingExtensionPlugin.ts Vedi File

import {IMaterial, IMaterialUserData, IObject3D, PhysicalMaterial} from '../../core' import {IMaterial, IMaterialUserData, IObject3D, PhysicalMaterial} from '../../core'
import {MaterialExtension, updateMaterialDefines} from '../../materials' import {MaterialExtension, updateMaterialDefines} from '../../materials'
import {shaderReplaceString, ThreeSerialization} from '../../utils' import {shaderReplaceString, ThreeSerialization} from '../../utils'
import {GLTFLoader2, GLTFWriter2} from '../../assetmanager'
import {AssetManager, GLTFWriter2} from '../../assetmanager'
import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader' import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader'
import FragmentClippingExtensionPluginPars from './shaders/FragmentClippingExtensionPlugin.pars.glsl' import FragmentClippingExtensionPluginPars from './shaders/FragmentClippingExtensionPlugin.pars.glsl'
import FragmentClippingExtensionPluginPatch from './shaders/FragmentClippingExtensionPlugin.patch.glsl' import FragmentClippingExtensionPluginPatch from './shaders/FragmentClippingExtensionPlugin.patch.glsl'
this._viewer?.setDirty() this._viewer?.setDirty()
} }


private _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
loader.register((p) => new GLTFMaterialsFragmentClippingExtensionImport(p))
}

constructor() { constructor() {
super() super()
this._loaderCreate = this._loaderCreate.bind(this)
Object.assign(this.materialExtension.extraUniforms!, this._uniforms) Object.assign(this.materialExtension.extraUniforms!, this._uniforms)
} }


super.onAdded(v) super.onAdded(v)
// v.addEventListener('preRender', this._preRender) // v.addEventListener('preRender', this._preRender)
v.assetManager.materials.registerMaterialExtension(this.materialExtension) v.assetManager.materials.registerMaterialExtension(this.materialExtension)
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFMaterialsFragmentClippingExtensionExport)
v.assetManager.registerGltfExtension(fragmentClippingGLTFExtension)
// v.getPlugin(GBufferPlugin)?.material?.registerMaterialExtensions([this.materialExtension]) // v.getPlugin(GBufferPlugin)?.material?.registerMaterialExtensions([this.materialExtension])


} }


onRemove(v: ThreeViewer) { onRemove(v: ThreeViewer) {
v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension) v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension)
v.assetManager.importer?.removeEventListener('loaderCreate', this._loaderCreate as any)
const exporter = v.assetManager.exporter.getExporter('gltf', 'glb')
if (exporter) {
const index = exporter.extensions?.indexOf(glTFMaterialsFragmentClippingExtensionExport)
if (index !== undefined && index >= 0) exporter.extensions?.splice(index, 1)
}
v.assetManager.unregisterGltfExtension(fragmentClippingGLTFExtension.name)
// v.getPlugin(GBufferPlugin)?.material?.unregisterMaterialExtensions([this.materialExtension]) // v.getPlugin(GBufferPlugin)?.material?.unregisterMaterialExtensions([this.materialExtension])
return super.onRemove(v) return super.onRemove(v)
} }


/**
* @deprecated use - use {@link fragmentClippingGLTFExtension}
*/
public static readonly FRAGMENT_CLIPPING_EXTENSION_GLTF_EXTENSION = 'WEBGI_materials_fragment_clipping_extension' public static readonly FRAGMENT_CLIPPING_EXTENSION_GLTF_EXTENSION = 'WEBGI_materials_fragment_clipping_extension'


} }


constructor(parser: GLTFParser) { constructor(parser: GLTFParser) {
this.parser = parser this.parser = parser
this.name = FragmentClippingExtensionPlugin.FRAGMENT_CLIPPING_EXTENSION_GLTF_EXTENSION
this.name = fragmentClippingGLTFExtension.name
} }


async extendMaterialParams(materialIndex: number, materialParams: any) { async extendMaterialParams(materialIndex: number, materialParams: any) {


const extensionDef: any = ThreeSerialization.Serialize(material.userData._fragmentClippingExt) const extensionDef: any = ThreeSerialization.Serialize(material.userData._fragmentClippingExt)


materialDef.extensions[ FragmentClippingExtensionPlugin.FRAGMENT_CLIPPING_EXTENSION_GLTF_EXTENSION ] = extensionDef
w.extensionsUsed[ FragmentClippingExtensionPlugin.FRAGMENT_CLIPPING_EXTENSION_GLTF_EXTENSION ] = true
materialDef.extensions[ fragmentClippingGLTFExtension.name ] = extensionDef
w.extensionsUsed[ fragmentClippingGLTFExtension.name ] = true
}, },
}) })

export const fragmentClippingGLTFExtension = {
name: 'WEBGI_materials_fragment_clipping',
import: (p) => new GLTFMaterialsFragmentClippingExtensionImport(p),
export: glTFMaterialsFragmentClippingExtensionExport,
textures: undefined,
} satisfies AssetManager['gltfExtensions'][number]

+ 18
- 19
src/plugins/material/NoiseBumpMaterialPlugin.ts Vedi File

import {IMaterial, IMaterialUserData, IObject3D, PhysicalMaterial} from '../../core' import {IMaterial, IMaterialUserData, IObject3D, PhysicalMaterial} from '../../core'
import {MaterialExtension, updateMaterialDefines} from '../../materials' import {MaterialExtension, updateMaterialDefines} from '../../materials'
import {shaderReplaceString, ThreeSerialization} from '../../utils' import {shaderReplaceString, ThreeSerialization} from '../../utils'
import {GLTFLoader2, GLTFWriter2} from '../../assetmanager'
import {AssetManager, GLTFWriter2} from '../../assetmanager'
import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader' import type {GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader'
import NoiseBumpMaterialPluginPars from './shaders/NoiseBumpMaterialPlugin.pars.glsl' import NoiseBumpMaterialPluginPars from './shaders/NoiseBumpMaterialPlugin.pars.glsl'
import NoiseBumpMaterialPluginPatch from './shaders/NoiseBumpMaterialPlugin.patch.glsl' import NoiseBumpMaterialPluginPatch from './shaders/NoiseBumpMaterialPlugin.patch.glsl'
this._viewer?.setDirty() this._viewer?.setDirty()
} }


private _loaderCreate({loader}: {loader: GLTFLoader2}) {
if (!loader.isGLTFLoader2) return
loader.register((p) => new GLTFMaterialsNoiseBumpMaterialImport(p))
}

constructor() { constructor() {
super() super()
this._loaderCreate = this._loaderCreate.bind(this)
Object.assign(this.materialExtension.extraUniforms!, this._uniforms) Object.assign(this.materialExtension.extraUniforms!, this._uniforms)
} }


onAdded(v: ThreeViewer) { onAdded(v: ThreeViewer) {
super.onAdded(v) super.onAdded(v)
v.assetManager.materials.registerMaterialExtension(this.materialExtension) v.assetManager.materials.registerMaterialExtension(this.materialExtension)
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
v.assetManager.exporter.getExporter('gltf', 'glb')?.extensions?.push(glTFMaterialsNoiseBumpMaterialExport)
v.assetManager.registerGltfExtension(noiseBumpMaterialGLTFExtension)
} }


onRemove(v: ThreeViewer) { onRemove(v: ThreeViewer) {
v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension) v.assetManager.materials?.unregisterMaterialExtension(this.materialExtension)
v.assetManager.importer?.removeEventListener('loaderCreate', this._loaderCreate as any)
const exporter = v.assetManager.exporter.getExporter('gltf', 'glb')
if (exporter) {
const index = exporter.extensions?.indexOf(glTFMaterialsNoiseBumpMaterialExport)
if (index !== undefined && index >= 0) exporter.extensions?.splice(index, 1)
}
v.assetManager.unregisterGltfExtension(noiseBumpMaterialGLTFExtension.name)
return super.onRemove(v) return super.onRemove(v)
} }


/**
* @deprecated - use {@link noiseBumpMaterialGLTFExtension}
*/
public static readonly NOISE_BUMP_MATERIAL_GLTF_EXTENSION = 'WEBGI_materials_noise_bump' public static readonly NOISE_BUMP_MATERIAL_GLTF_EXTENSION = 'WEBGI_materials_noise_bump'


} }
/** /**
* FragmentClipping Materials Extension * FragmentClipping Materials Extension
* *
* Specification: https://webgi.xyz/docs/gltf-extensions/WEBGI_materials_fragment_clipping_extension.html
* Specification: https://webgi.xyz/docs/gltf-extensions/WEBGI_materials_fragment_clipping_extension.html (todo - fix link)
*/ */
class GLTFMaterialsNoiseBumpMaterialImport implements GLTFLoaderPlugin { class GLTFMaterialsNoiseBumpMaterialImport implements GLTFLoaderPlugin {
public name: string public name: string


constructor(parser: GLTFParser) { constructor(parser: GLTFParser) {
this.parser = parser this.parser = parser
this.name = NoiseBumpMaterialPlugin.NOISE_BUMP_MATERIAL_GLTF_EXTENSION
this.name = noiseBumpMaterialGLTFExtension.name
} }


async extendMaterialParams(materialIndex: number, materialParams: any) { async extendMaterialParams(materialIndex: number, materialParams: any) {


const extensionDef: any = ThreeSerialization.Serialize(material.userData._noiseBumpMat) const extensionDef: any = ThreeSerialization.Serialize(material.userData._noiseBumpMat)


materialDef.extensions[ NoiseBumpMaterialPlugin.NOISE_BUMP_MATERIAL_GLTF_EXTENSION ] = extensionDef
w.extensionsUsed[ NoiseBumpMaterialPlugin.NOISE_BUMP_MATERIAL_GLTF_EXTENSION ] = true
materialDef.extensions[ noiseBumpMaterialGLTFExtension.name ] = extensionDef
w.extensionsUsed[ noiseBumpMaterialGLTFExtension.name ] = true
}, },
}) })

export const noiseBumpMaterialGLTFExtension = {
name: 'WEBGI_materials_noise_bump',
import: (p) => new GLTFMaterialsNoiseBumpMaterialImport(p),
export: glTFMaterialsNoiseBumpMaterialExport,
textures: undefined,
} satisfies AssetManager['gltfExtensions'][number]


Loading…
Annulla
Salva