| "version": "0.0.13", | "version": "0.0.13", | ||||
| "license": "Apache-2.0", | "license": "Apache-2.0", | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "ts-browser-helpers": "^0.8.0" | "ts-browser-helpers": "^0.8.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", | ||||
| "stats.js": "^0.17.0", | "stats.js": "^0.17.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2015/package.tgz", | |||||
| "tslib": "^2.5.0", | "tslib": "^2.5.0", | ||||
| "typedoc": "^0.24.7", | "typedoc": "^0.24.7", | ||||
| "typescript": "^5.0.4", | "typescript": "^5.0.4", | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "node_modules/@types/three": { | "node_modules/@types/three": { | ||||
| "version": "0.152.1014", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==", | |||||
| "version": "0.152.1016", | |||||
| "resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||||
| "integrity": "sha512-S4AczoUaWTfyh7ApgEXZWhhusqF9DGX8ynfIa8OzS0+ES0DmD1UQuyVQUmwOTxgTDGO10vc7zWrObZGPvM88NQ==", | |||||
| "dependencies": { | "dependencies": { | ||||
| "@tweenjs/tween.js": "~18.6.4", | "@tweenjs/tween.js": "~18.6.4", | ||||
| "fflate": "~0.6.9", | "fflate": "~0.6.9", | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/three": { | "node_modules/three": { | ||||
| "version": "0.152.2011", | |||||
| "resolved": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | |||||
| "integrity": "sha512-f2WKlSeuz9uvpfHNngEJMrQtKbyuE2iHjvpBaF1Wl8LcoMT3WUs7nmJzbEeheEr+J8BYnyRLNMDzR2xU0l1+Yw==", | |||||
| "version": "0.152.2015", | |||||
| "resolved": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2015/package.tgz", | |||||
| "integrity": "sha512-qON7KCzBCV2cWH4uOg6rfSJw5otIRk3JK7i8VtRq9K0KWaD/c3aW2Uz/WRqOJDxW/ENNrKhb171nqlToJIkgcg==", | |||||
| "dev": true, | "dev": true, | ||||
| "license": "MIT" | "license": "MIT" | ||||
| }, | }, | ||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "@types/three": { | "@types/three": { | ||||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "integrity": "sha512-1sR9iALwIFtfSXxJshAglvMjLy5litWF2hTbh0JQ+44d+21D2t0nppRZBnWtNQP5XsBYdhCNygnDQNeF6kd+NQ==", | |||||
| "version": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||||
| "integrity": "sha512-S4AczoUaWTfyh7ApgEXZWhhusqF9DGX8ynfIa8OzS0+ES0DmD1UQuyVQUmwOTxgTDGO10vc7zWrObZGPvM88NQ==", | |||||
| "requires": { | "requires": { | ||||
| "@tweenjs/tween.js": "~18.6.4", | "@tweenjs/tween.js": "~18.6.4", | ||||
| "fflate": "~0.6.9", | "fflate": "~0.6.9", | ||||
| } | } | ||||
| }, | }, | ||||
| "three": { | "three": { | ||||
| "version": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | |||||
| "integrity": "sha512-f2WKlSeuz9uvpfHNngEJMrQtKbyuE2iHjvpBaF1Wl8LcoMT3WUs7nmJzbEeheEr+J8BYnyRLNMDzR2xU0l1+Yw==", | |||||
| "version": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2015/package.tgz", | |||||
| "integrity": "sha512-qON7KCzBCV2cWH4uOg6rfSJw5otIRk3JK7i8VtRq9K0KWaD/c3aW2Uz/WRqOJDxW/ENNrKhb171nqlToJIkgcg==", | |||||
| "dev": true | "dev": true | ||||
| }, | }, | ||||
| "through": { | "through": { |
| "rollup-plugin-glsl": "^1.3.0", | "rollup-plugin-glsl": "^1.3.0", | ||||
| "rollup-plugin-postcss": "^4.0.2", | "rollup-plugin-postcss": "^4.0.2", | ||||
| "stats.js": "^0.17.0", | "stats.js": "^0.17.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | |||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2015/package.tgz", | |||||
| "tslib": "^2.5.0", | "tslib": "^2.5.0", | ||||
| "typedoc": "^0.24.7", | "typedoc": "^0.24.7", | ||||
| "typescript": "^5.0.4", | "typescript": "^5.0.4", | ||||
| "popmotion": "^11.0.5" | "popmotion": "^11.0.5" | ||||
| }, | }, | ||||
| "dependencies": { | "dependencies": { | ||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1016/package.tgz", | |||||
| "@types/webxr": "^0.5.1", | "@types/webxr": "^0.5.1", | ||||
| "@types/wicg-file-system-access": "^2020.9.5", | "@types/wicg-file-system-access": "^2020.9.5", | ||||
| "ts-browser-helpers": "^0.8.0" | "ts-browser-helpers": "^0.8.0" | ||||
| "dependencies": { | "dependencies": { | ||||
| "uiconfig.js": "^0.0.6", | "uiconfig.js": "^0.0.6", | ||||
| "ts-browser-helpers": "^0.8.0", | "ts-browser-helpers": "^0.8.0", | ||||
| "three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2012/package.tgz", | |||||
| "three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.152.2012.tar.gz", | |||||
| "@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1014/package.tgz", | |||||
| "@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.152.1014.tar.gz", | |||||
| "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-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" | ||||
| }, | }, | ||||
| "local_dependencies": { | "local_dependencies": { |
| import {Event, EventDispatcher, FileLoader, LoaderUtils, LoadingManager} from 'three' | |||||
| import {Event, EventDispatcher, EventListener, FileLoader, LoaderUtils, LoadingManager} from 'three' | |||||
| import { | import { | ||||
| IAssetImporter, | IAssetImporter, | ||||
| IAssetImporterEventTypes, | IAssetImporterEventTypes, | ||||
| return loader | return loader | ||||
| } | } | ||||
| addEventListener<T extends IAssetImporterEvent['type'] & IAssetImporterEventTypes>(type: T, listener: EventListener<IAssetImporterEvent, T, this>) { | |||||
| super.addEventListener(type, listener) | |||||
| if (type === 'loaderCreate') { | |||||
| for (const loaderCacheElement of this._loaderCache) { | |||||
| this.dispatchEvent({type: 'loaderCreate', loader: loaderCacheElement.loader}) | |||||
| } | |||||
| } | |||||
| } | |||||
| // endregion | // endregion | ||||
| // region Loader Event Dispatchers | // region Loader Event Dispatchers |
| return !uuid ? undefined : this._materials.find(v=>v.uuid === uuid) | return !uuid ? undefined : this._materials.find(v=>v.uuid === uuid) | ||||
| } | } | ||||
| public findMaterialsByName(name: string): IMaterial[] { | |||||
| return this._materials.filter(v=>v.name === name) | |||||
| public findMaterialsByName(name: string|RegExp, regex = false): IMaterial[] { | |||||
| return this._materials.filter(v=>typeof name !== 'string' || regex ? v.name.match(name) !== null : v.name === name) | |||||
| } | } | ||||
| public getMaterialsOfType<TM extends IMaterial = IMaterial>(typeSlug: string | undefined): TM[] { | public getMaterialsOfType<TM extends IMaterial = IMaterial>(typeSlug: string | undefined): TM[] { |
| getObjectByProperty<T extends IObject3D = IObject3D>(name: string, value: string): T | undefined | getObjectByProperty<T extends IObject3D = IObject3D>(name: string, value: string): T | undefined | ||||
| copy(source: this, recursive?: boolean, ...args: any[]): this | copy(source: this, recursive?: boolean, ...args: any[]): this | ||||
| clone(recursive?: boolean): this | clone(recursive?: boolean): this | ||||
| add(...object: IObject3D[]): this | |||||
| add(...object: Object3D[]): this | |||||
| remove(...object: IObject3D[]): this | remove(...object: IObject3D[]): this | ||||
| parent: IObject3D | null | parent: IObject3D | null | ||||
| children: IObject3D[] | children: IObject3D[] |
| import {UiObjectConfig} from 'uiconfig.js' | import {UiObjectConfig} from 'uiconfig.js' | ||||
| import {IGeometry, IGeometrySetDirtyOptions} from '../IGeometry' | import {IGeometry, IGeometrySetDirtyOptions} from '../IGeometry' | ||||
| import {isInScene, toIndexedGeometry} from '../../three' | |||||
| import {BufferGeometry} from 'three' | |||||
| import {autoGPUInstanceMeshes, isInScene, toIndexedGeometry} from '../../three' | |||||
| import {BufferGeometry, Vector3} from 'three' | |||||
| export const iGeometryCommons = { | export const iGeometryCommons = { | ||||
| setDirty: function(this: IGeometry, options?: IGeometrySetDirtyOptions): void { | setDirty: function(this: IGeometry, options?: IGeometrySetDirtyOptions): void { | ||||
| this.setDirty() | this.setDirty() | ||||
| }, | }, | ||||
| }, | }, | ||||
| { | |||||
| type: 'button', | |||||
| label: 'Center Geometry (keep position)', | |||||
| value: () => { | |||||
| const offset = new Vector3() | |||||
| this.center(offset) | |||||
| const meshes = this.appliedMeshes | |||||
| meshes.forEach(m=>{ | |||||
| m.position.sub(offset) | |||||
| m.setDirty && m.setDirty() | |||||
| }) | |||||
| }, | |||||
| }, | |||||
| { | { | ||||
| type: 'button', | type: 'button', | ||||
| label: 'Compute vertex normals', | label: 'Compute vertex normals', | ||||
| this.setDirty() | this.setDirty() | ||||
| }, | }, | ||||
| }, | }, | ||||
| { | |||||
| type: 'button', | |||||
| label: 'Auto GPU Instances', | |||||
| hidden: ()=> !this.appliedMeshes || this.appliedMeshes.size < 2, | |||||
| value: ()=>{ | |||||
| if (!confirm('This action is irreversible, do you want to continue?')) return | |||||
| autoGPUInstanceMeshes(this) | |||||
| }, | |||||
| }, | |||||
| { | { | ||||
| type: 'input', | type: 'input', | ||||
| label: 'Mesh count', | label: 'Mesh count', |
| { | { | ||||
| type: 'slider', | type: 'slider', | ||||
| bounds: [0, 1], | bounds: [0, 1], | ||||
| stepSize: 0.001, | |||||
| property: [material, 'alphaTest'], | property: [material, 'alphaTest'], | ||||
| }, | }, | ||||
| { | { |
| if (!isFinite(this.attenuationDistance)) this.attenuationDistance = 0 // hack for ui | if (!isFinite(this.attenuationDistance)) this.attenuationDistance = 0 // hack for ui | ||||
| this.userData.uuid = this.uuid // just in case | |||||
| this.userData.uuid = this.uuid | |||||
| return this | return this | ||||
| } | } | ||||
| if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial | if (clearCurrentUserData === undefined) clearCurrentUserData = (<Material>parameters).isMaterial | ||||
| if (clearCurrentUserData) this.userData = {} | if (clearCurrentUserData) this.userData = {} | ||||
| iMaterialCommons.setValues(super.setValues).call(this, parameters) | iMaterialCommons.setValues(super.setValues).call(this, parameters) | ||||
| this.userData.uuid = this.uuid // just in case | |||||
| this.userData.uuid = this.uuid | |||||
| return this | return this | ||||
| } | } | ||||
| copy(source: Material|any): this { | copy(source: Material|any): this { |
| import {IGeometry, IMaterial, IObject3D} from '../../core' | |||||
| import {BufferAttribute, InstancedMesh} from 'three' | |||||
| import {copyObject3DUserData} from '../../utils' | |||||
| export function autoGPUInstanceMeshes(matOrGeom: IMaterial|IGeometry) { | |||||
| if (!(<IMaterial>matOrGeom).isMaterial && !(<IGeometry>matOrGeom).isBufferGeometry) return | |||||
| const meshes = Array.from(matOrGeom.appliedMeshes).filter((m: any) => | |||||
| !m.isInstancedMesh && | |||||
| !!m.parent && | |||||
| m.children.length === 0 && | |||||
| !Array.isArray(m.material) | |||||
| ) | |||||
| if (meshes.length < 2) return | |||||
| const getKey = (m: IObject3D) => { | |||||
| return m.parent!.uuid + '_' + m.geometry?.uuid + '_' + (m.material as IMaterial)?.uuid // + '_' + (m.matrix.determinant()<0) | |||||
| } | |||||
| const keyMeshMap = new Map<string, IObject3D[]>() | |||||
| for (const mesh1 of meshes) { | |||||
| const key = getKey(mesh1) | |||||
| if (!keyMeshMap.has(key)) keyMeshMap.set(key, []) | |||||
| keyMeshMap.get(key)!.push(mesh1) | |||||
| mesh1.updateMatrix() | |||||
| } | |||||
| const keys = keyMeshMap.keys() | |||||
| for (const key of keys) { | |||||
| const iMeshes = keyMeshMap.get(key)! | |||||
| const baseMesh = iMeshes[0] | |||||
| if (!baseMesh) continue | |||||
| if (iMeshes.length < 2) continue | |||||
| const inst = new InstancedMesh(baseMesh.geometry, baseMesh.material, iMeshes.length) | |||||
| const ud = baseMesh.userData | |||||
| baseMesh.userData = {} | |||||
| inst.copy(baseMesh) | |||||
| copyObject3DUserData(inst.userData, ud) | |||||
| const parent = baseMesh.parent! | |||||
| inst.position.set(0, 0, 0) | |||||
| inst.rotation.set(0, 0, 0) | |||||
| inst.scale.set(1, 1, 1) | |||||
| inst.updateMatrix() | |||||
| const translationAttr = new Float32Array(inst.count * 3) | |||||
| const rotationAttr = new Float32Array(inst.count * 4) | |||||
| const scaleAttr = new Float32Array(inst.count * 3) | |||||
| // const pos = new Vector3() | |||||
| // const quat = new Quaternion() | |||||
| // const scale = new Vector3() | |||||
| for (let i = 0; i < iMeshes.length; i++) { | |||||
| const m = iMeshes[i] | |||||
| // const mat = inst.matrix.clone().invert().multiply(m.matrix) | |||||
| const mat = m.matrix | |||||
| // mat.decompose(pos, quat, scale) | |||||
| if (mat.determinant() < 0) { | |||||
| mat.elements[0] *= -1 | |||||
| mat.elements[1] *= -1 | |||||
| mat.elements[2] *= -1 | |||||
| } | |||||
| inst.setMatrixAt(i, mat) | |||||
| m.position.toArray(translationAttr, i * 3) | |||||
| m.quaternion.toArray(rotationAttr, i * 4) | |||||
| m.scale.toArray(scaleAttr, i * 3) | |||||
| m.removeFromParent() | |||||
| // ;(m.material as any)?.appliedMeshes?.delete(m) | |||||
| // m.geometry?.appliedMeshes?.delete(m) | |||||
| m.material = undefined | |||||
| m.geometry = undefined | |||||
| } | |||||
| // (inst.material as IMaterial).appliedMeshes?.add(inst) | |||||
| // inst.geometry.userData.__appliedMeshes.add(inst) | |||||
| // todo set position to center of all instances | |||||
| // @ts-expect-error todo not in ts | |||||
| inst.sourceTrs = { | |||||
| TRANSLATION: new BufferAttribute(translationAttr, 3), | |||||
| ROTATION: new BufferAttribute(rotationAttr, 4), | |||||
| SCALE: new BufferAttribute(scaleAttr, 3), | |||||
| } | |||||
| inst.instanceMatrix.needsUpdate = true | |||||
| parent.add(inst) | |||||
| ;(parent as any).setDirty() | |||||
| } | |||||
| } |
| export {threeConstMappings} from './const-mappings' | export {threeConstMappings} from './const-mappings' | ||||
| export {ObjectPicker} from './ObjectPicker' | export {ObjectPicker} from './ObjectPicker' | ||||
| export {SelectionWidget, BoxSelectionWidget} from './SelectionWidget' | export {SelectionWidget, BoxSelectionWidget} from './SelectionWidget' | ||||
| export {autoGPUInstanceMeshes} from './gpu-instancing' | |||||
| // export {} from './constants' | // export {} from './constants' |
| } | } | ||||
| static async LoadRootPathTextures({textures, images}: Pick<SerializationMetaType, 'textures'|'images'>, importer: IAssetImporter) { | |||||
| static async LoadRootPathTextures({textures, images}: Pick<SerializationMetaType, 'textures'|'images'>, importer: IAssetImporter, usePreviewImages = true) { | |||||
| const pms = [] | const pms = [] | ||||
| for (const inpTexture of Array.isArray(textures) ? textures : Object.values(textures ?? {} as any) as any as any[]) { | for (const inpTexture of Array.isArray(textures) ? textures : Object.values(textures ?? {} as any) as any as any[]) { | ||||
| const path = inpTexture?.userData?.rootPath | const path = inpTexture?.userData?.rootPath | ||||
| const hasImage = inpTexture.image && images[inpTexture.image] // its possible to have both image and rootPath, then the image will be preview image. | |||||
| const hasImage = usePreviewImages && inpTexture.image && images[inpTexture.image] // its possible to have both image and rootPath, then the image will be preview image. | |||||
| if (!path) continue | if (!path) continue | ||||
| // console.warn(path, inpTexture, images) | // console.warn(path, inpTexture, images) | ||||
| const promise = importer.importSingle<ITexture>(path, {processRaw: false}).then((texture) => { | const promise = importer.importSingle<ITexture>(path, {processRaw: false}).then((texture) => { |