@threepipe/plugin-gltf-transform 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GLTFDracoExportPlugin.d.ts +2 -0
- package/dist/GLTFDracoExportPlugin.d.ts.map +1 -1
- package/dist/GLTFDracoExporter.d.ts +13 -4
- package/dist/GLTFDracoExporter.d.ts.map +1 -1
- package/dist/GLTFSpecGlossinessConverterPlugin.d.ts +43 -0
- package/dist/GLTFSpecGlossinessConverterPlugin.d.ts.map +1 -0
- package/dist/dependencies.txt +288 -8
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10378 -3823
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10380 -3825
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/GLTFDracoExportPlugin.ts +12 -5
- package/src/GLTFDracoExporter.ts +45 -38
- package/src/GLTFSpecGlossinessConverterPlugin.ts +126 -0
- package/src/index.ts +2 -1
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threepipe/plugin-gltf-transform",
|
|
3
3
|
"description": "Utility plugins for threepipe using gltf-transform to optimize/compress glTF files.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"dependencies": {},
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"import": "./dist/index.mjs",
|
|
9
10
|
"require": "./dist/index.js"
|
|
10
11
|
},
|
|
@@ -40,6 +41,6 @@
|
|
|
40
41
|
"directory": "plugins/gltf-transform"
|
|
41
42
|
},
|
|
42
43
|
"peerDependencies": {
|
|
43
|
-
"threepipe": "^0.0.
|
|
44
|
+
"threepipe": "^0.0.47"
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -17,9 +17,14 @@ import {
|
|
|
17
17
|
noiseBumpMaterialGLTFExtension,
|
|
18
18
|
fragmentClippingGLTFExtension,
|
|
19
19
|
} from 'threepipe'
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
createGenericExtensionClass,
|
|
22
|
+
GLTFDracoExporter,
|
|
23
|
+
GLTFViewerConfigExtensionGP,
|
|
24
|
+
} from './GLTFDracoExporter'
|
|
21
25
|
import {UiObjectConfig} from 'uiconfig.js'
|
|
22
26
|
import {EncoderOptions} from '@gltf-transform/extensions/dist/khr-draco-mesh-compression/encoder'
|
|
27
|
+
import {Extension} from '@gltf-transform/core'
|
|
23
28
|
|
|
24
29
|
export enum EncoderMethod {
|
|
25
30
|
EDGEBREAKER = 1,
|
|
@@ -42,7 +47,7 @@ export class GLTFDracoExportPlugin extends AViewerPluginSync {
|
|
|
42
47
|
* 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.
|
|
43
48
|
* To explicitly remove the data, use `removeExtension` with the name of the extension
|
|
44
49
|
*/
|
|
45
|
-
extraExtensions = [
|
|
50
|
+
extraExtensions = [ // its array because we want to keep the order of extensions
|
|
46
51
|
[GLTFMaterialsBumpMapExtension.WebGiMaterialsBumpMapExtension, GLTFMaterialsBumpMapExtension.Textures],
|
|
47
52
|
[GLTFMaterialsLightMapExtension.WebGiMaterialsLightMapExtension, GLTFMaterialsLightMapExtension.Textures],
|
|
48
53
|
[GLTFMaterialsAlphaMapExtension.WebGiMaterialsAlphaMapExtension, GLTFMaterialsAlphaMapExtension.Textures],
|
|
@@ -69,6 +74,10 @@ export class GLTFDracoExportPlugin extends AViewerPluginSync {
|
|
|
69
74
|
// SSBevelMaterialExtension
|
|
70
75
|
] as [string, Record<string, string|number>|undefined][]
|
|
71
76
|
|
|
77
|
+
get gltfTransformExtensions(): (typeof Extension)[] {
|
|
78
|
+
return [GLTFViewerConfigExtensionGP, ...this.extraExtensions.map(e => createGenericExtensionClass(e[0], e[1]))]
|
|
79
|
+
}
|
|
80
|
+
|
|
72
81
|
addExtension(name: string, textures?: Record<string, string|number>) {
|
|
73
82
|
const ext = this.extraExtensions.findIndex(e => e[0] === name)
|
|
74
83
|
if (ext >= 0) this.extraExtensions[ext] = [name, textures]
|
|
@@ -95,9 +104,7 @@ export class GLTFDracoExportPlugin extends AViewerPluginSync {
|
|
|
95
104
|
// todo unregister on dispose
|
|
96
105
|
this._viewer.assetManager.importer.registerFile(tempFile) as DRACOLoader2)
|
|
97
106
|
ex.setup(this._viewer, _exporter.extensions)
|
|
98
|
-
|
|
99
|
-
ex.createAndAddExtension(ext, config)
|
|
100
|
-
}
|
|
107
|
+
ex.addExtension(...this.gltfTransformExtensions)
|
|
101
108
|
return ex
|
|
102
109
|
}
|
|
103
110
|
|
package/src/GLTFDracoExporter.ts
CHANGED
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
} from '@gltf-transform/core'
|
|
15
15
|
import {EncoderOptions} from '@gltf-transform/extensions/dist/khr-draco-mesh-compression/encoder'
|
|
16
16
|
import {ALL_EXTENSIONS, KHRDracoMeshCompression} from '@gltf-transform/extensions'
|
|
17
|
-
import {DRACOLoader2, GLTFExporter2, GLTFExporter2Options, GLTFViewerConfigExtension,
|
|
17
|
+
import {DRACOLoader2, GLTFExporter2, GLTFExporter2Options, GLTFViewerConfigExtension, IExportWriter} from 'threepipe'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* GLTF Draco Exporter
|
|
21
21
|
*
|
|
22
22
|
* Extension of GLTFExporter2 that runs the output through gltf-transform for draco compression.
|
|
23
23
|
*/
|
|
24
|
-
export class GLTFDracoExporter extends GLTFExporter2 implements
|
|
24
|
+
export class GLTFDracoExporter extends GLTFExporter2 implements IExportWriter {
|
|
25
25
|
public loader?: DRACOLoader2 // required for loading draco libs.
|
|
26
26
|
private _io: WebIO
|
|
27
27
|
private _loadedLibs = false
|
|
@@ -34,9 +34,6 @@ export class GLTFDracoExporter extends GLTFExporter2 implements IExportParser {
|
|
|
34
34
|
encodeSpeed: 5,
|
|
35
35
|
}
|
|
36
36
|
this._io = new WebIO().registerExtensions(ALL_EXTENSIONS)
|
|
37
|
-
.registerExtensions([
|
|
38
|
-
GLTFViewerConfigExtensionGP,
|
|
39
|
-
])
|
|
40
37
|
this._encoderOptions = encoderOptions
|
|
41
38
|
|
|
42
39
|
if (loader) {
|
|
@@ -67,7 +64,7 @@ export class GLTFDracoExporter extends GLTFExporter2 implements IExportParser {
|
|
|
67
64
|
|
|
68
65
|
}
|
|
69
66
|
|
|
70
|
-
async parseAsync(obj: any, {compress = false, dracoOptions, ...options}: {compress: boolean, dracoOptions?: EncoderOptions} & GLTFExporter2Options): Promise<Blob> {
|
|
67
|
+
async parseAsync(obj: any, {compress = false, dracoOptions, ...options}: {compress: boolean, dracoOptions?: EncoderOptions} & GLTFExporter2Options, throwOnError = false): Promise<Blob> {
|
|
71
68
|
if (!this.loader) {
|
|
72
69
|
console.error('GLTFDracoExporter: No DRACOLoader2 instance provided')
|
|
73
70
|
return super.parseAsync(obj, options)
|
|
@@ -86,51 +83,61 @@ export class GLTFDracoExporter extends GLTFExporter2 implements IExportParser {
|
|
|
86
83
|
const uncompressedBlob = await super.parseAsync(uncompressed, ops)
|
|
87
84
|
if (!compress) return uncompressedBlob
|
|
88
85
|
|
|
89
|
-
|
|
86
|
+
try {
|
|
87
|
+
if (!uncompressed) throw new Error('GLTFDracoExporter: gltf is null')
|
|
90
88
|
|
|
91
|
-
|
|
89
|
+
let gltf = uncompressed
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
const bytes = (gltf as ArrayBuffer).byteLength || Infinity
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
const iDocument = await (typeof gltf === 'object' && !(gltf as any).byteLength ? this._io.readJSON({
|
|
94
|
+
json: gltf as GLTF.IGLTF,
|
|
95
|
+
resources: {},
|
|
96
|
+
}) : this._io.readBinary(new Uint8Array(gltf as ArrayBuffer)))
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
// iDocument.createExtension(GLTFViewerConfigExtensionGP)
|
|
99
|
+
iDocument.createExtension(KHRDracoMeshCompression)
|
|
100
|
+
.setRequired(true)
|
|
101
|
+
.setEncoderOptions({...this._encoderOptions, ...dracoOptions ?? {}})
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
103
|
+
if (ops.exportExt === 'glb') {
|
|
104
|
+
gltf = await this._io.writeBinary(iDocument)
|
|
105
|
+
if (isFinite(bytes)) {
|
|
106
|
+
console.log('DRACO Compression ratio: ' + ((gltf as ArrayBuffer).byteLength / bytes).toFixed(5))
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
const jDoc = await this._io.writeJSON(iDocument)
|
|
110
|
+
gltf = jDoc.json
|
|
111
|
+
if (Object.values(jDoc.resources).filter(v => v).length > 0) {
|
|
112
|
+
console.warn('DRACOExporter: extra resources in resources not supported properly')
|
|
113
|
+
;(gltf as any).resources = jDoc.resources
|
|
114
|
+
}
|
|
116
115
|
}
|
|
117
|
-
}
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
gltf.__isGLTFOutput = true
|
|
118
|
+
const blob = await super.parseAsync(gltf, ops) as any // this will just convert it to blob because __isGLTFOutput is set (checked in GLTFExporter2)
|
|
119
|
+
if (!blob) throw new Error('GLTFDracoExporter: blob is null')
|
|
120
|
+
blob.ext = 'glb'
|
|
121
|
+
;(blob as any).__uncompressed = uncompressedBlob
|
|
122
|
+
return blob
|
|
123
|
+
} catch (e) {
|
|
124
|
+
if (throwOnError) throw e
|
|
125
|
+
console.error('Unable to compress glb with DRACO extension, fallback to uncompressed')
|
|
126
|
+
console.error(e)
|
|
127
|
+
return uncompressedBlob
|
|
128
|
+
}
|
|
125
129
|
}
|
|
126
130
|
|
|
127
|
-
addExtension(extension: typeof Extension): this {
|
|
128
|
-
this._io.registerExtensions(
|
|
131
|
+
addExtension(...extension: (typeof Extension)[]): this {
|
|
132
|
+
this._io.registerExtensions(extension)
|
|
129
133
|
return this
|
|
130
134
|
}
|
|
131
135
|
createAndAddExtension(name: string, textures?: Record<string, string|number>): this {
|
|
132
136
|
return this.addExtension(createGenericExtensionClass(name, textures))
|
|
133
137
|
}
|
|
138
|
+
createAndAddExtensions(extensions: [string, Record<string, string|number>|undefined][]): this {
|
|
139
|
+
return this.addExtension(...extensions.map(e=> createGenericExtensionClass(e[0], e[1])))
|
|
140
|
+
}
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
declare module 'threepipe'{
|
|
@@ -150,7 +157,7 @@ class ViewerJSONExtensionProperty extends ExtensionProperty {
|
|
|
150
157
|
protected init(): void {return}
|
|
151
158
|
|
|
152
159
|
}
|
|
153
|
-
class GLTFViewerConfigExtensionGP extends Extension {
|
|
160
|
+
export class GLTFViewerConfigExtensionGP extends Extension {
|
|
154
161
|
public readonly extensionName = GLTFViewerConfigExtension.ViewerConfigGLTFExtension
|
|
155
162
|
public static readonly EXTENSION_NAME = GLTFViewerConfigExtension.ViewerConfigGLTFExtension
|
|
156
163
|
private _viewerConfig: any = {}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {AViewerPluginSync, DRACOLoader2, GLTFBinaryExtension, GLTFLoader2, GLTFParser, ThreeViewer} from 'threepipe'
|
|
2
|
+
import {Extension, WebIO} from '@gltf-transform/core'
|
|
3
|
+
import {ALL_EXTENSIONS} from '@gltf-transform/extensions'
|
|
4
|
+
import {GLTFDracoExportPlugin} from './GLTFDracoExportPlugin'
|
|
5
|
+
import {metalRough} from '@gltf-transform/functions'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* GLTFSpecGlossinessConverterPlugin
|
|
9
|
+
*
|
|
10
|
+
* Plugin that adds a gltf loader extension that automatically converts GLTF files with specular glossiness materials ([KHR_materials_pbrSpecularGlossiness](https://kcoley.github.io/glTF/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/)) to metallic roughness during import.
|
|
11
|
+
*
|
|
12
|
+
* To use this plugin, simply add it to the viewer and import a file with specular glossiness materials.
|
|
13
|
+
* If `confirm` is set to true, a confirmation dialog will be shown before the conversion.
|
|
14
|
+
*/
|
|
15
|
+
export class GLTFSpecGlossinessConverterPlugin extends AViewerPluginSync {
|
|
16
|
+
enabled = true
|
|
17
|
+
|
|
18
|
+
static readonly PluginType = 'GLTFSpecGlossinessConverterPlugin'
|
|
19
|
+
toJSON: any = undefined
|
|
20
|
+
|
|
21
|
+
// dependencies = [GLTFDracoExportPlugin]
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Whether to show the confirmation dialog when loading a GLTF file with specular glossiness materials.
|
|
25
|
+
* If set to false, the conversion will be done automatically without confirmation.
|
|
26
|
+
* To disable the conversion entirely, disable the plugin.
|
|
27
|
+
*/
|
|
28
|
+
confirm = true
|
|
29
|
+
/**
|
|
30
|
+
* The message to show in the confirmation dialog when loading a GLTF file with specular glossiness materials.
|
|
31
|
+
*/
|
|
32
|
+
confirmMessage = 'GLTF Load: This file includes specular glossiness materials, do you want to convert it to metallic roughness before load?'
|
|
33
|
+
|
|
34
|
+
private _loaderCreate({loader}: {loader: GLTFLoader2}) {
|
|
35
|
+
if (!loader.isGLTFLoader2) return
|
|
36
|
+
|
|
37
|
+
const ep = this._viewer?.getPlugin(GLTFDracoExportPlugin)
|
|
38
|
+
if (!ep) {
|
|
39
|
+
console.error('GLTFSpecGlossinessConverterPlugin requires GLTFDracoExportPlugin in the plugin for extra extensions')
|
|
40
|
+
}
|
|
41
|
+
loader.register(gltfKhrPbrSpecularGlossinessConverter(async(m)=>!this.enabled ? false : !this.confirm ? true : this._viewer?.dialog.confirm(this.confirmMessage || m) ?? true, ep?.gltfTransformExtensions))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
constructor() {
|
|
45
|
+
super()
|
|
46
|
+
this._loaderCreate = this._loaderCreate.bind(this)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
onAdded(v: ThreeViewer) {
|
|
50
|
+
super.onAdded(v)
|
|
51
|
+
v.assetManager.importer.addEventListener('loaderCreate', this._loaderCreate as any)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onRemove(v: ThreeViewer) {
|
|
55
|
+
v.assetManager.importer.removeEventListener('loaderCreate', this._loaderCreate as any)
|
|
56
|
+
return super.onRemove(v)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
export const gltfKhrPbrSpecularGlossinessConverter = (confirm?: (s: string)=>Promise<boolean>, extensions?: (typeof Extension)[])=>(parser: GLTFParser)=>({
|
|
62
|
+
name: 'KHR_materials_pbrSpecularGlossiness',
|
|
63
|
+
beforeRoot: async() => {
|
|
64
|
+
try {
|
|
65
|
+
if (!parser.json.extensionsUsed || !parser.json.extensionsUsed.includes('KHR_materials_pbrSpecularGlossiness')) return
|
|
66
|
+
const doConfirm = parser.importOptions?.confirmSpecGlossConversion ?? true
|
|
67
|
+
if (doConfirm && confirm && !await confirm('Convert KHR_materials_pbrSpecularGlossiness to KHR_materials_pbrMetallicRoughness?')) return
|
|
68
|
+
|
|
69
|
+
const json = parser.json
|
|
70
|
+
const io = new WebIO().registerExtensions(ALL_EXTENSIONS).registerExtensions(extensions ?? [])
|
|
71
|
+
|
|
72
|
+
if (parser.extensions.KHR_draco_mesh_compression) {
|
|
73
|
+
const dracoLoader = parser.extensions.KHR_draco_mesh_compression.dracoLoader as DRACOLoader2
|
|
74
|
+
if (!dracoLoader.isDRACOLoader2) {
|
|
75
|
+
console.error('gltfKhrPbrSpecularGlossinessConverter: DRACOLoader2 required')
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
const decoder = await dracoLoader.initDecoder()
|
|
79
|
+
io.registerDependencies({
|
|
80
|
+
// 'draco3d.encoder': libs[0],
|
|
81
|
+
['draco3d.decoder']: decoder,
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const document = await io.readJSON({
|
|
86
|
+
json, resources: {
|
|
87
|
+
['@glb.bin']: new Uint8Array(parser.extensions.KHR_binary_glTF?.body),
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// Convert materials.
|
|
93
|
+
await document.transform(metalRough())
|
|
94
|
+
|
|
95
|
+
// no need to compress
|
|
96
|
+
if (parser.extensions.KHR_draco_mesh_compression) {
|
|
97
|
+
document.getRoot().listExtensionsUsed().find(e => e.extensionName === 'KHR_draco_mesh_compression')?.dispose()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Write back to GLB.
|
|
101
|
+
const res = await io.writeBinary(document)
|
|
102
|
+
const binaryExtension = new GLTFBinaryExtension(res.buffer as any)
|
|
103
|
+
parser.extensions.KHR_binary_glTF = binaryExtension
|
|
104
|
+
parser.json = JSON.parse(binaryExtension.content)
|
|
105
|
+
|
|
106
|
+
// this doesn't work for some reason
|
|
107
|
+
// const res = await io.writeJSON(document, {format: Format.GLB})
|
|
108
|
+
// parser.extensions.KHR_binary_glTF.data = res.resources['@glb.bin'].buffer as any
|
|
109
|
+
// parser.extensions.KHR_binary_glTF.content = res.json
|
|
110
|
+
// parser.json = res.json
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error(e)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
declare module 'threepipe'{
|
|
119
|
+
interface ImportAddOptions{
|
|
120
|
+
/**
|
|
121
|
+
* Whether to confirm the conversion of specular glossiness materials to metallic roughness.
|
|
122
|
+
* @default true
|
|
123
|
+
*/
|
|
124
|
+
confirmSpecGlossConversion?: boolean
|
|
125
|
+
}
|
|
126
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export {GLTFDracoExporter, createGenericExtensionClass} from './GLTFDracoExporter'
|
|
2
|
-
export {GLTFDracoExportPlugin} from './GLTFDracoExportPlugin'
|
|
2
|
+
export {GLTFDracoExportPlugin, EncoderMethod} from './GLTFDracoExportPlugin'
|
|
3
|
+
export {GLTFSpecGlossinessConverterPlugin, gltfKhrPbrSpecularGlossinessConverter} from './GLTFSpecGlossinessConverterPlugin'
|