Ver Fonte

KTX2Loader: Support loading uncompressed DataTexture and Data3DTexture (#24129)

Don McCurdy há 3 anos atrás
pai
commit
cd583bc9bb
1 ficheiros alterados com 156 adições e 26 exclusões
  1. 156 26
      examples/jsm/loaders/KTX2Loader.js

+ 156 - 26
examples/jsm/loaders/KTX2Loader.js

@@ -3,8 +3,8 @@
  *
  * KTX 2.0 is a container format for various GPU texture formats. The loader
  * supports Basis Universal GPU textures, which can be quickly transcoded to
- * a wide variety of GPU texture compression formats. While KTX 2.0 also allows
- * other hardware-specific formats, this loader does not yet parse them.
+ * a wide variety of GPU texture compression formats, as well as some
+ * uncompressed DataTexture and Data3DTexture formats.
  *
  * References:
  * - KTX: http://github.khronos.org/KTX-Specification/
@@ -13,25 +13,47 @@
 
 import {
 	CompressedTexture,
+	Data3DTexture,
+	DataTexture,
 	FileLoader,
+	FloatType,
+	HalfFloatType,
 	LinearEncoding,
 	LinearFilter,
 	LinearMipmapLinearFilter,
 	Loader,
-	RGBAFormat,
+	RedFormat,
+	RGB_ETC1_Format,
+	RGB_ETC2_Format,
+	RGB_PVRTC_4BPPV1_Format,
+	RGB_S3TC_DXT1_Format,
 	RGBA_ASTC_4x4_Format,
 	RGBA_BPTC_Format,
 	RGBA_ETC2_EAC_Format,
 	RGBA_PVRTC_4BPPV1_Format,
 	RGBA_S3TC_DXT5_Format,
-	RGB_ETC1_Format,
-	RGB_ETC2_Format,
-	RGB_PVRTC_4BPPV1_Format,
-	RGB_S3TC_DXT1_Format,
+	RGBAFormat,
+	RGFormat,
 	sRGBEncoding,
 	UnsignedByteType
 } from 'three';
 import { WorkerPool } from '../utils/WorkerPool.js';
+import {
+	read,
+	VK_FORMAT_UNDEFINED,
+	VK_FORMAT_R16_SFLOAT,
+	VK_FORMAT_R16G16_SFLOAT,
+	VK_FORMAT_R16G16B16A16_SFLOAT,
+	VK_FORMAT_R32_SFLOAT,
+	VK_FORMAT_R32G32_SFLOAT,
+	VK_FORMAT_R32G32B32A32_SFLOAT,
+	VK_FORMAT_R8_SRGB,
+	VK_FORMAT_R8_UNORM,
+	VK_FORMAT_R8G8_SRGB,
+	VK_FORMAT_R8G8_UNORM,
+	VK_FORMAT_R8G8B8A8_SRGB,
+	VK_FORMAT_R8G8B8A8_UNORM,
+} from '../libs/ktx-parse.module.js';
 
 const KTX2TransferSRGB = 2;
 const KTX2_ALPHA_PREMULTIPLIED = 1;
@@ -189,8 +211,6 @@ class KTX2Loader extends Loader {
 		loader.setResponseType( 'arraybuffer' );
 		loader.setWithCredentials( this.withCredentials );
 
-		const texture = new CompressedTexture();
-
 		loader.load( url, ( buffer ) => {
 
 			// Check for an existing task using this buffer. A transferred buffer cannot be transferred
@@ -203,21 +223,12 @@ class KTX2Loader extends Loader {
 
 			}
 
-			this._createTexture( [ buffer ] )
-				.then( function ( _texture ) {
-
-					texture.copy( _texture );
-					texture.needsUpdate = true;
-
-					if ( onLoad ) onLoad( texture );
-
-				} )
+			this._createTexture( buffer )
+				.then( ( texture ) => onLoad ? onLoad( texture ) : null )
 				.catch( onError );
 
 		}, onProgress, onError );
 
-		return texture;
-
 	}
 
 	_createTextureFrom( transcodeResult ) {
@@ -239,21 +250,31 @@ class KTX2Loader extends Loader {
 	}
 
 	/**
-	 * @param {ArrayBuffer[]} buffers
+	 * @param {ArrayBuffer} buffer
 	 * @param {object?} config
-	 * @return {Promise<CompressedTexture>}
+	 * @return {Promise<CompressedTexture|DataTexture|Data3DTexture>}
 	 */
-	_createTexture( buffers, config = {} ) {
+	_createTexture( buffer, config = {} ) {
+
+		const container = read( new Uint8Array( buffer ) );
+
+		if ( container.vkFormat !== VK_FORMAT_UNDEFINED ) {
+
+			return createDataTexture( container );
+
+		}
+
+		//
 
 		const taskConfig = config;
 		const texturePending = this.init().then( () => {
 
-			return this.workerPool.postMessage( { type: 'transcode', buffers, taskConfig: taskConfig }, buffers );
+			return this.workerPool.postMessage( { type: 'transcode', buffer, taskConfig: taskConfig }, [ buffer ] );
 
 		} ).then( ( e ) => this._createTextureFrom( e.data ) );
 
 		// Cache the task result.
-		_taskCache.set( buffers[ 0 ], { promise: texturePending } );
+		_taskCache.set( buffer, { promise: texturePending } );
 
 		return texturePending;
 
@@ -342,7 +363,7 @@ KTX2Loader.BasisWorker = function () {
 
 					try {
 
-						const { width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags } = transcode( message.buffers[ 0 ] );
+						const { width, height, hasAlpha, mipmaps, format, dfdTransferFn, dfdFlags } = transcode( message.buffer );
 
 						const buffers = [];
 
@@ -588,4 +609,113 @@ KTX2Loader.BasisWorker = function () {
 
 };
 
+//
+// DataTexture and Data3DTexture parsing.
+
+const FORMAT_MAP = {
+
+	[VK_FORMAT_R32G32B32A32_SFLOAT]: RGBAFormat,
+	[VK_FORMAT_R16G16B16A16_SFLOAT]: RGBAFormat,
+	[VK_FORMAT_R8G8B8A8_UNORM]: RGBAFormat,
+	[VK_FORMAT_R8G8B8A8_SRGB]: RGBAFormat,
+
+	[VK_FORMAT_R32G32_SFLOAT]: RGFormat,
+	[VK_FORMAT_R16G16_SFLOAT]: RGFormat,
+	[VK_FORMAT_R8G8_UNORM]: RGFormat,
+	[VK_FORMAT_R8G8_SRGB]: RGFormat,
+
+	[VK_FORMAT_R32_SFLOAT]: RedFormat,
+	[VK_FORMAT_R16_SFLOAT]: RedFormat,
+	[VK_FORMAT_R8_SRGB]: RedFormat,
+	[VK_FORMAT_R8_UNORM]: RedFormat,
+
+};
+
+const TYPE_MAP = {
+
+	[VK_FORMAT_R32G32B32A32_SFLOAT]: FloatType,
+	[VK_FORMAT_R16G16B16A16_SFLOAT]: HalfFloatType,
+	[VK_FORMAT_R8G8B8A8_UNORM]: UnsignedByteType,
+	[VK_FORMAT_R8G8B8A8_SRGB]: UnsignedByteType,
+
+	[VK_FORMAT_R32G32_SFLOAT]: FloatType,
+	[VK_FORMAT_R16G16_SFLOAT]: HalfFloatType,
+	[VK_FORMAT_R8G8_UNORM]: UnsignedByteType,
+	[VK_FORMAT_R8G8_SRGB]: UnsignedByteType,
+
+	[VK_FORMAT_R32_SFLOAT]: FloatType,
+	[VK_FORMAT_R16_SFLOAT]: HalfFloatType,
+	[VK_FORMAT_R8_SRGB]: UnsignedByteType,
+	[VK_FORMAT_R8_UNORM]: UnsignedByteType,
+
+};
+
+const ENCODING_MAP = {
+
+	[VK_FORMAT_R8G8B8A8_SRGB]: sRGBEncoding,
+	[VK_FORMAT_R8G8_SRGB]: sRGBEncoding,
+	[VK_FORMAT_R8_SRGB]: sRGBEncoding,
+
+};
+
+function createDataTexture( container ) {
+
+	const { vkFormat, pixelWidth, pixelHeight, pixelDepth } = container;
+
+	if ( FORMAT_MAP[ vkFormat ] === undefined ) {
+
+		throw new Error( 'THREE.KTX2Loader: Unsupported vkFormat.' );
+
+	}
+
+	//
+
+	let view;
+
+	const levelData = container.levels[ 0 ].levelData;
+
+	if ( TYPE_MAP[ vkFormat ] === FloatType ) {
+
+		view = new Float32Array(
+
+			levelData.buffer,
+			levelData.byteOffset,
+			levelData.byteLength / Float32Array.BYTES_PER_ELEMENT
+
+		);
+
+	} else if ( TYPE_MAP[ vkFormat ] === HalfFloatType ) {
+
+		view = new Uint16Array(
+
+			levelData.buffer,
+			levelData.byteOffset,
+			levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT
+
+		);
+
+	} else {
+
+		view = levelData;
+
+	}
+
+	//
+
+	const texture = pixelDepth === 0
+		? new DataTexture( view, pixelWidth, pixelHeight )
+		: new Data3DTexture( view, pixelWidth, pixelHeight, pixelDepth );
+
+	texture.type = TYPE_MAP[ vkFormat ];
+	texture.format = FORMAT_MAP[ vkFormat ];
+	texture.encoding = ENCODING_MAP[ vkFormat ] || LinearEncoding;
+
+	texture.needsUpdate = true;
+
+	//
+
+	return Promise.resolve( texture );
+
+}
+
 export { KTX2Loader };