Parcourir la source

Three patch version update, types update, Fix image source being -1 in gltf export, use writer.checkEmptyMap in gltf extensions during export, Add FBXLoader2 which loads invalid image with default 1px white image, Support loading embedded files of various extensions in GLTFLoader by plugins, add SVGTextureLoader, Add AssetImporter.WHITE_IMAGE_DATA,

master
Palash Bansal il y a 1 an
Parent
révision
4657f635e1
Aucun compte lié à l'adresse e-mail de l'auteur

+ 7
- 7
package.json Voir le fichier

@@ -107,7 +107,7 @@
"rimraf": "^5.0.1",
"rollup-plugin-glsl": "^1.3.0",
"rollup-plugin-license": "^3.0.1",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1004/package.tgz",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1007/package.tgz",
"tslib": "^2.5.0",
"typedoc": "^0.27.5",
"typescript": "5.7.2",
@@ -118,7 +118,7 @@
"vitepress-plugin-nprogress": "^0.0.4"
},
"dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1004/package.tgz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5",
"stats.js": "^0.17.0",
@@ -127,7 +127,7 @@
"popmotion": "^11.0.5"
},
"peerDependencies": {
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1004/package.tgz"
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1007/package.tgz"
},
"peerDependenciesMeta": {
"three": {
@@ -138,10 +138,10 @@
"dependencies": {
"uiconfig.js": "^0.1.3",
"ts-browser-helpers": "^0.16.2",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1004/package.tgz",
"three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.157.1004.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1004/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.157.1004.tar.gz",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1007/package.tgz",
"three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.157.1007.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.157.1005.tar.gz",
"@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three"
},
"local_dependencies": {

+ 2
- 0
src/assetmanager/AssetImporter.ts Voir le fichier

@@ -68,6 +68,8 @@ export class AssetImporter extends EventDispatcher<IAssetImporterEventMap> imple
private _fileDatabase: Map<string, IFile> = new Map<string, IFile>()
private _cachedAssets: IAsset[] = []

static WHITE_IMAGE_DATA = new ImageData(new Uint8ClampedArray([255, 255, 255, 255]), 1, 1)

readonly importers: IImporter[] = [
// new Importer(VideoTextureLoader, ['mp4', 'ogg', 'mov', 'data:video'], false),
new Importer(SimpleJSONLoader, ['json', 'vjson'], ['application/json'], false),

+ 16
- 5
src/assetmanager/AssetManager.ts Voir le fichier

@@ -39,9 +39,17 @@ import {
} from '../core'
import {Importer} from './Importer'
import {MaterialManager} from './MaterialManager'
import {DRACOLoader2, GLTFLoader2, JSONMaterialLoader, MTLLoader2, OBJLoader2, ZipLoader} from './import'
import {
DRACOLoader2,
FBXLoader2,
GLTFLoader2,
JSONMaterialLoader,
MTLLoader2,
OBJLoader2,
SVGTextureLoader,
ZipLoader,
} from './import'
import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader.js'
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {EXRLoader} from 'three/examples/jsm/loaders/EXRLoader.js'
import {Class, ValOrArr} from 'ts-browser-helpers'
import {ILoader} from './IImporter'
@@ -279,9 +287,12 @@ export class AssetManager extends EventDispatcher<AssetManagerEventMap> {
const viewer = this.viewer
if (!viewer) return

// todo fix - loading manager getHandler matches backwards?
const importers: Importer[] = [
new Importer(TextureLoader, ['webp', 'png', 'jpeg', 'jpg', 'svg', 'ico', 'data:image', 'avif'], [
'image/webp', 'image/png', 'image/jpeg', 'image/svg+xml', 'image/gif', 'image/bmp', 'image/tiff', 'image/x-icon', 'image/avif',
new Importer(SVGTextureLoader, ['svg', 'data:image/svg'], ['image/svg+xml'], false), // todo: use ImageBitmapLoader if supported (better performance)

new Importer(TextureLoader, ['webp', 'png', 'jpeg', 'jpg', 'ico', 'data:image', 'avif'], [
'image/webp', 'image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/tiff', 'image/x-icon', 'image/avif',
], false), // todo: use ImageBitmapLoader if supported (better performance)

new Importer<JSONMaterialLoader>(JSONMaterialLoader,
@@ -305,7 +316,7 @@ export class AssetManager extends EventDispatcher<AssetManagerEventMap> {
}
}, ['exr'], ['image/x-exr'], false),

new Importer(FBXLoader, ['fbx'], ['model/fbx'], true),
new Importer(FBXLoader2, ['fbx'], ['model/fbx'], true),
new Importer(ZipLoader, ['zip', 'glbz', 'gltfz'], ['application/zip', 'model/gltf+zip', 'model/zip'], true), // gltfz and glbz are invented zip files with gltf/glb inside along with resources

new Importer(OBJLoader2 as any as Class<ILoader>, ['obj'], ['model/obj'], true),

+ 3
- 1
src/assetmanager/export/GLTFExporter2.ts Voir le fichier

@@ -158,8 +158,10 @@ export class GLTFExporter2 extends GLTFExporter implements IExportParser {
maxTextureSize: options.maxTextureSize ?? Infinity,
animations: options.animations ?? [],
includeCustomExtensions: options.includeCustomExtensions ?? true,
forceIndices: options.forceIndices ?? false,
forceIndices: options.forceIndices ?? false, // todo implement
exporterOptions: options,
ignoreInvalidMorphTargetTracks: options.ignoreInvalidMorphTargetTracks,
ignoreEmptyTextures: options.ignoreEmptyTextures,
}
if (options.exportExt === 'glb') {
gltfOptions.binary = true

+ 1
- 0
src/assetmanager/export/GLTFWriter2.ts Voir le fichier

@@ -228,6 +228,7 @@ export class GLTFWriter2 extends GLTFExporter.Utils.GLTFWriter {
}
if (textureDef.source < 0) {
console.error('textureDef.source cannot be saved', textureDef, map)
delete textureDef.source // gltf spec allows undefined, not -1
}

return processed

+ 1
- 1
src/assetmanager/gltf/GLTFMaterialsAlphaMapExtension.ts Voir le fichier

@@ -88,7 +88,7 @@ class GLTFMaterialsAlphaMapExtensionExport {

const extensionDef: any = {}

if (material.alphaMap) {
if (material.alphaMap && writer.checkEmptyMap(material.alphaMap)) {

const alphaMapDef = {index: writer.processTexture(material.alphaMap)}
writer.applyTextureTransform(alphaMapDef, material.alphaMap)

+ 1
- 1
src/assetmanager/gltf/GLTFMaterialsBumpMapExtension.ts Voir le fichier

@@ -95,7 +95,7 @@ class GLTFMaterialsBumpMapExtensionExport {

extensionDef.bumpScale = material.bumpScale

if (material.bumpMap) {
if (material.bumpMap && writer.checkEmptyMap(material.bumpMap)) {

const bumpMapDef = {index: writer.processTexture(material.bumpMap)}
writer.applyTextureTransform(bumpMapDef, material.bumpMap)

+ 1
- 1
src/assetmanager/gltf/GLTFMaterialsDisplacementMapExtension.ts Voir le fichier

@@ -90,7 +90,7 @@ class GLTFMaterialsDisplacementMapExtensionExport {
extensionDef.displacementScale = material.displacementScale
extensionDef.displacementBias = material.displacementBias

if (material.displacementMap) {
if (material.displacementMap && writer.checkEmptyMap(material.displacementMap)) {

const displacementMapDef = {index: writer.processTexture(material.displacementMap)}
writer.applyTextureTransform(displacementMapDef, material.displacementMap)

+ 1
- 1
src/assetmanager/gltf/GLTFMaterialsLightMapExtension.ts Voir le fichier

@@ -95,7 +95,7 @@ class GLTFMaterialsLightMapExtensionExport {

extensionDef.lightMapIntensity = material.lightMapIntensity

if (material.lightMap) {
if (material.lightMap && writer.checkEmptyMap(material.lightMap)) {

const lightMapDef = {index: writer.processTexture(material.lightMap)}
writer.applyTextureTransform(lightMapDef, material.lightMap)

+ 23
- 0
src/assetmanager/import/FBXLoader2.ts Voir le fichier

@@ -0,0 +1,23 @@
import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js'
import {Group, Texture} from 'three'
import {AssetImporter} from '../AssetImporter'

/**
* Extended FBXLoader that sets the default image from AssetImporter (for invalid/missing textures)
*/
export class FBXLoader2 extends FBXLoader {
async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<Group> {

const val = Texture.DEFAULT_IMAGE

// this will be used when doing new Texture(). Which is done for not found images or when some error happens in loading. See FBXLoader.
// todo save the path of invalid textures, check if they can be found in the loaded libs, and ask the user in UI to remap it to something else manually
if (!Texture.DEFAULT_IMAGE) Texture.DEFAULT_IMAGE = AssetImporter.WHITE_IMAGE_DATA

const res = await super.loadAsync(url, onProgress)

Texture.DEFAULT_IMAGE = val

return res
}
}

+ 35
- 10
src/assetmanager/import/GLTFLoader2.ts Voir le fichier

@@ -1,6 +1,6 @@
import type {GLTF, GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {LoadingManager, Object3D, OrthographicCamera} from 'three'
import {LoadingManager, Object3D, OrthographicCamera, Texture} from 'three'
import {AnyOptions, safeSetProperty} from 'ts-browser-helpers'
import {ThreeViewer} from '../../viewer'
import {generateUUID} from '../../three'
@@ -27,6 +27,10 @@ import {
UnlitLineMaterial,
UnlitMaterial,
} from '../../core'
import {AssetImporter} from '../AssetImporter'

// todo move somewhere
const supportedEmbeddedFiles = ['hdr', 'exr', 'webp', 'avif', 'ktx', 'hdrpng', 'svg', 'cube'] // ktx2, drc handled separately

export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|undefined> {
isGLTFLoader2 = true
@@ -69,7 +73,18 @@ export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|un

parse(data: ArrayBuffer | string, path: string, onLoad: (gltf: GLTF) => void, onError?: (event: ErrorEvent) => void, url?: string) {
this.preparse.call(this, data, url || path)
.then((res: ArrayBuffer | string) => res ? super.parse(res, path, onLoad, onError) : onError && onError(new ErrorEvent('no data')))
.then((res: ArrayBuffer|string) => {
const val = Texture.DEFAULT_IMAGE

// this will be used when doing new Texture(). Which is done for not found images or when some error happens in loading. See FBXLoader.
// todo save the path of invalid textures, check if they can be found in the loaded libs, and ask the user in UI to remap it to something else manually
if (!Texture.DEFAULT_IMAGE) Texture.DEFAULT_IMAGE = AssetImporter.WHITE_IMAGE_DATA

return res ? super.parse(res, path, (ret)=>{
Texture.DEFAULT_IMAGE = val
onLoad && onLoad(ret)
}, onError) : onError && onError(new ErrorEvent('no data'))
})
.catch((e: any) => {
console.error(e)
if (onError) onError(e ?? new ErrorEvent('unknown error'))
@@ -146,17 +161,27 @@ export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|un
console.error('Add GLTFMeshOptPlugin(and initialize it) to viewer to enable EXT_meshopt_compression decode')
}
}
const needsBasisU = parser.json?.extensionsUsed?.includes?.('KHR_texture_basisu')
if (needsBasisU) {
const ktx2 = viewer.assetManager.importer.registerFile(tempPathKtx2)
if (ktx2) {
this.setKTX2Loader(ktx2 as any) // todo: check class?
parser.options.ktx2Loader = ktx2 as any
}

// create ktx2 loader so it can be used with getHandler, we need to do this even when extension is not used since we dont know
const ktx2 = viewer.assetManager.importer.registerFile(tempPathKtx2)
// const needsBasisU = parser.json?.extensionsUsed?.includes?.('KHR_texture_basisu')
// if (needsBasisU) {
// const ktx2 = viewer.assetManager.importer.registerFile(tempPathKtx2)
if (ktx2) {
this.setKTX2Loader(ktx2 as any) // todo: check class?
parser.options.ktx2Loader = ktx2 as any
}
// }

// registering temp file creates and makes a loader available to the loading manager of that type
const tempFiles = supportedEmbeddedFiles.map(f=>generateUUID() + '.' + f)
tempFiles.forEach(f=>viewer.assetManager.importer.registerFile(f))

return {name: 'GLTF2_HELPER_PLUGIN', afterRoot: async(result: GLTF) => {
if (needsDrc) viewer.assetManager.importer.unregisterFile(tempPathDrc)
if (needsBasisU) viewer.assetManager.importer.unregisterFile(tempPathKtx2)
if (ktx2) viewer.assetManager.importer.unregisterFile(tempPathKtx2)
tempFiles.forEach(f=>viewer.assetManager.importer.unregisterFile(f))

await GLTFViewerConfigExtension.ImportViewerConfig(parser, viewer, result.scenes || [result.scene])
}}
}

+ 1
- 1
src/assetmanager/import/Rhino3dmLoader2.ts Voir le fichier

@@ -40,7 +40,7 @@ export class Rhino3dmLoader2 extends Rhino3dmLoader {
})
return super._createMaterial(material)
}
private _compareMaterials!: (material: Material) => Material
private declare _compareMaterials: (material: Material) => Material

async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<Object3D> {
const ret = await super.loadAsync(url, onProgress)

+ 69
- 0
src/assetmanager/import/SVGTextureLoader.ts Voir le fichier

@@ -0,0 +1,69 @@
import {CanvasTexture, ImageLoader, Loader, LoadingManager, Texture} from 'three'
import {getUrlQueryParam} from 'ts-browser-helpers'

/**
* Same as TextureLoader but loads SVG images, fixes issues with windows not loading svg files without a defined size.
* See - https://github.com/mrdoob/three.js/issues/30899
*
* todo - create example for test, see sample code in gh issue.
*/
class SVGTextureLoader extends Loader {

constructor(manager: LoadingManager) {

super(manager)

}

static USE_CANVAS_TEXTURE = getUrlQueryParam('svg-load-disable-canvas') !== 'true'

load(url: string, onLoad: (texture: Texture) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): Texture {

const canvas = SVGTextureLoader.USE_CANVAS_TEXTURE ? document.createElement('canvas') : undefined
const texture = SVGTextureLoader.USE_CANVAS_TEXTURE ? new CanvasTexture(canvas!) : new Texture()

const loader = new ImageLoader(this.manager)
loader.setCrossOrigin(this.crossOrigin)
loader.setPath(this.path)

loader.load(url, function(image) {

if (canvas) {
SVGTextureLoader.CopyImageToCanvas(canvas, image)
} else {

texture.image = image

}
texture.needsUpdate = true

if (onLoad !== undefined) {

onLoad(texture)

}

}, onProgress, onError)

return texture

}

static CopyImageToCanvas(canvas: HTMLCanvasElement, image: HTMLImageElement) {
// size can be scaled here, this is based on the viewBox aspect ratio and minimum size of 150hx300w
canvas.width = image.naturalWidth || image.width || 512
canvas.height = image.naturalHeight || image.height || 512

const ctx = canvas.getContext('2d')
if (ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
} else {
console.error('SVGTextureLoader: Failed to get canvas context.')
}
}

}


export {SVGTextureLoader}

+ 12
- 0
src/plugins/export/AssetExporterPlugin.ts Voir le fichier

@@ -61,6 +61,8 @@ export class AssetExporterPlugin extends AViewerPluginSync {
embedUrlImages: false,
encrypt: false,
encryptKey: '',
ignoreInvalidMorphTargetTracks: true,
ignoreEmptyTextures: true,
}

async exportScene(options?: ExportAssetOptions): Promise<BlobExt | undefined> {
@@ -129,6 +131,16 @@ export class AssetExporterPlugin extends AViewerPluginSync {
// label: 'Convert to indexed',
// property: [this.exportOptions, 'convertMeshToIndexed'],
// },
{
type: 'checkbox',
label: 'Ignore invalid animations',
property: [this.exportOptions, 'ignoreInvalidMorphTargetTracks'],
},
{
type: 'checkbox',
label: 'Ignore invalid textures',
property: [this.exportOptions, 'ignoreInvalidTextures'],
},
{
type: 'button',
label: 'Export GLB',

+ 1
- 1
src/plugins/material/CustomBumpMapPlugin.ts Voir le fichier

@@ -281,7 +281,7 @@ const glTFMaterialsCustomBumpMapExport = (w: GLTFWriter2)=> ({

extensionDef.customBumpScale = material.userData._customBumpScale || 1.0

if (material.userData._customBumpMap) {
if (w.checkEmptyMap(material.userData._customBumpMap)) {

const customBumpMapDef = {index: w.processTexture(material.userData._customBumpMap)}
w.applyTextureTransform(customBumpMapDef, material.userData._customBumpMap)

Chargement…
Annuler
Enregistrer