|
@@ -54,7 +54,7 @@ import { WebGLUtils } from './webgl/WebGLUtils.js';
|
|
|
import { WebXRManager } from './webxr/WebXRManager.js';
|
|
|
import { WebGLMaterials } from './webgl/WebGLMaterials.js';
|
|
|
import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js';
|
|
|
-import { createCanvasElement } from '../utils.js';
|
|
|
+import { createCanvasElement, probeAsync } from '../utils.js';
|
|
|
import { ColorManagement } from '../math/ColorManagement.js';
|
|
|
|
|
|
class WebGLRenderer {
|
|
@@ -2357,6 +2357,85 @@ class WebGLRenderer {
|
|
|
|
|
|
};
|
|
|
|
|
|
+ this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
|
|
|
+
|
|
|
+ if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
|
|
|
+ if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
|
|
|
+
|
|
|
+ framebuffer = framebuffer[ activeCubeFaceIndex ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( framebuffer ) {
|
|
|
+
|
|
|
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
+
|
|
|
+ try {
|
|
|
+
|
|
|
+ const texture = renderTarget.texture;
|
|
|
+ const textureFormat = texture.format;
|
|
|
+ const textureType = texture.type;
|
|
|
+
|
|
|
+ if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( ! capabilities.textureTypeReadable( textureType ) ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
|
|
|
+ if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
|
|
|
+
|
|
|
+ const glBuffer = _gl.createBuffer();
|
|
|
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
|
|
|
+ _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
|
|
|
+ _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
|
|
|
+ _gl.flush();
|
|
|
+
|
|
|
+ // check if the commands have finished every 8 ms
|
|
|
+ const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
|
|
|
+ await probeAsync( _gl, sync, 4 );
|
|
|
+
|
|
|
+ try {
|
|
|
+
|
|
|
+ _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
|
|
|
+ _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
|
|
|
+
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ _gl.deleteBuffer( glBuffer );
|
|
|
+ _gl.deleteSync( sync );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return buffer;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } finally {
|
|
|
+
|
|
|
+ // restore framebuffer of current render target if necessary
|
|
|
+
|
|
|
+ const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
|
|
|
+ state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
|
|
|
|
|
|
const levelScale = Math.pow( 2, - level );
|