@babylonjs/core 7.10.0 → 7.10.2
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/Audio/Interfaces/IAudioEngine.d.ts +2 -0
- package/Audio/Interfaces/IAudioEngine.js.map +1 -1
- package/Audio/audioEngine.d.ts +2 -0
- package/Audio/audioEngine.js +12 -0
- package/Audio/audioEngine.js.map +1 -1
- package/Collisions/gpuPicker.d.ts +15 -6
- package/Collisions/gpuPicker.js +83 -89
- package/Collisions/gpuPicker.js.map +1 -1
- package/Engines/AbstractEngine/abstractEngine.cubeTexture.d.ts +1 -1
- package/Engines/AbstractEngine/abstractEngine.cubeTexture.js +7 -3
- package/Engines/AbstractEngine/abstractEngine.cubeTexture.js.map +1 -1
- package/Engines/Extensions/engine.cubeTexture.d.ts +3 -2
- package/Engines/Extensions/engine.cubeTexture.js +2 -2
- package/Engines/Extensions/engine.cubeTexture.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.cubeTexture.d.ts +3 -2
- package/Engines/WebGPU/Extensions/engine.cubeTexture.js +2 -2
- package/Engines/WebGPU/Extensions/engine.cubeTexture.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.videoTexture.js +12 -4
- package/Engines/WebGPU/Extensions/engine.videoTexture.js.map +1 -1
- package/Engines/WebGPU/webgpuShaderProcessorsWGSL.js +2 -3
- package/Engines/WebGPU/webgpuShaderProcessorsWGSL.js.map +1 -1
- package/Engines/abstractEngine.js +2 -2
- package/Engines/abstractEngine.js.map +1 -1
- package/Engines/nativeEngine.d.ts +2 -1
- package/Engines/nativeEngine.js +7 -2
- package/Engines/nativeEngine.js.map +1 -1
- package/Layers/layer.js +5 -3
- package/Layers/layer.js.map +1 -1
- package/Loading/Plugins/babylonFileLoader.js +1 -1
- package/Loading/Plugins/babylonFileLoader.js.map +1 -1
- package/Materials/Node/Blocks/Dual/currentScreenBlock.js +13 -4
- package/Materials/Node/Blocks/Dual/currentScreenBlock.js.map +1 -1
- package/Materials/Node/Blocks/Dual/sceneDepthBlock.js +12 -3
- package/Materials/Node/Blocks/Dual/sceneDepthBlock.js.map +1 -1
- package/Materials/Node/nodeMaterial.js +7 -7
- package/Materials/Node/nodeMaterial.js.map +1 -1
- package/Materials/Textures/cubeTexture.d.ts +38 -3
- package/Materials/Textures/cubeTexture.js +36 -14
- package/Materials/Textures/cubeTexture.js.map +1 -1
- package/Materials/Textures/internalTexture.js +1 -1
- package/Materials/Textures/internalTexture.js.map +1 -1
- package/Materials/shaderMaterial.d.ts +0 -5
- package/Materials/shaderMaterial.js +1 -8
- package/Materials/shaderMaterial.js.map +1 -1
- package/Meshes/mesh.js +2 -2
- package/Meshes/mesh.js.map +1 -1
- package/Shaders/picking.fragment.d.ts +5 -0
- package/Shaders/picking.fragment.js +20 -0
- package/Shaders/picking.fragment.js.map +1 -0
- package/Shaders/picking.vertex.d.ts +15 -0
- package/Shaders/picking.vertex.js +42 -0
- package/Shaders/picking.vertex.js.map +1 -0
- package/ShadersWGSL/ShadersInclude/shadowsFragmentFunctions.js +1 -1
- package/ShadersWGSL/ShadersInclude/shadowsFragmentFunctions.js.map +1 -1
- package/XR/webXRExperienceHelper.js +3 -0
- package/XR/webXRExperienceHelper.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IAudioEngine.js","sourceRoot":"","sources":["../../../../../dev/core/src/Audio/Interfaces/IAudioEngine.ts"],"names":[],"mappings":"","sourcesContent":["import type { Observable } from \"../../Misc/observable\";\r\nimport type { IDisposable } from \"../../scene\";\r\nimport type { Nullable } from \"../../types\";\r\nimport type { Analyser } from \"../analyser\";\r\n\r\n/**\r\n * This represents an audio engine and it is responsible\r\n * to play, synchronize and analyse sounds throughout the application.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic\r\n */\r\nexport interface IAudioEngine extends IDisposable {\r\n /**\r\n * Gets whether the current host supports Web Audio and thus could create AudioContexts.\r\n */\r\n readonly canUseWebAudio: boolean;\r\n\r\n /**\r\n * Gets the current AudioContext if available.\r\n */\r\n readonly audioContext: Nullable<AudioContext>;\r\n\r\n /**\r\n * The master gain node defines the global audio volume of your audio engine.\r\n */\r\n readonly masterGain: GainNode;\r\n\r\n /**\r\n * Gets whether or not mp3 are supported by your browser.\r\n */\r\n readonly isMP3supported: boolean;\r\n\r\n /**\r\n * Gets whether or not ogg are supported by your browser.\r\n */\r\n readonly isOGGsupported: boolean;\r\n\r\n /**\r\n * Defines if Babylon should emit a warning if WebAudio is not supported.\r\n * @ignoreNaming\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n WarnedWebAudioUnsupported: boolean;\r\n\r\n /**\r\n * Defines if the audio engine relies on a custom unlocked button.\r\n * In this case, the embedded button will not be displayed.\r\n */\r\n useCustomUnlockedButton: boolean;\r\n\r\n /**\r\n * Gets whether or not the audio engine is unlocked (require first a user gesture on some browser).\r\n */\r\n readonly unlocked: boolean;\r\n\r\n /**\r\n * Event raised when audio has been unlocked on the browser.\r\n */\r\n onAudioUnlockedObservable: Observable<IAudioEngine>;\r\n\r\n /**\r\n * Event raised when audio has been locked on the browser.\r\n */\r\n onAudioLockedObservable: Observable<IAudioEngine>;\r\n\r\n /**\r\n * Flags the audio engine in Locked state.\r\n * This happens due to new browser policies preventing audio to autoplay.\r\n */\r\n lock(): void;\r\n\r\n /**\r\n * Unlocks the audio engine once a user action has been done on the dom.\r\n * This is helpful to resume play once browser policies have been satisfied.\r\n */\r\n unlock(): void;\r\n\r\n /**\r\n * Gets the global volume sets on the master gain.\r\n * @returns the global volume if set or -1 otherwise\r\n */\r\n getGlobalVolume(): number;\r\n\r\n /**\r\n * Sets the global volume of your experience (sets on the master gain).\r\n * @param newVolume Defines the new global volume of the application\r\n */\r\n setGlobalVolume(newVolume: number): void;\r\n\r\n /**\r\n * Connect the audio engine to an audio analyser allowing some amazing\r\n * synchronization between the sounds/music and your visualization (VuMeter for instance).\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic#using-the-analyser\r\n * @param analyser The analyser to connect to the engine\r\n */\r\n connectToAnalyser(analyser: Analyser): void;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"IAudioEngine.js","sourceRoot":"","sources":["../../../../../dev/core/src/Audio/Interfaces/IAudioEngine.ts"],"names":[],"mappings":"","sourcesContent":["import type { Observable } from \"../../Misc/observable\";\r\nimport type { IDisposable } from \"../../scene\";\r\nimport type { Nullable } from \"../../types\";\r\nimport type { Analyser } from \"../analyser\";\r\n\r\n/**\r\n * This represents an audio engine and it is responsible\r\n * to play, synchronize and analyse sounds throughout the application.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic\r\n */\r\nexport interface IAudioEngine extends IDisposable {\r\n /**\r\n * Gets whether the current host supports Web Audio and thus could create AudioContexts.\r\n */\r\n readonly canUseWebAudio: boolean;\r\n\r\n /**\r\n * Gets the current AudioContext if available.\r\n */\r\n readonly audioContext: Nullable<AudioContext>;\r\n\r\n /**\r\n * The master gain node defines the global audio volume of your audio engine.\r\n */\r\n readonly masterGain: GainNode;\r\n\r\n /**\r\n * Gets whether or not mp3 are supported by your browser.\r\n */\r\n readonly isMP3supported: boolean;\r\n\r\n /**\r\n * Gets whether or not ogg are supported by your browser.\r\n */\r\n readonly isOGGsupported: boolean;\r\n\r\n /**\r\n * Defines if Babylon should emit a warning if WebAudio is not supported.\r\n * @ignoreNaming\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n WarnedWebAudioUnsupported: boolean;\r\n\r\n /**\r\n * Defines if the audio engine relies on a custom unlocked button.\r\n * In this case, the embedded button will not be displayed.\r\n */\r\n useCustomUnlockedButton: boolean;\r\n\r\n /**\r\n * Gets whether or not the audio engine is unlocked (require first a user gesture on some browser).\r\n */\r\n readonly unlocked: boolean;\r\n\r\n /**\r\n * Event raised when audio has been unlocked on the browser.\r\n */\r\n onAudioUnlockedObservable: Observable<IAudioEngine>;\r\n\r\n /**\r\n * Event raised when audio has been locked on the browser.\r\n */\r\n onAudioLockedObservable: Observable<IAudioEngine>;\r\n\r\n /**\r\n * Flags the audio engine in Locked state.\r\n * This happens due to new browser policies preventing audio to autoplay.\r\n */\r\n lock(): void;\r\n\r\n /**\r\n * Unlocks the audio engine once a user action has been done on the dom.\r\n * This is helpful to resume play once browser policies have been satisfied.\r\n */\r\n unlock(): void;\r\n\r\n /**\r\n * Gets the global volume sets on the master gain.\r\n * @returns the global volume if set or -1 otherwise\r\n */\r\n getGlobalVolume(): number;\r\n\r\n /**\r\n * Sets the global volume of your experience (sets on the master gain).\r\n * @param newVolume Defines the new global volume of the application\r\n */\r\n setGlobalVolume(newVolume: number): void;\r\n\r\n /**\r\n * Connect the audio engine to an audio analyser allowing some amazing\r\n * synchronization between the sounds/music and your visualization (VuMeter for instance).\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic#using-the-analyser\r\n * @param analyser The analyser to connect to the engine\r\n */\r\n connectToAnalyser(analyser: Analyser): void;\r\n\r\n /** @internal */\r\n _resumeAudioContextOnStateChange(): void;\r\n}\r\n"]}
|
package/Audio/audioEngine.d.ts
CHANGED
|
@@ -78,6 +78,8 @@ export declare class AudioEngine implements IAudioEngine {
|
|
|
78
78
|
* This is helpful to resume play once browser policies have been satisfied.
|
|
79
79
|
*/
|
|
80
80
|
unlock(): void;
|
|
81
|
+
/** @internal */
|
|
82
|
+
_resumeAudioContextOnStateChange(): void;
|
|
81
83
|
private _resumeAudioContext;
|
|
82
84
|
private _initializeAudioContext;
|
|
83
85
|
private _tryToRun;
|
package/Audio/audioEngine.js
CHANGED
|
@@ -139,6 +139,18 @@ export class AudioEngine {
|
|
|
139
139
|
this._triggerRunningState();
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
/** @internal */
|
|
143
|
+
_resumeAudioContextOnStateChange() {
|
|
144
|
+
this._audioContext?.addEventListener("statechange", () => {
|
|
145
|
+
if (this.unlocked && this._audioContext?.state !== "running") {
|
|
146
|
+
this._resumeAudioContext();
|
|
147
|
+
}
|
|
148
|
+
}, {
|
|
149
|
+
once: true,
|
|
150
|
+
passive: true,
|
|
151
|
+
signal: AbortSignal.timeout(3000),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
142
154
|
_resumeAudioContext() {
|
|
143
155
|
if (this._audioContext?.resume) {
|
|
144
156
|
return this._audioContext.resume();
|
package/Audio/audioEngine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audioEngine.js","sourceRoot":"","sources":["../../../../dev/core/src/Audio/audioEngine.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Analyser } from \"./analyser\";\r\n\r\nimport type { Nullable } from \"../types\";\r\nimport { Observable } from \"../Misc/observable\";\r\nimport { Logger } from \"../Misc/logger\";\r\nimport { AbstractEngine } from \"../Engines/abstractEngine\";\r\nimport type { IAudioEngine } from \"./Interfaces/IAudioEngine\";\r\nimport { IsWindowObjectExist } from \"../Misc/domManagement\";\r\n\r\n// Sets the default audio engine to Babylon.js\r\nAbstractEngine.AudioEngineFactory = (\r\n hostElement: Nullable<HTMLElement>,\r\n audioContext: Nullable<AudioContext>,\r\n audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode>\r\n) => {\r\n return new AudioEngine(hostElement, audioContext, audioDestination);\r\n};\r\n\r\n/**\r\n * This represents the default audio engine used in babylon.\r\n * It is responsible to play, synchronize and analyse sounds throughout the application.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic\r\n */\r\nexport class AudioEngine implements IAudioEngine {\r\n private _audioContext: Nullable<AudioContext> = null;\r\n private _audioContextInitialized = false;\r\n private _muteButton: Nullable<HTMLButtonElement> = null;\r\n private _hostElement: Nullable<HTMLElement>;\r\n private _audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode> = null;\r\n\r\n /**\r\n * Gets whether the current host supports Web Audio and thus could create AudioContexts.\r\n */\r\n public canUseWebAudio: boolean = false;\r\n\r\n /**\r\n * The master gain node defines the global audio volume of your audio engine.\r\n */\r\n public masterGain: GainNode;\r\n\r\n /**\r\n * Defines if Babylon should emit a warning if WebAudio is not supported.\r\n * @ignoreNaming\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public WarnedWebAudioUnsupported: boolean = false;\r\n\r\n /**\r\n * Gets whether or not mp3 are supported by your browser.\r\n */\r\n public isMP3supported: boolean = false;\r\n\r\n /**\r\n * Gets whether or not ogg are supported by your browser.\r\n */\r\n public isOGGsupported: boolean = false;\r\n\r\n /**\r\n * Gets whether audio has been unlocked on the device.\r\n * Some Browsers have strong restrictions about Audio and won't autoplay unless\r\n * a user interaction has happened.\r\n */\r\n public unlocked: boolean = false;\r\n\r\n /**\r\n * Defines if the audio engine relies on a custom unlocked button.\r\n * In this case, the embedded button will not be displayed.\r\n */\r\n public useCustomUnlockedButton: boolean = false;\r\n\r\n /**\r\n * Event raised when audio has been unlocked on the browser.\r\n */\r\n public onAudioUnlockedObservable = new Observable<IAudioEngine>();\r\n\r\n /**\r\n * Event raised when audio has been locked on the browser.\r\n */\r\n public onAudioLockedObservable = new Observable<IAudioEngine>();\r\n\r\n /**\r\n * Gets the current AudioContext if available.\r\n */\r\n public get audioContext(): Nullable<AudioContext> {\r\n if (!this._audioContextInitialized) {\r\n this._initializeAudioContext();\r\n }\r\n return this._audioContext;\r\n }\r\n\r\n private _connectedAnalyser: Nullable<Analyser>;\r\n\r\n /**\r\n * Instantiates a new audio engine.\r\n *\r\n * There should be only one per page as some browsers restrict the number\r\n * of audio contexts you can create.\r\n * @param hostElement defines the host element where to display the mute icon if necessary\r\n * @param audioContext defines the audio context to be used by the audio engine\r\n * @param audioDestination defines the audio destination node to be used by audio engine\r\n */\r\n constructor(\r\n hostElement: Nullable<HTMLElement> = null,\r\n audioContext: Nullable<AudioContext> = null,\r\n audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode> = null\r\n ) {\r\n if (!IsWindowObjectExist()) {\r\n return;\r\n }\r\n if (typeof window.AudioContext !== \"undefined\") {\r\n this.canUseWebAudio = true;\r\n }\r\n\r\n const audioElem = document.createElement(\"audio\");\r\n this._hostElement = hostElement;\r\n this._audioContext = audioContext;\r\n this._audioDestination = audioDestination;\r\n\r\n try {\r\n if (\r\n audioElem &&\r\n !!audioElem.canPlayType &&\r\n (audioElem.canPlayType('audio/mpeg; codecs=\"mp3\"').replace(/^no$/, \"\") || audioElem.canPlayType(\"audio/mp3\").replace(/^no$/, \"\"))\r\n ) {\r\n this.isMP3supported = true;\r\n }\r\n } catch (e) {\r\n // protect error during capability check.\r\n }\r\n\r\n try {\r\n if (audioElem && !!audioElem.canPlayType && audioElem.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, \"\")) {\r\n this.isOGGsupported = true;\r\n }\r\n } catch (e) {\r\n // protect error during capability check.\r\n }\r\n }\r\n\r\n /**\r\n * Flags the audio engine in Locked state.\r\n * This happens due to new browser policies preventing audio to autoplay.\r\n */\r\n public lock() {\r\n this._triggerSuspendedState();\r\n }\r\n\r\n /**\r\n * Unlocks the audio engine once a user action has been done on the dom.\r\n * This is helpful to resume play once browser policies have been satisfied.\r\n */\r\n public unlock() {\r\n if (this._audioContext?.state === \"running\") {\r\n this._hideMuteButton();\r\n\r\n if (!this.unlocked) {\r\n // Notify users that the audio stack is unlocked/unmuted\r\n this.unlocked = true;\r\n this.onAudioUnlockedObservable.notifyObservers(this);\r\n }\r\n\r\n return;\r\n }\r\n\r\n // On iOS, if the audio context resume request was sent from an event other than a `click` event, then\r\n // the resume promise will never resolve and the only way to get the audio context unstuck is to\r\n // suspend it and make another resume request.\r\n if (this._tryToRun) {\r\n this._audioContext?.suspend().then(() => {\r\n this._tryToRun = false;\r\n this._triggerRunningState();\r\n });\r\n } else {\r\n this._triggerRunningState();\r\n }\r\n }\r\n\r\n private _resumeAudioContext(): Promise<void> {\r\n if (this._audioContext?.resume) {\r\n return this._audioContext.resume();\r\n }\r\n return Promise.resolve();\r\n }\r\n\r\n private _initializeAudioContext() {\r\n try {\r\n if (this.canUseWebAudio) {\r\n if (!this._audioContext) {\r\n this._audioContext = new AudioContext();\r\n }\r\n // create a global volume gain node\r\n this.masterGain = this._audioContext.createGain();\r\n this.masterGain.gain.value = 1;\r\n if (!this._audioDestination) {\r\n this._audioDestination = this._audioContext.destination;\r\n }\r\n this.masterGain.connect(this._audioDestination);\r\n this._audioContextInitialized = true;\r\n if (this._audioContext.state === \"running\") {\r\n // Do not wait for the promise to unlock.\r\n this._triggerRunningState();\r\n }\r\n }\r\n } catch (e) {\r\n this.canUseWebAudio = false;\r\n Logger.Error(\"Web Audio: \" + e.message);\r\n }\r\n }\r\n\r\n private _tryToRun = false;\r\n private _triggerRunningState() {\r\n if (this._tryToRun) {\r\n return;\r\n }\r\n this._tryToRun = true;\r\n\r\n this._resumeAudioContext()\r\n .then(() => {\r\n this._tryToRun = false;\r\n if (this._muteButton) {\r\n this._hideMuteButton();\r\n }\r\n // Notify users that the audio stack is unlocked/unmuted\r\n this.unlocked = true;\r\n this.onAudioUnlockedObservable.notifyObservers(this);\r\n })\r\n .catch(() => {\r\n this._tryToRun = false;\r\n this.unlocked = false;\r\n });\r\n }\r\n\r\n private _triggerSuspendedState() {\r\n this.unlocked = false;\r\n this.onAudioLockedObservable.notifyObservers(this);\r\n this._displayMuteButton();\r\n }\r\n\r\n private _displayMuteButton() {\r\n if (this.useCustomUnlockedButton || this._muteButton) {\r\n return;\r\n }\r\n\r\n this._muteButton = <HTMLButtonElement>document.createElement(\"BUTTON\");\r\n this._muteButton.className = \"babylonUnmuteIcon\";\r\n this._muteButton.id = \"babylonUnmuteIconBtn\";\r\n this._muteButton.title = \"Unmute\";\r\n const imageUrl = !window.SVGSVGElement\r\n ? \"https://cdn.babylonjs.com/Assets/audio.png\"\r\n : \"data:image/svg+xml;charset=UTF-8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2239%22%20height%3D%2232%22%20viewBox%3D%220%200%2039%2032%22%3E%3Cpath%20fill%3D%22white%22%20d%3D%22M9.625%2018.938l-0.031%200.016h-4.953q-0.016%200-0.031-0.016v-12.453q0-0.016%200.031-0.016h4.953q0.031%200%200.031%200.016v12.453zM12.125%207.688l8.719-8.703v27.453l-8.719-8.719-0.016-0.047v-9.938zM23.359%207.875l1.406-1.406%204.219%204.203%204.203-4.203%201.422%201.406-4.219%204.219%204.219%204.203-1.484%201.359-4.141-4.156-4.219%204.219-1.406-1.422%204.219-4.203z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E\";\r\n\r\n const css =\r\n \".babylonUnmuteIcon { position: absolute; left: 20px; top: 20px; height: 40px; width: 60px; background-color: rgba(51,51,51,0.7); background-image: url(\" +\r\n imageUrl +\r\n \"); background-size: 80%; background-repeat:no-repeat; background-position: center; background-position-y: 4px; border: none; outline: none; transition: transform 0.125s ease-out; cursor: pointer; z-index: 9999; } .babylonUnmuteIcon:hover { transform: scale(1.05) } .babylonUnmuteIcon:active { background-color: rgba(51,51,51,1) }\";\r\n\r\n const style = document.createElement(\"style\");\r\n style.appendChild(document.createTextNode(css));\r\n document.getElementsByTagName(\"head\")[0].appendChild(style);\r\n\r\n document.body.appendChild(this._muteButton);\r\n\r\n this._moveButtonToTopLeft();\r\n\r\n this._muteButton.addEventListener(\r\n \"touchend\",\r\n () => {\r\n this._triggerRunningState();\r\n },\r\n true\r\n );\r\n this._muteButton.addEventListener(\r\n \"click\",\r\n () => {\r\n this.unlock();\r\n },\r\n true\r\n );\r\n\r\n window.addEventListener(\"resize\", this._onResize);\r\n }\r\n\r\n private _moveButtonToTopLeft() {\r\n if (this._hostElement && this._muteButton) {\r\n this._muteButton.style.top = this._hostElement.offsetTop + 20 + \"px\";\r\n this._muteButton.style.left = this._hostElement.offsetLeft + 20 + \"px\";\r\n }\r\n }\r\n\r\n private _onResize = () => {\r\n this._moveButtonToTopLeft();\r\n };\r\n\r\n private _hideMuteButton() {\r\n if (this._muteButton) {\r\n document.body.removeChild(this._muteButton);\r\n this._muteButton = null;\r\n }\r\n }\r\n\r\n /**\r\n * Destroy and release the resources associated with the audio context.\r\n */\r\n public dispose(): void {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n if (this._connectedAnalyser && this._audioContext) {\r\n this._connectedAnalyser.stopDebugCanvas();\r\n this._connectedAnalyser.dispose();\r\n this.masterGain.disconnect();\r\n this.masterGain.connect(this._audioContext.destination);\r\n this._connectedAnalyser = null;\r\n }\r\n this.masterGain.gain.value = 1;\r\n }\r\n this.WarnedWebAudioUnsupported = false;\r\n this._hideMuteButton();\r\n window.removeEventListener(\"resize\", this._onResize);\r\n\r\n this.onAudioUnlockedObservable.clear();\r\n this.onAudioLockedObservable.clear();\r\n }\r\n\r\n /**\r\n * Gets the global volume sets on the master gain.\r\n * @returns the global volume if set or -1 otherwise\r\n */\r\n public getGlobalVolume(): number {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n return this.masterGain.gain.value;\r\n } else {\r\n return -1;\r\n }\r\n }\r\n\r\n /**\r\n * Sets the global volume of your experience (sets on the master gain).\r\n * @param newVolume Defines the new global volume of the application\r\n */\r\n public setGlobalVolume(newVolume: number): void {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n this.masterGain.gain.value = newVolume;\r\n }\r\n }\r\n\r\n /**\r\n * Connect the audio engine to an audio analyser allowing some amazing\r\n * synchronization between the sounds/music and your visualization (VuMeter for instance).\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic#using-the-analyser\r\n * @param analyser The analyser to connect to the engine\r\n */\r\n public connectToAnalyser(analyser: Analyser): void {\r\n if (this._connectedAnalyser) {\r\n this._connectedAnalyser.stopDebugCanvas();\r\n }\r\n if (this.canUseWebAudio && this._audioContextInitialized && this._audioContext) {\r\n this._connectedAnalyser = analyser;\r\n this.masterGain.disconnect();\r\n this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);\r\n }\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"audioEngine.js","sourceRoot":"","sources":["../../../../dev/core/src/Audio/audioEngine.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Analyser } from \"./analyser\";\r\n\r\nimport type { Nullable } from \"../types\";\r\nimport { Observable } from \"../Misc/observable\";\r\nimport { Logger } from \"../Misc/logger\";\r\nimport { AbstractEngine } from \"../Engines/abstractEngine\";\r\nimport type { IAudioEngine } from \"./Interfaces/IAudioEngine\";\r\nimport { IsWindowObjectExist } from \"../Misc/domManagement\";\r\n\r\n// Sets the default audio engine to Babylon.js\r\nAbstractEngine.AudioEngineFactory = (\r\n hostElement: Nullable<HTMLElement>,\r\n audioContext: Nullable<AudioContext>,\r\n audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode>\r\n) => {\r\n return new AudioEngine(hostElement, audioContext, audioDestination);\r\n};\r\n\r\n/**\r\n * This represents the default audio engine used in babylon.\r\n * It is responsible to play, synchronize and analyse sounds throughout the application.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic\r\n */\r\nexport class AudioEngine implements IAudioEngine {\r\n private _audioContext: Nullable<AudioContext> = null;\r\n private _audioContextInitialized = false;\r\n private _muteButton: Nullable<HTMLButtonElement> = null;\r\n private _hostElement: Nullable<HTMLElement>;\r\n private _audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode> = null;\r\n\r\n /**\r\n * Gets whether the current host supports Web Audio and thus could create AudioContexts.\r\n */\r\n public canUseWebAudio: boolean = false;\r\n\r\n /**\r\n * The master gain node defines the global audio volume of your audio engine.\r\n */\r\n public masterGain: GainNode;\r\n\r\n /**\r\n * Defines if Babylon should emit a warning if WebAudio is not supported.\r\n * @ignoreNaming\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public WarnedWebAudioUnsupported: boolean = false;\r\n\r\n /**\r\n * Gets whether or not mp3 are supported by your browser.\r\n */\r\n public isMP3supported: boolean = false;\r\n\r\n /**\r\n * Gets whether or not ogg are supported by your browser.\r\n */\r\n public isOGGsupported: boolean = false;\r\n\r\n /**\r\n * Gets whether audio has been unlocked on the device.\r\n * Some Browsers have strong restrictions about Audio and won't autoplay unless\r\n * a user interaction has happened.\r\n */\r\n public unlocked: boolean = false;\r\n\r\n /**\r\n * Defines if the audio engine relies on a custom unlocked button.\r\n * In this case, the embedded button will not be displayed.\r\n */\r\n public useCustomUnlockedButton: boolean = false;\r\n\r\n /**\r\n * Event raised when audio has been unlocked on the browser.\r\n */\r\n public onAudioUnlockedObservable = new Observable<IAudioEngine>();\r\n\r\n /**\r\n * Event raised when audio has been locked on the browser.\r\n */\r\n public onAudioLockedObservable = new Observable<IAudioEngine>();\r\n\r\n /**\r\n * Gets the current AudioContext if available.\r\n */\r\n public get audioContext(): Nullable<AudioContext> {\r\n if (!this._audioContextInitialized) {\r\n this._initializeAudioContext();\r\n }\r\n return this._audioContext;\r\n }\r\n\r\n private _connectedAnalyser: Nullable<Analyser>;\r\n\r\n /**\r\n * Instantiates a new audio engine.\r\n *\r\n * There should be only one per page as some browsers restrict the number\r\n * of audio contexts you can create.\r\n * @param hostElement defines the host element where to display the mute icon if necessary\r\n * @param audioContext defines the audio context to be used by the audio engine\r\n * @param audioDestination defines the audio destination node to be used by audio engine\r\n */\r\n constructor(\r\n hostElement: Nullable<HTMLElement> = null,\r\n audioContext: Nullable<AudioContext> = null,\r\n audioDestination: Nullable<AudioDestinationNode | MediaStreamAudioDestinationNode> = null\r\n ) {\r\n if (!IsWindowObjectExist()) {\r\n return;\r\n }\r\n if (typeof window.AudioContext !== \"undefined\") {\r\n this.canUseWebAudio = true;\r\n }\r\n\r\n const audioElem = document.createElement(\"audio\");\r\n this._hostElement = hostElement;\r\n this._audioContext = audioContext;\r\n this._audioDestination = audioDestination;\r\n\r\n try {\r\n if (\r\n audioElem &&\r\n !!audioElem.canPlayType &&\r\n (audioElem.canPlayType('audio/mpeg; codecs=\"mp3\"').replace(/^no$/, \"\") || audioElem.canPlayType(\"audio/mp3\").replace(/^no$/, \"\"))\r\n ) {\r\n this.isMP3supported = true;\r\n }\r\n } catch (e) {\r\n // protect error during capability check.\r\n }\r\n\r\n try {\r\n if (audioElem && !!audioElem.canPlayType && audioElem.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, \"\")) {\r\n this.isOGGsupported = true;\r\n }\r\n } catch (e) {\r\n // protect error during capability check.\r\n }\r\n }\r\n\r\n /**\r\n * Flags the audio engine in Locked state.\r\n * This happens due to new browser policies preventing audio to autoplay.\r\n */\r\n public lock() {\r\n this._triggerSuspendedState();\r\n }\r\n\r\n /**\r\n * Unlocks the audio engine once a user action has been done on the dom.\r\n * This is helpful to resume play once browser policies have been satisfied.\r\n */\r\n public unlock() {\r\n if (this._audioContext?.state === \"running\") {\r\n this._hideMuteButton();\r\n\r\n if (!this.unlocked) {\r\n // Notify users that the audio stack is unlocked/unmuted\r\n this.unlocked = true;\r\n this.onAudioUnlockedObservable.notifyObservers(this);\r\n }\r\n\r\n return;\r\n }\r\n\r\n // On iOS, if the audio context resume request was sent from an event other than a `click` event, then\r\n // the resume promise will never resolve and the only way to get the audio context unstuck is to\r\n // suspend it and make another resume request.\r\n if (this._tryToRun) {\r\n this._audioContext?.suspend().then(() => {\r\n this._tryToRun = false;\r\n this._triggerRunningState();\r\n });\r\n } else {\r\n this._triggerRunningState();\r\n }\r\n }\r\n\r\n /** @internal */\r\n public _resumeAudioContextOnStateChange(): void {\r\n this._audioContext?.addEventListener(\r\n \"statechange\",\r\n () => {\r\n if (this.unlocked && this._audioContext?.state !== \"running\") {\r\n this._resumeAudioContext();\r\n }\r\n },\r\n {\r\n once: true,\r\n passive: true,\r\n signal: AbortSignal.timeout(3000),\r\n }\r\n );\r\n }\r\n\r\n private _resumeAudioContext(): Promise<void> {\r\n if (this._audioContext?.resume) {\r\n return this._audioContext.resume();\r\n }\r\n return Promise.resolve();\r\n }\r\n\r\n private _initializeAudioContext() {\r\n try {\r\n if (this.canUseWebAudio) {\r\n if (!this._audioContext) {\r\n this._audioContext = new AudioContext();\r\n }\r\n // create a global volume gain node\r\n this.masterGain = this._audioContext.createGain();\r\n this.masterGain.gain.value = 1;\r\n if (!this._audioDestination) {\r\n this._audioDestination = this._audioContext.destination;\r\n }\r\n this.masterGain.connect(this._audioDestination);\r\n this._audioContextInitialized = true;\r\n if (this._audioContext.state === \"running\") {\r\n // Do not wait for the promise to unlock.\r\n this._triggerRunningState();\r\n }\r\n }\r\n } catch (e) {\r\n this.canUseWebAudio = false;\r\n Logger.Error(\"Web Audio: \" + e.message);\r\n }\r\n }\r\n\r\n private _tryToRun = false;\r\n private _triggerRunningState() {\r\n if (this._tryToRun) {\r\n return;\r\n }\r\n this._tryToRun = true;\r\n\r\n this._resumeAudioContext()\r\n .then(() => {\r\n this._tryToRun = false;\r\n if (this._muteButton) {\r\n this._hideMuteButton();\r\n }\r\n // Notify users that the audio stack is unlocked/unmuted\r\n this.unlocked = true;\r\n this.onAudioUnlockedObservable.notifyObservers(this);\r\n })\r\n .catch(() => {\r\n this._tryToRun = false;\r\n this.unlocked = false;\r\n });\r\n }\r\n\r\n private _triggerSuspendedState() {\r\n this.unlocked = false;\r\n this.onAudioLockedObservable.notifyObservers(this);\r\n this._displayMuteButton();\r\n }\r\n\r\n private _displayMuteButton() {\r\n if (this.useCustomUnlockedButton || this._muteButton) {\r\n return;\r\n }\r\n\r\n this._muteButton = <HTMLButtonElement>document.createElement(\"BUTTON\");\r\n this._muteButton.className = \"babylonUnmuteIcon\";\r\n this._muteButton.id = \"babylonUnmuteIconBtn\";\r\n this._muteButton.title = \"Unmute\";\r\n const imageUrl = !window.SVGSVGElement\r\n ? \"https://cdn.babylonjs.com/Assets/audio.png\"\r\n : \"data:image/svg+xml;charset=UTF-8,%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2239%22%20height%3D%2232%22%20viewBox%3D%220%200%2039%2032%22%3E%3Cpath%20fill%3D%22white%22%20d%3D%22M9.625%2018.938l-0.031%200.016h-4.953q-0.016%200-0.031-0.016v-12.453q0-0.016%200.031-0.016h4.953q0.031%200%200.031%200.016v12.453zM12.125%207.688l8.719-8.703v27.453l-8.719-8.719-0.016-0.047v-9.938zM23.359%207.875l1.406-1.406%204.219%204.203%204.203-4.203%201.422%201.406-4.219%204.219%204.219%204.203-1.484%201.359-4.141-4.156-4.219%204.219-1.406-1.422%204.219-4.203z%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E\";\r\n\r\n const css =\r\n \".babylonUnmuteIcon { position: absolute; left: 20px; top: 20px; height: 40px; width: 60px; background-color: rgba(51,51,51,0.7); background-image: url(\" +\r\n imageUrl +\r\n \"); background-size: 80%; background-repeat:no-repeat; background-position: center; background-position-y: 4px; border: none; outline: none; transition: transform 0.125s ease-out; cursor: pointer; z-index: 9999; } .babylonUnmuteIcon:hover { transform: scale(1.05) } .babylonUnmuteIcon:active { background-color: rgba(51,51,51,1) }\";\r\n\r\n const style = document.createElement(\"style\");\r\n style.appendChild(document.createTextNode(css));\r\n document.getElementsByTagName(\"head\")[0].appendChild(style);\r\n\r\n document.body.appendChild(this._muteButton);\r\n\r\n this._moveButtonToTopLeft();\r\n\r\n this._muteButton.addEventListener(\r\n \"touchend\",\r\n () => {\r\n this._triggerRunningState();\r\n },\r\n true\r\n );\r\n this._muteButton.addEventListener(\r\n \"click\",\r\n () => {\r\n this.unlock();\r\n },\r\n true\r\n );\r\n\r\n window.addEventListener(\"resize\", this._onResize);\r\n }\r\n\r\n private _moveButtonToTopLeft() {\r\n if (this._hostElement && this._muteButton) {\r\n this._muteButton.style.top = this._hostElement.offsetTop + 20 + \"px\";\r\n this._muteButton.style.left = this._hostElement.offsetLeft + 20 + \"px\";\r\n }\r\n }\r\n\r\n private _onResize = () => {\r\n this._moveButtonToTopLeft();\r\n };\r\n\r\n private _hideMuteButton() {\r\n if (this._muteButton) {\r\n document.body.removeChild(this._muteButton);\r\n this._muteButton = null;\r\n }\r\n }\r\n\r\n /**\r\n * Destroy and release the resources associated with the audio context.\r\n */\r\n public dispose(): void {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n if (this._connectedAnalyser && this._audioContext) {\r\n this._connectedAnalyser.stopDebugCanvas();\r\n this._connectedAnalyser.dispose();\r\n this.masterGain.disconnect();\r\n this.masterGain.connect(this._audioContext.destination);\r\n this._connectedAnalyser = null;\r\n }\r\n this.masterGain.gain.value = 1;\r\n }\r\n this.WarnedWebAudioUnsupported = false;\r\n this._hideMuteButton();\r\n window.removeEventListener(\"resize\", this._onResize);\r\n\r\n this.onAudioUnlockedObservable.clear();\r\n this.onAudioLockedObservable.clear();\r\n }\r\n\r\n /**\r\n * Gets the global volume sets on the master gain.\r\n * @returns the global volume if set or -1 otherwise\r\n */\r\n public getGlobalVolume(): number {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n return this.masterGain.gain.value;\r\n } else {\r\n return -1;\r\n }\r\n }\r\n\r\n /**\r\n * Sets the global volume of your experience (sets on the master gain).\r\n * @param newVolume Defines the new global volume of the application\r\n */\r\n public setGlobalVolume(newVolume: number): void {\r\n if (this.canUseWebAudio && this._audioContextInitialized) {\r\n this.masterGain.gain.value = newVolume;\r\n }\r\n }\r\n\r\n /**\r\n * Connect the audio engine to an audio analyser allowing some amazing\r\n * synchronization between the sounds/music and your visualization (VuMeter for instance).\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/audio/playingSoundsMusic#using-the-analyser\r\n * @param analyser The analyser to connect to the engine\r\n */\r\n public connectToAnalyser(analyser: Analyser): void {\r\n if (this._connectedAnalyser) {\r\n this._connectedAnalyser.stopDebugCanvas();\r\n }\r\n if (this.canUseWebAudio && this._audioContextInitialized && this._audioContext) {\r\n this._connectedAnalyser = analyser;\r\n this.masterGain.disconnect();\r\n this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { AbstractMesh } from "../Meshes/abstractMesh.js";
|
|
2
|
-
import type { Scene } from "../scene.js";
|
|
3
2
|
import type { Nullable } from "../types.js";
|
|
3
|
+
import "../Shaders/picking.fragment";
|
|
4
|
+
import "../Shaders/picking.vertex";
|
|
5
|
+
/**
|
|
6
|
+
* Class used to store the result of a GPU picking operation
|
|
7
|
+
*/
|
|
8
|
+
export interface IGPUPickingInfo {
|
|
9
|
+
/**
|
|
10
|
+
* Picked mesh
|
|
11
|
+
*/
|
|
12
|
+
mesh: AbstractMesh;
|
|
13
|
+
}
|
|
4
14
|
/**
|
|
5
15
|
* Class used to perform a picking operation using GPU
|
|
6
16
|
* Please note that GPUPIcker cannot pick instances, only meshes
|
|
@@ -9,17 +19,17 @@ export declare class GPUPicker {
|
|
|
9
19
|
private _pickingTexure;
|
|
10
20
|
private _idMap;
|
|
11
21
|
private _idColors;
|
|
12
|
-
private _cachedMaterials;
|
|
13
22
|
private _cachedScene;
|
|
14
23
|
private _renderMaterial;
|
|
15
24
|
private _pickableMeshes;
|
|
16
25
|
private _readbuffer;
|
|
17
26
|
private _meshRenderingCount;
|
|
18
|
-
private
|
|
27
|
+
private readonly _attributeName;
|
|
19
28
|
private _createRenderTarget;
|
|
20
29
|
private _createColorMaterial;
|
|
21
30
|
/**
|
|
22
31
|
* Set the list of meshes to pick from
|
|
32
|
+
* Set that value to null to clear the list (and avoid leaks)
|
|
23
33
|
* @param list defines the list of meshes to pick from
|
|
24
34
|
*/
|
|
25
35
|
setPickingList(list: Nullable<Array<AbstractMesh>>): void;
|
|
@@ -27,11 +37,10 @@ export declare class GPUPicker {
|
|
|
27
37
|
* Execute a picking operation
|
|
28
38
|
* @param x defines the X coordinates where to run the pick
|
|
29
39
|
* @param y defines the Y coordinates where to run the pick
|
|
30
|
-
* @param
|
|
31
|
-
* @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive
|
|
40
|
+
* @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive (false by default)
|
|
32
41
|
* @returns A promise with the picking results
|
|
33
42
|
*/
|
|
34
|
-
pickAsync(x: number, y: number,
|
|
43
|
+
pickAsync(x: number, y: number, disposeWhenDone?: boolean): Promise<Nullable<IGPUPickingInfo>>;
|
|
35
44
|
private _readTexturePixelsAsync;
|
|
36
45
|
/** Release the resources */
|
|
37
46
|
dispose(): void;
|
package/Collisions/gpuPicker.js
CHANGED
|
@@ -3,6 +3,8 @@ import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture.j
|
|
|
3
3
|
import { ShaderMaterial } from "../Materials/shaderMaterial.js";
|
|
4
4
|
import { Color3, Color4 } from "../Maths/math.color.js";
|
|
5
5
|
import { VertexBuffer } from "../Meshes/buffer.js";
|
|
6
|
+
import "../Shaders/picking.fragment.js";
|
|
7
|
+
import "../Shaders/picking.vertex.js";
|
|
6
8
|
/**
|
|
7
9
|
* Class used to perform a picking operation using GPU
|
|
8
10
|
* Please note that GPUPIcker cannot pick instances, only meshes
|
|
@@ -10,13 +12,15 @@ import { VertexBuffer } from "../Meshes/buffer.js";
|
|
|
10
12
|
export class GPUPicker {
|
|
11
13
|
constructor() {
|
|
12
14
|
this._pickingTexure = null;
|
|
13
|
-
this._idMap =
|
|
15
|
+
this._idMap = [];
|
|
14
16
|
this._idColors = [];
|
|
15
|
-
this._cachedMaterials = [];
|
|
16
17
|
this._meshRenderingCount = 0;
|
|
17
|
-
this.
|
|
18
|
+
this._attributeName = "instanceMeshID";
|
|
18
19
|
}
|
|
19
20
|
_createRenderTarget(scene, width, height) {
|
|
21
|
+
if (this._pickingTexure) {
|
|
22
|
+
this._pickingTexure.dispose();
|
|
23
|
+
}
|
|
20
24
|
this._pickingTexure = new RenderTargetTexture("pickingTexure", { width: width, height: height }, scene, false, undefined, 0, false, 1);
|
|
21
25
|
}
|
|
22
26
|
_createColorMaterial(scene) {
|
|
@@ -25,59 +29,85 @@ export class GPUPicker {
|
|
|
25
29
|
}
|
|
26
30
|
const defines = [];
|
|
27
31
|
const options = {
|
|
28
|
-
attributes: [VertexBuffer.PositionKind],
|
|
29
|
-
uniforms: ["world", "viewProjection", "
|
|
32
|
+
attributes: [VertexBuffer.PositionKind, this._attributeName],
|
|
33
|
+
uniforms: ["world", "viewProjection", "meshID"],
|
|
30
34
|
needAlphaBlending: false,
|
|
31
35
|
defines: defines,
|
|
32
36
|
useClipPlane: null,
|
|
33
37
|
};
|
|
34
|
-
this._renderMaterial = new ShaderMaterial("
|
|
38
|
+
this._renderMaterial = new ShaderMaterial("pickingShader", scene, "picking", options, false);
|
|
35
39
|
const callback = (mesh) => {
|
|
36
40
|
if (!mesh) {
|
|
37
41
|
return;
|
|
38
42
|
}
|
|
39
43
|
const effect = this._renderMaterial.getEffect();
|
|
40
44
|
if (!mesh.hasInstances && !mesh.isAnInstance) {
|
|
41
|
-
effect.setColor4("
|
|
45
|
+
effect.setColor4("meshID", this._idColors[mesh.uniqueId], 1);
|
|
42
46
|
}
|
|
43
47
|
this._meshRenderingCount++;
|
|
44
48
|
};
|
|
45
|
-
this._renderMaterial.
|
|
49
|
+
this._renderMaterial.onBindObservable.add(callback);
|
|
46
50
|
}
|
|
47
51
|
/**
|
|
48
52
|
* Set the list of meshes to pick from
|
|
53
|
+
* Set that value to null to clear the list (and avoid leaks)
|
|
49
54
|
* @param list defines the list of meshes to pick from
|
|
50
55
|
*/
|
|
51
56
|
setPickingList(list) {
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
57
|
+
if (this._pickableMeshes) {
|
|
58
|
+
// Cleanup
|
|
59
|
+
for (let index = 0; index < this._pickableMeshes.length; index++) {
|
|
60
|
+
const mesh = this._pickableMeshes[index];
|
|
61
|
+
if (mesh.hasInstances) {
|
|
62
|
+
mesh.removeVerticesData(this._attributeName);
|
|
59
63
|
}
|
|
64
|
+
if (this._pickingTexure) {
|
|
65
|
+
this._pickingTexure.setMaterialForRendering(mesh, undefined);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
this._pickableMeshes.length = 0;
|
|
69
|
+
this._idMap.length = 0;
|
|
70
|
+
this._idColors.length = 0;
|
|
71
|
+
if (this._pickingTexure) {
|
|
72
|
+
this._pickingTexure.renderList = [];
|
|
60
73
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this._idMap = {};
|
|
64
|
-
this._idColors = [];
|
|
74
|
+
}
|
|
75
|
+
if (!list || list.length === 0) {
|
|
65
76
|
return;
|
|
66
77
|
}
|
|
67
|
-
this._userDefinedList = true;
|
|
68
78
|
this._pickableMeshes = list;
|
|
79
|
+
// Prepare target
|
|
80
|
+
const scene = list[0].getScene();
|
|
81
|
+
const engine = scene.getEngine();
|
|
82
|
+
const rttSizeW = engine.getRenderWidth();
|
|
83
|
+
const rttSizeH = engine.getRenderHeight();
|
|
84
|
+
if (!this._pickingTexure) {
|
|
85
|
+
this._createRenderTarget(scene, rttSizeW, rttSizeH);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const size = this._pickingTexure.getSize();
|
|
89
|
+
if (size.width !== rttSizeW || size.height !== rttSizeH || this._cachedScene !== scene) {
|
|
90
|
+
this._createRenderTarget(scene, rttSizeW, rttSizeH);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (!this._cachedScene || this._cachedScene !== scene) {
|
|
94
|
+
this._createColorMaterial(scene);
|
|
95
|
+
}
|
|
96
|
+
this._cachedScene = scene;
|
|
97
|
+
this._pickingTexure.renderList = [];
|
|
69
98
|
// We will affect colors and create vertex color buffers
|
|
70
99
|
let id = 1;
|
|
71
100
|
for (let index = 0; index < this._pickableMeshes.length; index++) {
|
|
72
101
|
const mesh = this._pickableMeshes[index];
|
|
73
|
-
mesh.
|
|
102
|
+
this._pickingTexure.setMaterialForRendering(mesh, this._renderMaterial);
|
|
103
|
+
this._pickingTexure.renderList.push(mesh);
|
|
74
104
|
if (mesh.isAnInstance) {
|
|
75
105
|
continue; // This will be handled by the source mesh
|
|
76
106
|
}
|
|
77
107
|
const r = (id & 0xff0000) >> 16;
|
|
78
108
|
const g = (id & 0x00ff00) >> 8;
|
|
79
109
|
const b = (id & 0x0000ff) >> 0;
|
|
80
|
-
this._idMap[
|
|
110
|
+
this._idMap[id] = index;
|
|
81
111
|
id++;
|
|
82
112
|
if (mesh.hasInstances) {
|
|
83
113
|
const instances = mesh.instances;
|
|
@@ -92,14 +122,14 @@ export class GPUPicker {
|
|
|
92
122
|
const r = (id & 0xff0000) >> 16;
|
|
93
123
|
const g = (id & 0x00ff00) >> 8;
|
|
94
124
|
const b = (id & 0x0000ff) >> 0;
|
|
95
|
-
this._idMap[
|
|
125
|
+
this._idMap[id] = this._pickableMeshes.indexOf(instance);
|
|
96
126
|
colorData[(i + 1) * 4] = r / 255.0;
|
|
97
127
|
colorData[(i + 1) * 4 + 1] = g / 255.0;
|
|
98
128
|
colorData[(i + 1) * 4 + 2] = b / 255.0;
|
|
99
129
|
colorData[(i + 1) * 4 + 3] = 1.0;
|
|
100
130
|
id++;
|
|
101
131
|
}
|
|
102
|
-
const buffer = new VertexBuffer(engine, colorData,
|
|
132
|
+
const buffer = new VertexBuffer(engine, colorData, this._attributeName, false, false, 4, true);
|
|
103
133
|
mesh.setVerticesBuffer(buffer, true);
|
|
104
134
|
}
|
|
105
135
|
else {
|
|
@@ -111,17 +141,31 @@ export class GPUPicker {
|
|
|
111
141
|
* Execute a picking operation
|
|
112
142
|
* @param x defines the X coordinates where to run the pick
|
|
113
143
|
* @param y defines the Y coordinates where to run the pick
|
|
114
|
-
* @param
|
|
115
|
-
* @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive
|
|
144
|
+
* @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive (false by default)
|
|
116
145
|
* @returns A promise with the picking results
|
|
117
146
|
*/
|
|
118
|
-
pickAsync(x, y,
|
|
147
|
+
pickAsync(x, y, disposeWhenDone = false) {
|
|
148
|
+
if (!this._pickableMeshes || this._pickableMeshes.length === 0) {
|
|
149
|
+
return Promise.resolve(null);
|
|
150
|
+
}
|
|
151
|
+
const scene = this._cachedScene;
|
|
119
152
|
const engine = scene.getEngine();
|
|
120
153
|
const rttSizeW = engine.getRenderWidth();
|
|
121
154
|
const rttSizeH = engine.getRenderHeight();
|
|
122
155
|
if (!this._readbuffer) {
|
|
123
156
|
this._readbuffer = new Uint8Array(engine.isWebGPU ? 256 : 4); // Because of block alignment in WebGPU
|
|
124
157
|
}
|
|
158
|
+
// Do we need to rebuild the RTT?
|
|
159
|
+
const size = this._pickingTexure.getSize();
|
|
160
|
+
if (size.width !== rttSizeW || size.height !== rttSizeH) {
|
|
161
|
+
this._createRenderTarget(scene, rttSizeW, rttSizeH);
|
|
162
|
+
this._pickingTexure.renderList = [];
|
|
163
|
+
for (let index = 0; index < this._pickableMeshes.length; index++) {
|
|
164
|
+
const mesh = this._pickableMeshes[index];
|
|
165
|
+
this._pickingTexure.setMaterialForRendering(mesh, this._renderMaterial);
|
|
166
|
+
this._pickingTexure.renderList.push(mesh);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
125
169
|
this._meshRenderingCount = 0;
|
|
126
170
|
// Ensure ints
|
|
127
171
|
x = x >> 0;
|
|
@@ -131,48 +175,9 @@ export class GPUPicker {
|
|
|
131
175
|
}
|
|
132
176
|
// Invert Y
|
|
133
177
|
y = rttSizeH - y;
|
|
134
|
-
if (!this._pickingTexure) {
|
|
135
|
-
this._createRenderTarget(scene, rttSizeW, rttSizeH);
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
const size = this._pickingTexure.getSize();
|
|
139
|
-
if (size.width !== rttSizeW || size.height !== rttSizeH || this._cachedScene !== scene) {
|
|
140
|
-
this._pickingTexure.dispose();
|
|
141
|
-
this._createRenderTarget(scene, rttSizeW, rttSizeH);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (!this._cachedScene || this._cachedScene !== scene) {
|
|
145
|
-
this._createColorMaterial(scene);
|
|
146
|
-
}
|
|
147
|
-
this._cachedScene = scene;
|
|
148
|
-
scene.customRenderTargets.push(this._pickingTexure);
|
|
149
|
-
this._pickingTexure.renderList = [];
|
|
150
178
|
this._pickingTexure.clearColor = new Color4(0, 0, 0, 0);
|
|
151
|
-
|
|
179
|
+
scene.customRenderTargets.push(this._pickingTexure);
|
|
152
180
|
this._pickingTexure.onBeforeRender = () => {
|
|
153
|
-
if (!this._userDefinedList) {
|
|
154
|
-
this._pickableMeshes = scene.meshes.filter((m) => m.geometry && m.isPickable && m.onBeforeRenderObservable);
|
|
155
|
-
}
|
|
156
|
-
for (let index = 0; index < this._pickableMeshes.length; index++) {
|
|
157
|
-
const mesh = this._pickableMeshes[index];
|
|
158
|
-
if (!mesh.isAnInstance) {
|
|
159
|
-
this._cachedMaterials[index] = mesh.material;
|
|
160
|
-
if (!this._userDefinedList) {
|
|
161
|
-
// We need to define the color for each mesh as it was not previously defined
|
|
162
|
-
const id = index + 1;
|
|
163
|
-
const r = (id & 0xff0000) >> 16;
|
|
164
|
-
const g = (id & 0x00ff00) >> 8;
|
|
165
|
-
const b = (id & 0x0000ff) >> 0;
|
|
166
|
-
this._idMap[`${r}_${g}_${b}`] = index;
|
|
167
|
-
this._idColors[mesh.uniqueId] = Color3.FromInts(r, g, b);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
mesh.useVertexColors = true; // In that case we will be using vertex colors and not an uniform to support instances
|
|
171
|
-
}
|
|
172
|
-
mesh.material = this._renderMaterial;
|
|
173
|
-
}
|
|
174
|
-
this._pickingTexure?.renderList?.push(mesh);
|
|
175
|
-
}
|
|
176
181
|
// Enable scissor
|
|
177
182
|
if (engine.enableScissor) {
|
|
178
183
|
engine.enableScissor(x, y, 1, 1);
|
|
@@ -189,16 +194,6 @@ export class GPUPicker {
|
|
|
189
194
|
}
|
|
190
195
|
let pickedMesh = null;
|
|
191
196
|
const wasSuccessfull = this._meshRenderingCount > 0;
|
|
192
|
-
// Restore materials
|
|
193
|
-
for (let index = 0; index < this._pickableMeshes.length; index++) {
|
|
194
|
-
const mesh = this._pickableMeshes[index];
|
|
195
|
-
if (!mesh.isAnInstance) {
|
|
196
|
-
mesh.material = this._cachedMaterials[index];
|
|
197
|
-
if (this._userDefinedList) {
|
|
198
|
-
mesh.useVertexColors = false;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
197
|
if (wasSuccessfull) {
|
|
203
198
|
// Remove from the active RTTs
|
|
204
199
|
const index = scene.customRenderTargets.indexOf(this._pickingTexure);
|
|
@@ -207,17 +202,14 @@ export class GPUPicker {
|
|
|
207
202
|
}
|
|
208
203
|
// Do the actual picking
|
|
209
204
|
if (await this._readTexturePixelsAsync(x, y)) {
|
|
210
|
-
const
|
|
205
|
+
const r = this._readbuffer[0];
|
|
206
|
+
const g = this._readbuffer[1];
|
|
207
|
+
const b = this._readbuffer[2];
|
|
208
|
+
const colorId = (r << 16) + (g << 8) + b;
|
|
211
209
|
pickedMesh = this._pickableMeshes[this._idMap[colorId]];
|
|
212
210
|
}
|
|
213
211
|
}
|
|
214
212
|
// Clean-up
|
|
215
|
-
if (!this._userDefinedList) {
|
|
216
|
-
this._idMap = {};
|
|
217
|
-
this._idColors = [];
|
|
218
|
-
this._pickableMeshes = [];
|
|
219
|
-
}
|
|
220
|
-
this._pickingTexure.renderList = [];
|
|
221
213
|
if (!wasSuccessfull) {
|
|
222
214
|
this._meshRenderingCount = 0;
|
|
223
215
|
return; // We need to wait for the shaders to be ready
|
|
@@ -226,7 +218,12 @@ export class GPUPicker {
|
|
|
226
218
|
if (disposeWhenDone) {
|
|
227
219
|
this.dispose();
|
|
228
220
|
}
|
|
229
|
-
|
|
221
|
+
if (pickedMesh) {
|
|
222
|
+
resolve({ mesh: pickedMesh });
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
resolve(null);
|
|
226
|
+
}
|
|
230
227
|
}
|
|
231
228
|
};
|
|
232
229
|
});
|
|
@@ -241,10 +238,7 @@ export class GPUPicker {
|
|
|
241
238
|
}
|
|
242
239
|
/** Release the resources */
|
|
243
240
|
dispose() {
|
|
244
|
-
|
|
245
|
-
this.setPickingList(null);
|
|
246
|
-
}
|
|
247
|
-
this._pickableMeshes = [];
|
|
241
|
+
this.setPickingList(null);
|
|
248
242
|
this._cachedScene = null;
|
|
249
243
|
// Cleaning up
|
|
250
244
|
this._pickingTexure?.dispose();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gpuPicker.js","sourceRoot":"","sources":["../../../../dev/core/src/Collisions/gpuPicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Constants } from \"core/Engines/constants\";\r\nimport type { Engine } from \"core/Engines/engine\";\r\nimport type { WebGPUEngine } from \"core/Engines/webgpuEngine\";\r\nimport { RenderTargetTexture } from \"core/Materials/Textures/renderTargetTexture\";\r\nimport type { Material } from \"core/Materials/material\";\r\nimport { ShaderMaterial } from \"core/Materials/shaderMaterial\";\r\nimport { Color3, Color4 } from \"core/Maths/math.color\";\r\nimport type { AbstractMesh } from \"core/Meshes/abstractMesh\";\r\nimport { VertexBuffer } from \"core/Meshes/buffer\";\r\nimport type { Mesh } from \"core/Meshes/mesh\";\r\nimport type { Scene } from \"core/scene\";\r\nimport type { Nullable } from \"core/types\";\r\n\r\n/**\r\n * Class used to perform a picking operation using GPU\r\n * Please note that GPUPIcker cannot pick instances, only meshes\r\n */\r\nexport class GPUPicker {\r\n private _pickingTexure: Nullable<RenderTargetTexture> = null;\r\n private _idMap: { [key: string]: number } = {};\r\n private _idColors: Array<Color3> = [];\r\n private _cachedMaterials: Array<Nullable<Material>> = [];\r\n private _cachedScene: Nullable<Scene>;\r\n private _renderMaterial: Nullable<ShaderMaterial>;\r\n private _pickableMeshes: Array<AbstractMesh>;\r\n private _readbuffer: Uint8Array;\r\n private _meshRenderingCount: number = 0;\r\n private _userDefinedList = false;\r\n\r\n private _createRenderTarget(scene: Scene, width: number, height: number) {\r\n this._pickingTexure = new RenderTargetTexture(\r\n \"pickingTexure\",\r\n { width: width, height: height },\r\n scene,\r\n false,\r\n undefined,\r\n Constants.TEXTURETYPE_UNSIGNED_INT,\r\n false,\r\n Constants.TEXTURE_NEAREST_NEAREST\r\n );\r\n }\r\n\r\n private _createColorMaterial(scene: Scene) {\r\n if (this._renderMaterial) {\r\n this._renderMaterial.dispose();\r\n }\r\n\r\n const defines: string[] = [];\r\n const options = {\r\n attributes: [VertexBuffer.PositionKind],\r\n uniforms: [\"world\", \"viewProjection\", \"color\"],\r\n needAlphaBlending: false,\r\n defines: defines,\r\n useClipPlane: null,\r\n };\r\n\r\n this._renderMaterial = new ShaderMaterial(\"colorShader\", scene, \"color\", options, false);\r\n\r\n const callback = (mesh: AbstractMesh | undefined) => {\r\n if (!mesh) {\r\n return;\r\n }\r\n\r\n const effect = this._renderMaterial!.getEffect();\r\n\r\n if (!mesh.hasInstances && !mesh.isAnInstance) {\r\n effect.setColor4(\"color\", this._idColors[mesh.uniqueId], 1);\r\n }\r\n\r\n this._meshRenderingCount++;\r\n };\r\n\r\n this._renderMaterial.customBindingObservable.add(callback);\r\n }\r\n\r\n /**\r\n * Set the list of meshes to pick from\r\n * @param list defines the list of meshes to pick from\r\n */\r\n public setPickingList(list: Nullable<Array<AbstractMesh>>) {\r\n if (!list) {\r\n if (this._userDefinedList) {\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n if (mesh.hasInstances) {\r\n (mesh as Mesh).removeVerticesData(VertexBuffer.ColorKind);\r\n }\r\n }\r\n }\r\n this._userDefinedList = false;\r\n this._pickableMeshes = [];\r\n this._idMap = {};\r\n this._idColors = [];\r\n return;\r\n }\r\n this._userDefinedList = true;\r\n this._pickableMeshes = list;\r\n\r\n // We will affect colors and create vertex color buffers\r\n let id = 1;\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n mesh.useVertexColors = false;\r\n\r\n if (mesh.isAnInstance) {\r\n continue; // This will be handled by the source mesh\r\n }\r\n\r\n const r = (id & 0xff0000) >> 16;\r\n const g = (id & 0x00ff00) >> 8;\r\n const b = (id & 0x0000ff) >> 0;\r\n this._idMap[`${r}_${g}_${b}`] = index;\r\n id++;\r\n\r\n if (mesh.hasInstances) {\r\n const instances = (mesh as Mesh).instances;\r\n const colorData = new Float32Array(4 * (instances.length + 1));\r\n const engine = mesh.getEngine();\r\n\r\n colorData[0] = r / 255.0;\r\n colorData[1] = g / 255.0;\r\n colorData[2] = b / 255.0;\r\n colorData[3] = 1.0;\r\n for (let i = 0; i < instances.length; i++) {\r\n const instance = instances[i];\r\n const r = (id & 0xff0000) >> 16;\r\n const g = (id & 0x00ff00) >> 8;\r\n const b = (id & 0x0000ff) >> 0;\r\n this._idMap[`${r}_${g}_${b}`] = this._pickableMeshes.indexOf(instance);\r\n\r\n colorData[(i + 1) * 4] = r / 255.0;\r\n colorData[(i + 1) * 4 + 1] = g / 255.0;\r\n colorData[(i + 1) * 4 + 2] = b / 255.0;\r\n colorData[(i + 1) * 4 + 3] = 1.0;\r\n id++;\r\n }\r\n\r\n const buffer = new VertexBuffer(engine, colorData, VertexBuffer.ColorKind, false, false, 4, true);\r\n (mesh as Mesh).setVerticesBuffer(buffer, true);\r\n } else {\r\n this._idColors[mesh.uniqueId] = Color3.FromInts(r, g, b);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Execute a picking operation\r\n * @param x defines the X coordinates where to run the pick\r\n * @param y defines the Y coordinates where to run the pick\r\n * @param scene defines the scene to pick from\r\n * @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive\r\n * @returns A promise with the picking results\r\n */\r\n public pickAsync(x: number, y: number, scene: Scene, disposeWhenDone = true): Promise<Nullable<AbstractMesh>> {\r\n const engine = scene.getEngine();\r\n const rttSizeW = engine.getRenderWidth();\r\n const rttSizeH = engine.getRenderHeight();\r\n\r\n if (!this._readbuffer) {\r\n this._readbuffer = new Uint8Array(engine.isWebGPU ? 256 : 4); // Because of block alignment in WebGPU\r\n }\r\n\r\n this._meshRenderingCount = 0;\r\n // Ensure ints\r\n x = x >> 0;\r\n y = y >> 0;\r\n\r\n if (x < 0 || y < 0 || x >= rttSizeW || y >= rttSizeH) {\r\n return Promise.resolve(null);\r\n }\r\n\r\n // Invert Y\r\n y = rttSizeH - y;\r\n\r\n if (!this._pickingTexure) {\r\n this._createRenderTarget(scene, rttSizeW, rttSizeH);\r\n } else {\r\n const size = this._pickingTexure.getSize();\r\n\r\n if (size.width !== rttSizeW || size.height !== rttSizeH || this._cachedScene !== scene) {\r\n this._pickingTexure.dispose();\r\n this._createRenderTarget(scene, rttSizeW, rttSizeH);\r\n }\r\n }\r\n\r\n if (!this._cachedScene || this._cachedScene !== scene) {\r\n this._createColorMaterial(scene);\r\n }\r\n\r\n this._cachedScene = scene;\r\n scene.customRenderTargets.push(this._pickingTexure!);\r\n this._pickingTexure!.renderList = [];\r\n this._pickingTexure!.clearColor = new Color4(0, 0, 0, 0);\r\n\r\n // We need to give every mesh an unique color (when there is no picking list)\r\n this._pickingTexure!.onBeforeRender = () => {\r\n if (!this._userDefinedList) {\r\n this._pickableMeshes = scene.meshes.filter((m) => (m as Mesh).geometry && m.isPickable && (m as Mesh).onBeforeRenderObservable) as Mesh[];\r\n }\r\n\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n if (!mesh.isAnInstance) {\r\n this._cachedMaterials[index] = mesh.material;\r\n if (!this._userDefinedList) {\r\n // We need to define the color for each mesh as it was not previously defined\r\n const id = index + 1;\r\n const r = (id & 0xff0000) >> 16;\r\n const g = (id & 0x00ff00) >> 8;\r\n const b = (id & 0x0000ff) >> 0;\r\n this._idMap[`${r}_${g}_${b}`] = index;\r\n\r\n this._idColors[mesh.uniqueId] = Color3.FromInts(r, g, b);\r\n } else {\r\n mesh.useVertexColors = true; // In that case we will be using vertex colors and not an uniform to support instances\r\n }\r\n mesh.material = this._renderMaterial;\r\n }\r\n this._pickingTexure?.renderList?.push(mesh);\r\n }\r\n\r\n // Enable scissor\r\n if ((engine as WebGPUEngine | Engine).enableScissor) {\r\n (engine as WebGPUEngine | Engine).enableScissor(x, y, 1, 1);\r\n }\r\n };\r\n\r\n return new Promise((resolve, reject) => {\r\n this._pickingTexure!.onAfterRender = async () => {\r\n // Disable scissor\r\n if ((engine as WebGPUEngine | Engine).disableScissor) {\r\n (engine as WebGPUEngine | Engine).disableScissor();\r\n }\r\n\r\n if (!this._pickingTexure) {\r\n reject();\r\n }\r\n\r\n let pickedMesh: Nullable<AbstractMesh> = null;\r\n const wasSuccessfull = this._meshRenderingCount > 0;\r\n\r\n // Restore materials\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n if (!mesh.isAnInstance) {\r\n mesh.material = this._cachedMaterials[index];\r\n\r\n if (this._userDefinedList) {\r\n mesh.useVertexColors = false;\r\n }\r\n }\r\n }\r\n\r\n if (wasSuccessfull) {\r\n // Remove from the active RTTs\r\n const index = scene.customRenderTargets.indexOf(this._pickingTexure!);\r\n if (index > -1) {\r\n scene.customRenderTargets.splice(index, 1);\r\n }\r\n\r\n // Do the actual picking\r\n if (await this._readTexturePixelsAsync(x, y)) {\r\n const colorId = `${this._readbuffer[0]}_${this._readbuffer[1]}_${this._readbuffer[2]}`;\r\n pickedMesh = this._pickableMeshes[this._idMap[colorId]];\r\n }\r\n }\r\n\r\n // Clean-up\r\n if (!this._userDefinedList) {\r\n this._idMap = {};\r\n this._idColors = [];\r\n\r\n this._pickableMeshes = [];\r\n }\r\n this._pickingTexure!.renderList = [];\r\n\r\n if (!wasSuccessfull) {\r\n this._meshRenderingCount = 0;\r\n return; // We need to wait for the shaders to be ready\r\n } else {\r\n if (disposeWhenDone) {\r\n this.dispose();\r\n }\r\n resolve(pickedMesh);\r\n }\r\n };\r\n });\r\n }\r\n\r\n private async _readTexturePixelsAsync(x: number, y: number) {\r\n if (!this._cachedScene || !this._pickingTexure?._texture) {\r\n return false;\r\n }\r\n const engine = this._cachedScene.getEngine();\r\n await engine._readTexturePixels(this._pickingTexure._texture, 1, 1, -1, 0, this._readbuffer, true, true, x, y);\r\n\r\n return true;\r\n }\r\n\r\n /** Release the resources */\r\n public dispose() {\r\n if (this._userDefinedList) {\r\n this.setPickingList(null);\r\n }\r\n this._pickableMeshes = [];\r\n this._cachedScene = null;\r\n\r\n // Cleaning up\r\n this._pickingTexure?.dispose();\r\n this._pickingTexure = null;\r\n this._renderMaterial?.dispose();\r\n this._renderMaterial = null;\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"gpuPicker.js","sourceRoot":"","sources":["../../../../dev/core/src/Collisions/gpuPicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Constants } from \"core/Engines/constants\";\r\nimport type { Engine } from \"core/Engines/engine\";\r\nimport type { WebGPUEngine } from \"core/Engines/webgpuEngine\";\r\nimport { RenderTargetTexture } from \"core/Materials/Textures/renderTargetTexture\";\r\nimport { ShaderMaterial } from \"core/Materials/shaderMaterial\";\r\nimport { Color3, Color4 } from \"core/Maths/math.color\";\r\nimport type { AbstractMesh } from \"core/Meshes/abstractMesh\";\r\nimport { VertexBuffer } from \"core/Meshes/buffer\";\r\nimport type { Mesh } from \"core/Meshes/mesh\";\r\nimport type { Scene } from \"core/scene\";\r\nimport type { Nullable } from \"core/types\";\r\n\r\nimport \"../Shaders/picking.fragment\";\r\nimport \"../Shaders/picking.vertex\";\r\n\r\n/**\r\n * Class used to store the result of a GPU picking operation\r\n */\r\nexport interface IGPUPickingInfo {\r\n /**\r\n * Picked mesh\r\n */\r\n mesh: AbstractMesh;\r\n}\r\n\r\n/**\r\n * Class used to perform a picking operation using GPU\r\n * Please note that GPUPIcker cannot pick instances, only meshes\r\n */\r\nexport class GPUPicker {\r\n private _pickingTexure: Nullable<RenderTargetTexture> = null;\r\n private _idMap: Array<number> = [];\r\n private _idColors: Array<Color3> = [];\r\n private _cachedScene: Nullable<Scene>;\r\n private _renderMaterial: Nullable<ShaderMaterial>;\r\n private _pickableMeshes: Array<AbstractMesh>;\r\n private _readbuffer: Uint8Array;\r\n private _meshRenderingCount: number = 0;\r\n private readonly _attributeName = \"instanceMeshID\";\r\n\r\n private _createRenderTarget(scene: Scene, width: number, height: number) {\r\n if (this._pickingTexure) {\r\n this._pickingTexure.dispose();\r\n }\r\n this._pickingTexure = new RenderTargetTexture(\r\n \"pickingTexure\",\r\n { width: width, height: height },\r\n scene,\r\n false,\r\n undefined,\r\n Constants.TEXTURETYPE_UNSIGNED_INT,\r\n false,\r\n Constants.TEXTURE_NEAREST_NEAREST\r\n );\r\n }\r\n\r\n private _createColorMaterial(scene: Scene) {\r\n if (this._renderMaterial) {\r\n this._renderMaterial.dispose();\r\n }\r\n\r\n const defines: string[] = [];\r\n const options = {\r\n attributes: [VertexBuffer.PositionKind, this._attributeName],\r\n uniforms: [\"world\", \"viewProjection\", \"meshID\"],\r\n needAlphaBlending: false,\r\n defines: defines,\r\n useClipPlane: null,\r\n };\r\n\r\n this._renderMaterial = new ShaderMaterial(\"pickingShader\", scene, \"picking\", options, false);\r\n\r\n const callback = (mesh: AbstractMesh | undefined) => {\r\n if (!mesh) {\r\n return;\r\n }\r\n\r\n const effect = this._renderMaterial!.getEffect();\r\n\r\n if (!mesh.hasInstances && !mesh.isAnInstance) {\r\n effect.setColor4(\"meshID\", this._idColors[mesh.uniqueId], 1);\r\n }\r\n\r\n this._meshRenderingCount++;\r\n };\r\n\r\n this._renderMaterial.onBindObservable.add(callback);\r\n }\r\n\r\n /**\r\n * Set the list of meshes to pick from\r\n * Set that value to null to clear the list (and avoid leaks)\r\n * @param list defines the list of meshes to pick from\r\n */\r\n public setPickingList(list: Nullable<Array<AbstractMesh>>) {\r\n if (this._pickableMeshes) {\r\n // Cleanup\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n if (mesh.hasInstances) {\r\n (mesh as Mesh).removeVerticesData(this._attributeName);\r\n }\r\n if (this._pickingTexure) {\r\n this._pickingTexure.setMaterialForRendering(mesh, undefined);\r\n }\r\n }\r\n this._pickableMeshes.length = 0;\r\n this._idMap.length = 0;\r\n this._idColors.length = 0;\r\n if (this._pickingTexure) {\r\n this._pickingTexure.renderList = [];\r\n }\r\n }\r\n if (!list || list.length === 0) {\r\n return;\r\n }\r\n this._pickableMeshes = list;\r\n\r\n // Prepare target\r\n const scene = list[0].getScene();\r\n const engine = scene.getEngine();\r\n const rttSizeW = engine.getRenderWidth();\r\n const rttSizeH = engine.getRenderHeight();\r\n if (!this._pickingTexure) {\r\n this._createRenderTarget(scene, rttSizeW, rttSizeH);\r\n } else {\r\n const size = this._pickingTexure.getSize();\r\n\r\n if (size.width !== rttSizeW || size.height !== rttSizeH || this._cachedScene !== scene) {\r\n this._createRenderTarget(scene, rttSizeW, rttSizeH);\r\n }\r\n }\r\n\r\n if (!this._cachedScene || this._cachedScene !== scene) {\r\n this._createColorMaterial(scene);\r\n }\r\n\r\n this._cachedScene = scene;\r\n this._pickingTexure!.renderList = [];\r\n\r\n // We will affect colors and create vertex color buffers\r\n let id = 1;\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n this._pickingTexure!.setMaterialForRendering(mesh, this._renderMaterial!);\r\n this._pickingTexure!.renderList.push(mesh);\r\n\r\n if (mesh.isAnInstance) {\r\n continue; // This will be handled by the source mesh\r\n }\r\n\r\n const r = (id & 0xff0000) >> 16;\r\n const g = (id & 0x00ff00) >> 8;\r\n const b = (id & 0x0000ff) >> 0;\r\n this._idMap[id] = index;\r\n id++;\r\n\r\n if (mesh.hasInstances) {\r\n const instances = (mesh as Mesh).instances;\r\n const colorData = new Float32Array(4 * (instances.length + 1));\r\n const engine = mesh.getEngine();\r\n\r\n colorData[0] = r / 255.0;\r\n colorData[1] = g / 255.0;\r\n colorData[2] = b / 255.0;\r\n colorData[3] = 1.0;\r\n for (let i = 0; i < instances.length; i++) {\r\n const instance = instances[i];\r\n const r = (id & 0xff0000) >> 16;\r\n const g = (id & 0x00ff00) >> 8;\r\n const b = (id & 0x0000ff) >> 0;\r\n this._idMap[id] = this._pickableMeshes.indexOf(instance);\r\n\r\n colorData[(i + 1) * 4] = r / 255.0;\r\n colorData[(i + 1) * 4 + 1] = g / 255.0;\r\n colorData[(i + 1) * 4 + 2] = b / 255.0;\r\n colorData[(i + 1) * 4 + 3] = 1.0;\r\n id++;\r\n }\r\n\r\n const buffer = new VertexBuffer(engine, colorData, this._attributeName, false, false, 4, true);\r\n (mesh as Mesh).setVerticesBuffer(buffer, true);\r\n } else {\r\n this._idColors[mesh.uniqueId] = Color3.FromInts(r, g, b);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Execute a picking operation\r\n * @param x defines the X coordinates where to run the pick\r\n * @param y defines the Y coordinates where to run the pick\r\n * @param disposeWhenDone defines a boolean indicating we do not want to keep resources alive (false by default)\r\n * @returns A promise with the picking results\r\n */\r\n public pickAsync(x: number, y: number, disposeWhenDone = false): Promise<Nullable<IGPUPickingInfo>> {\r\n if (!this._pickableMeshes || this._pickableMeshes.length === 0) {\r\n return Promise.resolve(null);\r\n }\r\n\r\n const scene = this._cachedScene!;\r\n const engine = scene.getEngine();\r\n const rttSizeW = engine.getRenderWidth();\r\n const rttSizeH = engine.getRenderHeight();\r\n\r\n if (!this._readbuffer) {\r\n this._readbuffer = new Uint8Array(engine.isWebGPU ? 256 : 4); // Because of block alignment in WebGPU\r\n }\r\n\r\n // Do we need to rebuild the RTT?\r\n const size = this._pickingTexure!.getSize();\r\n\r\n if (size.width !== rttSizeW || size.height !== rttSizeH) {\r\n this._createRenderTarget(scene, rttSizeW, rttSizeH);\r\n\r\n this._pickingTexure!.renderList = [];\r\n for (let index = 0; index < this._pickableMeshes.length; index++) {\r\n const mesh = this._pickableMeshes[index];\r\n this._pickingTexure!.setMaterialForRendering(mesh, this._renderMaterial!);\r\n this._pickingTexure!.renderList.push(mesh);\r\n }\r\n }\r\n\r\n this._meshRenderingCount = 0;\r\n // Ensure ints\r\n x = x >> 0;\r\n y = y >> 0;\r\n\r\n if (x < 0 || y < 0 || x >= rttSizeW || y >= rttSizeH) {\r\n return Promise.resolve(null);\r\n }\r\n\r\n // Invert Y\r\n y = rttSizeH - y;\r\n\r\n this._pickingTexure!.clearColor = new Color4(0, 0, 0, 0);\r\n\r\n scene.customRenderTargets.push(this._pickingTexure!);\r\n this._pickingTexure!.onBeforeRender = () => {\r\n // Enable scissor\r\n if ((engine as WebGPUEngine | Engine).enableScissor) {\r\n (engine as WebGPUEngine | Engine).enableScissor(x, y, 1, 1);\r\n }\r\n };\r\n\r\n return new Promise((resolve, reject) => {\r\n this._pickingTexure!.onAfterRender = async () => {\r\n // Disable scissor\r\n if ((engine as WebGPUEngine | Engine).disableScissor) {\r\n (engine as WebGPUEngine | Engine).disableScissor();\r\n }\r\n\r\n if (!this._pickingTexure) {\r\n reject();\r\n }\r\n\r\n let pickedMesh: Nullable<AbstractMesh> = null;\r\n const wasSuccessfull = this._meshRenderingCount > 0;\r\n\r\n if (wasSuccessfull) {\r\n // Remove from the active RTTs\r\n const index = scene.customRenderTargets.indexOf(this._pickingTexure!);\r\n if (index > -1) {\r\n scene.customRenderTargets.splice(index, 1);\r\n }\r\n\r\n // Do the actual picking\r\n if (await this._readTexturePixelsAsync(x, y)) {\r\n const r = this._readbuffer[0];\r\n const g = this._readbuffer[1];\r\n const b = this._readbuffer[2];\r\n const colorId = (r << 16) + (g << 8) + b;\r\n pickedMesh = this._pickableMeshes[this._idMap[colorId]];\r\n }\r\n }\r\n\r\n // Clean-up\r\n if (!wasSuccessfull) {\r\n this._meshRenderingCount = 0;\r\n return; // We need to wait for the shaders to be ready\r\n } else {\r\n if (disposeWhenDone) {\r\n this.dispose();\r\n }\r\n if (pickedMesh) {\r\n resolve({ mesh: pickedMesh });\r\n } else {\r\n resolve(null);\r\n }\r\n }\r\n };\r\n });\r\n }\r\n\r\n private async _readTexturePixelsAsync(x: number, y: number) {\r\n if (!this._cachedScene || !this._pickingTexure?._texture) {\r\n return false;\r\n }\r\n const engine = this._cachedScene.getEngine();\r\n await engine._readTexturePixels(this._pickingTexure._texture, 1, 1, -1, 0, this._readbuffer, true, true, x, y);\r\n\r\n return true;\r\n }\r\n\r\n /** Release the resources */\r\n public dispose() {\r\n this.setPickingList(null);\r\n this._cachedScene = null;\r\n\r\n // Cleaning up\r\n this._pickingTexure?.dispose();\r\n this._pickingTexure = null;\r\n this._renderMaterial?.dispose();\r\n this._renderMaterial = null;\r\n }\r\n}\r\n"]}
|