소스 검색

Add support for 'textureUpdate' and texture's 'update' event, fix divide by 0, make resizeTrackedTargets in RenderTargetManager public, other minor fixes.

master
Palash Bansal 3 년 전
부모
커밋
3dcb3ea5a7
No account linked to committer's email address

+ 1
- 1
src/assetmanager/AssetImporter.ts 파일 보기

@@ -248,7 +248,7 @@ export class AssetImporter extends EventDispatcher<IAssetImporterEvent, IAssetIm

res = await loader.loadAsync(path + (options.queryString ? (path.includes('?') ? '&' : '?') + options.queryString : ''), (e)=>{
if (onDownloadProgress) onDownloadProgress(e)
this.dispatchEvent({type: 'importFile', path, state:'downloading', progress: e.loaded / e.total})
this.dispatchEvent({type: 'importFile', path, state:'downloading', progress: e.total > 0 ? e.loaded / e.total : 1})
})
if (loader.transform) res = await loader.transform(res, options)


+ 23
- 15
src/assetmanager/MaterialManager.ts 파일 보기

@@ -6,6 +6,7 @@ import {
IMaterialParameters,
IMaterialTemplate,
ITexture,
ITextureEvent,
PhysicalMaterial,
UnlitMaterial,
} from '../core'
@@ -121,24 +122,30 @@ export class MaterialManager<T = ''> extends EventDispatcher<BaseEvent, T> {
this._refreshTextureRefs(mat)
}

protected _textureUpdate = function(this: IMaterial, e: ITextureEvent<'update'>) {
if (!this || this.assetType !== 'material') return
this.dispatchEvent({texture: e.target, bubbleToParent: true, bubbleToObject: true, ...e, type: 'textureUpdate'})
}

private _refreshTextureRefs(mat: any) {
if (!mat.__textureUpdate) mat.__textureUpdate = this._textureUpdate.bind(mat)
const newMaps = this._getMapsForMaterial(mat)
const oldMaps = this._materialMaps.get(mat.uuid) || new Set<ITexture>()
newMaps.forEach(map => {
if (!oldMaps.has(map)) {
if (!map.userData.__appliedMaterials) map.userData.__appliedMaterials = new Set<IMaterial>()
map.userData.__appliedMaterials.add(mat)
}
})
oldMaps.forEach(map => {
if (!newMaps.has(map)) {
if (!map.userData.__appliedMaterials) return
const mats = map.userData.__appliedMaterials
mats?.delete(mat)
if (!mats || map.userData.disposeOnIdle === false) return
if (mats.size === 0) map.dispose()
}
})
for (const map of newMaps) {
if (oldMaps.has(map)) continue
if (!map.userData.__appliedMaterials) map.userData.__appliedMaterials = new Set<IMaterial>()
map.userData.__appliedMaterials.add(mat)
map.addEventListener('update', mat.__textureUpdate)
}
for (const map of oldMaps) {
if (newMaps.has(map)) continue
map.removeEventListener('update', mat.__textureUpdate)
if (!map.userData.__appliedMaterials) continue
const mats = map.userData.__appliedMaterials
mats?.delete(mat)
if (!mats || map.userData.disposeOnIdle === false) continue
if (mats.size === 0) map.dispose()
}
this._materialMaps.set(mat.uuid, newMaps)
}

