Преглед изворни кода

WebGPURenderer: ReadRenderTargetPixelsAsync (RFC) (#26326)

* add support for meshPhongNodeMaterial

* draft readPixel api

* Update examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js

Co-authored-by: Levi Pesin <[email protected]>

* Update examples/jsm/renderers/common/Renderer.js

Co-authored-by: Levi Pesin <[email protected]>

---------

Co-authored-by: aardgoose <[email protected]>
Co-authored-by: Levi Pesin <[email protected]>
aardgoose пре 2 година
родитељ
комит
b287bde4f8

+ 2 - 0
examples/jsm/renderers/common/Backend.js

@@ -68,6 +68,8 @@ class Backend {
 
 	createTexture( texture ) { }
 
+	copyTextureToBuffer( texture, x, y, width, height ) {}
+
 	// attributes
 
 	createAttribute( attribute ) { }

+ 6 - 0
examples/jsm/renderers/common/Renderer.js

@@ -637,6 +637,12 @@ class Renderer {
 
 	}
 
+	readRenderTargetPixelsAsync( renderTarget, x, y, width, height ) {
+
+		return this.backend.copyTextureToBuffer( renderTarget.texture, x, y, width, height );
+
+	}
+
 	_projectObject( object, camera, groupOrder, renderList ) {
 
 		if ( object.visible === false ) return;

+ 6 - 0
examples/jsm/renderers/webgpu/WebGPUBackend.js

@@ -572,6 +572,12 @@ class WebGPUBackend extends Backend {
 
 	}
 
+	copyTextureToBuffer( texture, x, y, width, height ) {
+
+		return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height );
+
+	}
+
 	// node builder
 
 	createNodeBuilder( object, renderer ) {

+ 82 - 0
examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js

@@ -245,6 +245,52 @@ class WebGPUTextureUtils {
 
 	}
 
+	async copyTextureToBuffer( texture, x, y, width, height ) {
+
+		const device = this.backend.device;
+
+		const textureData = this.backend.get( texture );
+		const textureGPU = textureData.texture;
+		const format = textureData.textureDescriptorGPU.format;
+		const bytesPerTexel = this._getBytesPerTexel( format );
+
+		const readBuffer = device.createBuffer(
+			{
+				size: width * height * bytesPerTexel,
+				usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
+			}
+		);
+
+		const encoder = device.createCommandEncoder();
+
+		encoder.copyTextureToBuffer(
+			{
+				texture: textureGPU,
+				origin: { x, y },
+			},
+			{
+				buffer: readBuffer,
+				bytesPerRow: width * bytesPerTexel
+			},
+			{
+				width: width,
+				height: height
+			}
+
+		);
+
+		const typedArrayType = this._getTypedArrayType( format );
+
+		device.queue.submit( [ encoder.finish() ] );
+
+		await readBuffer.mapAsync( GPUMapMode.READ );
+
+		const buffer = readBuffer.getMappedRange();
+
+		return new typedArrayType( buffer );
+
+	}
+
 	_isEnvironmentTexture( texture ) {
 
 		const mapping = texture.mapping;
@@ -579,6 +625,42 @@ class WebGPUTextureUtils {
 
 	}
 
+	_getTypedArrayType( format ) {
+
+		if ( format === GPUTextureFormat.R8Uint ) return Uint8Array;
+		if ( format === GPUTextureFormat.R8Sint ) return Int8Array;
+		if ( format === GPUTextureFormat.R8Unorm ) return Uint8Array;
+		if ( format === GPUTextureFormat.R8Snorm ) return Int8Array;
+		if ( format === GPUTextureFormat.RG8Uint ) return Uint8Array;
+		if ( format === GPUTextureFormat.RG8Sint ) return Int8Array;
+		if ( format === GPUTextureFormat.RG8Unorm ) return Uint8Array;
+		if ( format === GPUTextureFormat.RG8Snorm ) return Int8Array;
+		if ( format === GPUTextureFormat.RGBA8Uint ) return Uint8Array;
+		if ( format === GPUTextureFormat.RGBA8Sint ) return Int8Array;
+		if ( format === GPUTextureFormat.RGBA8Unorm ) return Uint8Array;
+		if ( format === GPUTextureFormat.RGBA8Snorm ) return Int8Array;
+
+
+		if ( format === GPUTextureFormat.R16Uint ) return Uint16Array;
+		if ( format === GPUTextureFormat.R16Sint ) return Int16Array;
+		if ( format === GPUTextureFormat.RG16Uint ) return Uint16Array;
+		if ( format === GPUTextureFormat.RG16Sint ) return Int16Array;
+		if ( format === GPUTextureFormat.RGBA16Uint ) return Uint16Array;
+		if ( format === GPUTextureFormat.RGBA16Sint ) return Int16Array;
+
+
+		if ( format === GPUTextureFormat.R32Uint ) return Uint32Array;
+		if ( format === GPUTextureFormat.R32Sint ) return Int32Array;
+		if ( format === GPUTextureFormat.R32Float ) return Float32Array;
+		if ( format === GPUTextureFormat.RG32Uint ) return Uint32Array;
+		if ( format === GPUTextureFormat.RG32Sint ) return Int32Array;
+		if ( format === GPUTextureFormat.RG32Float ) return Float32Array;
+		if ( format === GPUTextureFormat.RGBA32Uint ) return Uint32Array;
+		if ( format === GPUTextureFormat.RGBA32Sint ) return Int32Array;
+		if ( format === GPUTextureFormat.RGBA32Float ) return Float32Array;
+
+	}
+
 	_getDimension( texture ) {
 
 		let dimension;