浏览代码

Add KTX2Exporter (#24102)

* KTX2Exporter: Initial commit

* KTX2Exporter: Keep relative import
Don McCurdy 3 年之前
父节点
当前提交
746f66b295
共有 2 个文件被更改,包括 281 次插入0 次删除
  1. 281 0
      examples/jsm/exporters/KTX2Exporter.js
  2. 0 0
      examples/jsm/libs/ktx-parse.module.js

+ 281 - 0
examples/jsm/exporters/KTX2Exporter.js

@@ -0,0 +1,281 @@
+import {
+	FloatType,
+	HalfFloatType,
+	UnsignedByteType,
+	RGBAFormat,
+	RGFormat,
+	RGIntegerFormat,
+	RedFormat,
+	RedIntegerFormat,
+	LinearEncoding,
+	sRGBEncoding,
+	DataTexture,
+	REVISION,
+} from 'three';
+
+import {
+	write,
+	KTX2Container,
+	KHR_DF_CHANNEL_RGBSDA_ALPHA,
+	KHR_DF_CHANNEL_RGBSDA_BLUE,
+	KHR_DF_CHANNEL_RGBSDA_GREEN,
+	KHR_DF_CHANNEL_RGBSDA_RED,
+	KHR_DF_MODEL_RGBSDA,
+	KHR_DF_PRIMARIES_BT709,
+	KHR_DF_SAMPLE_DATATYPE_FLOAT,
+	KHR_DF_SAMPLE_DATATYPE_LINEAR,
+	KHR_DF_SAMPLE_DATATYPE_SIGNED,
+	KHR_DF_TRANSFER_LINEAR,
+	KHR_DF_TRANSFER_SRGB,
+	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 VK_FORMAT_MAP = {
+
+	[RGBAFormat]: {
+		[FloatType]: {
+			[LinearEncoding]: VK_FORMAT_R32G32B32A32_SFLOAT,
+		},
+		[HalfFloatType]: {
+			[LinearEncoding]: VK_FORMAT_R16G16B16A16_SFLOAT,
+		},
+		[UnsignedByteType]: {
+			[LinearEncoding]: VK_FORMAT_R8G8B8A8_UNORM,
+			[sRGBEncoding]: VK_FORMAT_R8G8B8A8_SRGB,
+		},
+	},
+
+	[RGFormat]: {
+		[FloatType]: {
+			[LinearEncoding]: VK_FORMAT_R32G32_SFLOAT,
+		},
+		[HalfFloatType]: {
+			[LinearEncoding]: VK_FORMAT_R16G16_SFLOAT,
+		},
+		[UnsignedByteType]: {
+			[LinearEncoding]: VK_FORMAT_R8G8_UNORM,
+			[sRGBEncoding]: VK_FORMAT_R8G8_SRGB,
+		},
+	},
+
+	[RedFormat]: {
+		[FloatType]: {
+			[LinearEncoding]: VK_FORMAT_R32_SFLOAT,
+		},
+		[HalfFloatType]: {
+			[LinearEncoding]: VK_FORMAT_R16_SFLOAT,
+		},
+		[UnsignedByteType]: {
+			[LinearEncoding]: VK_FORMAT_R8_SRGB,
+			[sRGBEncoding]: VK_FORMAT_R8_UNORM,
+		},
+	},
+
+};
+
+const KHR_DF_CHANNEL_MAP = {
+
+	0: KHR_DF_CHANNEL_RGBSDA_RED,
+	1: KHR_DF_CHANNEL_RGBSDA_GREEN,
+	2: KHR_DF_CHANNEL_RGBSDA_BLUE,
+	3: KHR_DF_CHANNEL_RGBSDA_ALPHA,
+
+};
+
+const ERROR_INPUT = 'THREE.KTX2Exporter: Supported inputs are DataTexture, Data3DTexture, or WebGLRenderer and WebGLRenderTarget.';
+const ERROR_FORMAT = 'THREE.KTX2Exporter: Supported formats are RGBAFormat, RGFormat, or RedFormat.';
+const ERROR_TYPE = 'THREE.KTX2Exporter: Supported types are FloatType, HalfFloatType, or UnsignedByteType."';
+const ERROR_ENCODING = 'THREE.KTX2Exporter: Supported encodings are sRGB (UnsignedByteType only) or Linear.';
+
+export class KTX2Exporter {
+
+	parse( arg1, arg2 ) {
+
+		let texture;
+
+		if ( arg1.isDataTexture || arg1.isData3DTexture ) {
+
+			texture = arg1;
+
+		} else if ( arg1.isWebGLRenderer && arg2.isWebGLRenderTarget ) {
+
+			texture = toDataTexture( arg1, arg2 );
+
+		} else {
+
+			throw new Error( ERROR_INPUT );
+
+		}
+
+		if ( VK_FORMAT_MAP[ texture.format ] === undefined ) {
+
+			throw new Error( ERROR_FORMAT );
+
+		}
+
+		if ( VK_FORMAT_MAP[ texture.format ][ texture.type ] === undefined ) {
+
+			throw new Error( ERROR_TYPE );
+
+		}
+
+		if ( VK_FORMAT_MAP[ texture.format ][ texture.type ][ texture.encoding ] === undefined ) {
+
+			throw new Error( ERROR_ENCODING );
+
+		}
+
+		//
+
+		const array = texture.image.data;
+		const channelCount = getChannelCount( texture );
+		const container = new KTX2Container();
+
+		container.vkFormat = VK_FORMAT_MAP[ texture.format ][ texture.type ][ texture.encoding ];
+		container.typeSize = array.BYTES_PER_ELEMENT;
+		container.pixelWidth = texture.image.width;
+		container.pixelHeight = texture.image.height;
+
+		if ( texture.isData3DTexture ) {
+
+			container.pixelDepth = texture.image.depth;
+
+		}
+
+		//
+
+		const basicDesc = container.dataFormatDescriptor[ 0 ];
+
+		// TODO: After `texture.encoding` is replaced, distinguish between
+		// non-color data (unspecified model and primaries) and sRGB or Linear-sRGB colors.
+		basicDesc.colorModel = KHR_DF_MODEL_RGBSDA;
+		basicDesc.colorPrimaries = KHR_DF_PRIMARIES_BT709;
+		basicDesc.transferFunction = texture.encoding === sRGBEncoding
+			? KHR_DF_TRANSFER_SRGB
+			: KHR_DF_TRANSFER_LINEAR;
+
+		basicDesc.texelBlockDimension = [ 0, 0, 0, 0 ];
+
+		basicDesc.bytesPlane = [
+
+			container.typeSize * channelCount, 0, 0, 0, 0, 0, 0, 0,
+
+		];
+
+		for ( let i = 0; i < channelCount; ++ i ) {
+
+			let channelType = KHR_DF_CHANNEL_MAP[ i ];
+
+			if ( texture.encoding === LinearEncoding ) {
+
+				channelType |= KHR_DF_SAMPLE_DATATYPE_LINEAR;
+
+			}
+
+			if ( texture.type === FloatType || texture.type === HalfFloatType ) {
+
+				channelType |= KHR_DF_SAMPLE_DATATYPE_FLOAT;
+				channelType |= KHR_DF_SAMPLE_DATATYPE_SIGNED;
+
+			}
+
+			basicDesc.samples.push( {
+
+				channelType: channelType,
+				bitOffset: i * array.BYTES_PER_ELEMENT,
+				bitLength: array.BYTES_PER_ELEMENT * 8 - 1,
+				samplePosition: [0, 0, 0, 0],
+				sampleLower: texture.type === UnsignedByteType ? 0 : -1,
+				sampleUpper: texture.type === UnsignedByteType ? 255 : 1,
+
+			} );
+
+		}
+
+		//
+
+		container.levels = [ {
+
+			levelData: new Uint8Array( array.buffer, array.byteOffset, array.byteLength ),
+			uncompressedByteLength: array.byteLength,
+
+		} ];
+
+		//
+
+		container.keyValue['KTXwriter'] = `three.js ${ REVISION }`;
+
+		//
+
+		return write( container, { keepWriter: true } );
+
+	}
+
+}
+
+function toDataTexture( renderer, rtt ) {
+
+	const channelCount = getChannelCount( rtt.texture );
+
+	let view;
+
+	if ( rtt.texture.type === FloatType ) {
+
+		view = new Float32Array( rtt.width * rtt.height * channelCount );
+
+	} else if ( rtt.texture.type === HalfFloatType ) {
+
+		view = new Uint16Array( rtt.width * rtt.height * channelCount );
+
+	} else if ( rtt.texture.type === UnsignedByteType ) {
+
+		view = new Uint8Array( rtt.width * rtt.height * channelCount );
+
+	} else {
+
+		throw new Error( ERROR_TYPE );
+
+	}
+
+	renderer.readRenderTargetPixels( rtt, 0, 0, rtt.width, rtt.height, view );
+
+	return new DataTexture( view, rtt.width, rt.height, rtt.texture.format, rtt.texture.type );
+
+}
+
+function getChannelCount( texture ) {
+
+	switch ( texture.format ) {
+
+		case RGBAFormat:
+
+			return 4;
+
+		case RGFormat:
+		case RGIntegerFormat:
+
+			return 2;
+
+		case RedFormat:
+		case RedIntegerFormat:
+
+			return 1;
+
+		default:
+
+			throw new Error( ERROR_FORMAT );
+
+	}
+
+}

文件差异内容过多而无法显示
+ 0 - 0
examples/jsm/libs/ktx-parse.module.js


部分文件因为文件数量过多而无法显示