@@ -289,6 +296,7 @@ export class MaterialManager<T = ''> extends EventDispatcher<BaseEvent, T> {
for (const c of currentMats) {
// console.log(c)
if (!c) continue
if (c === material) continue
if (c.userData.__isVariation) continue
const cType = Object.getPrototypeOf(c).constructor.TYPE
// console.log(cType, mType)

+ 1
- 1
src/core/IMaterial.ts 파일 보기

@@ -8,7 +8,7 @@ import type {ITexture} from './ITexture'
import type {IImportResultUserData} from '../assetmanager'

export type IMaterialParameters = MaterialParameters & {customMaterialExtensions?: MaterialExtension[]}
export type IMaterialEventTypes = 'dispose' | 'materialUpdate' | 'beforeRender' | 'beforeCompile' | 'afterRender' | 'textureChanged' | 'beforeDeserialize'
export type IMaterialEventTypes = 'dispose' | 'materialUpdate' | 'beforeRender' | 'beforeCompile' | 'afterRender' | 'textureUpdate' | 'beforeDeserialize'
export type IMaterialEvent<T extends string = IMaterialEventTypes> = Event & {
type: T
bubbleToObject?: boolean

+ 1
- 1
src/core/IObject.ts 파일 보기

@@ -6,7 +6,7 @@ import {IGeometry, IGeometryEvent} from './IGeometry'
import {IImportResultUserData} from '../assetmanager'
import {GLTF} from 'three/examples/jsm/loaders/GLTFLoader.js'

export type IObject3DEventTypes = 'dispose' | 'materialUpdate' | 'objectUpdate' | 'geometryChanged' |
export type IObject3DEventTypes = 'dispose' | 'materialUpdate' | 'objectUpdate' | 'textureUpdate' | 'geometryChanged' |
'materialChanged' | 'geometryUpdate' | 'added' | 'removed' | 'select' | 'beforeDeserialize' |
'setView' | 'activateMain' | 'cameraUpdate' // from camera
// | string

+ 9
- 1
src/core/ITexture.ts 파일 보기

@@ -1,11 +1,19 @@
import {IMaterial} from './IMaterial'
import {Texture} from 'three'
import {Event, Texture} from 'three'
import {ChangeEvent} from 'uiconfig.js'

export interface ITextureUserData{
mimeType?: string
disposeOnIdle?: boolean // automatically dispose when added to a material and then not used in any material
__appliedMaterials?: Set<IMaterial>
}
export type ITextureEventTypes = 'dispose' | 'update'
export type ITextureEvent<T extends string = ITextureEventTypes> = Event & {
type: T
texture?: ITexture
uiChangeEvent?: ChangeEvent
}

export interface ITexture extends Texture {
assetType?: 'texture'
userData: ITextureUserData

+ 1
- 1
src/core/index.ts 파일 보기

@@ -17,4 +17,4 @@ export type {IMaterial, IMaterialEvent, IMaterialEventTypes, IMaterialParameters
export type {IObject3D, IObject3DEvent, IObjectSetDirtyOptions, IObjectProcessor, IObject3DEventTypes, IObject3DUserData} from './IObject'
export type {IRenderManager, IRenderManagerOptions, IWebGLRenderer, IRenderManagerEventTypes, IAnimationLoopEvent, TThreeRendererMode, TThreeRendererModeUserData, IRenderManagerUpdateEvent, IRenderManagerEvent} from './IRenderer'
export type {IScene, ISceneEvent, ISceneEventTypes, ISceneSetDirtyOptions, AddObjectOptions, ISceneUserData, IWidget} from './IScene'
export type {ITexture, ITextureUserData} from './ITexture'
export type {ITexture, ITextureUserData, ITextureEvent, ITextureEventTypes} from './ITexture'

+ 1
- 1
src/core/material/iMaterialCommons.ts 파일 보기

@@ -128,7 +128,7 @@ export const iMaterialCommons = {
superDispatchEvent.call(this, event)
const type = event.type
if (event.bubbleToObject && (
type === 'beforeDeserialize' || type === 'materialUpdate' // todo - add more events
type === 'beforeDeserialize' || type === 'materialUpdate' || type === 'textureUpdate' // todo - add more events
)) {
this.appliedMeshes.forEach(m => m.dispatchEvent({...event, material: this, type}))
}

+ 1
- 1
src/rendering/RenderManager.ts 파일 보기

@@ -160,7 +160,7 @@ export class RenderManager extends RenderTargetManager<IRenderManagerEvent, IRen
this._composer.setPixelRatio(this._renderScale, false)
this._composer.setSize(this._renderSize.width, this._renderSize.height)

this._resizeTracedTargets()
this.resizeTrackedTargets()

// console.log('setSize', {...this._renderSize}, this._trackedTargets.length)


+ 17
- 10
src/rendering/RenderTargetManager.ts 파일 보기

@@ -2,6 +2,7 @@ import {Class} from 'ts-browser-helpers'
import {createRenderTargetKey, CreateRenderTargetOptions, IRenderTarget} from './RenderTarget'
import {
BaseEvent,
ClampToEdgeWrapping,
DepthTexture,
EventDispatcher,
LinearFilter,
@@ -187,15 +188,19 @@ export abstract class RenderTargetManager<E extends BaseEvent = BaseEvent, ET ex
this._trackedTempTargets = []
}

protected _resizeTracedTargets() {
this._trackedTargets.forEach(v=>{
const target = v as any as WebGLRenderTarget
const multiplier = (target as any).sizeMultiplier
if (multiplier) {
const s = this.renderSize.clone().multiplyScalar(this.renderScale * multiplier)
target.setSize(Math.floor(s.width), Math.floor(s.height))
}
})
/**
* Resizes all tracked targets with a sizeMultiplier based on the current renderSize and renderScale.
* This must be automatically called by the renderer on resize, and manually when sizeMultiplier of a target changes.
*/
resizeTrackedTargets() {
for (const v of this._trackedTargets) this.resizeTrackedTarget(v)
}
resizeTrackedTarget(target: IRenderTarget): void {
const multiplier = target.sizeMultiplier
if (multiplier) {
const s = this.renderSize.clone().multiplyScalar(this.renderScale * multiplier)
target.setSize(Math.floor(s.width), Math.floor(s.height))
}
}

private _processNewTempTarget(target: IRenderTarget, key: string): IRenderTarget {
@@ -215,8 +220,10 @@ export abstract class RenderTargetManager<E extends BaseEvent = BaseEvent, ET ex
private _setTargetTextureOptions(texture: Texture, op: CreateRenderTargetOptions) {
texture.minFilter = op.minFilter ?? LinearFilter
texture.magFilter = op.magFilter ?? LinearFilter
texture.wrapS = op.wrapS ?? ClampToEdgeWrapping
texture.wrapT = op.wrapT ?? ClampToEdgeWrapping
texture.generateMipmaps = op.generateMipmaps ?? false
if (texture.generateMipmaps && texture.minFilter === LinearFilter) // todo: check if this is needed for magFilter
if (texture.generateMipmaps && texture.minFilter === LinearFilter)
texture.minFilter = LinearMipMapLinearFilter
if (!texture.generateMipmaps && texture.minFilter === LinearMipMapLinearFilter)
texture.minFilter = LinearFilter

+ 2
- 1
src/utils/serialization.ts 파일 보기

@@ -286,6 +286,7 @@ export class ThreeSerialization {
if (!obj?.isWebGLRenderTarget || !obj.uuid) throw new Error('Expected a IRenderTarget')
if (meta?.extras[obj.uuid]) return {uuid: obj.uuid, resource: 'extras'}

// This is for the class implementing IRenderTarget, check {@link RenderTargetManager} for class implementation
const tex = Array.isArray(obj.texture) ? obj.texture[0] : obj.texture
let res: any = {
metadata: {type: 'RenderTarget'},
@@ -714,7 +715,7 @@ export function metaToResources(meta?: SerializationMetaType): Partial<Serializa
if (!meta) return {}
const res: Partial<SerializationResourcesType> = {...meta}
if (res._context) delete res._context
return meta
return res
}
export function metaFromResources(resources?: Partial<SerializationResourcesType>, viewer?: ThreeViewer): SerializationMetaType {
return {

+ 1
- 0
src/viewer/ThreeViewer.ts 파일 보기

@@ -255,6 +255,7 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
this._scene.addEventListener('materialUpdate', (e) => this.setDirty(this._scene, e))
this._scene.addEventListener('materialChanged', (e) => this.setDirty(this._scene, e))
this._scene.addEventListener('objectUpdate', (e) => this.setDirty(this._scene, e))
this._scene.addEventListener('textureUpdate', (e) => this.setDirty(this._scene, e))
this._scene.addEventListener('sceneUpdate', (e) => {
this.setDirty(this._scene, e)
if (e.geometryChanged === false) return

Loading…
취소
저장