Skip to content

Commit

Permalink
KTX2Loader: Add support for u8, f16, and f32 array and cube textures …
Browse files Browse the repository at this point in the history
…(WIP)

Add DataCubeTexure

Add TextureHelper.

Improve TextureHelper, show slices.

Clean up

Fix issues in data textures

Tmp remove textureHelper
  • Loading branch information
donmccurdy committed Nov 14, 2023
1 parent 99fd53f commit 4031585
Show file tree
Hide file tree
Showing 25 changed files with 129 additions and 47 deletions.
51 changes: 44 additions & 7 deletions examples/jsm/loaders/KTX2Loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
CompressedArrayTexture,
CompressedCubeTexture,
Data3DTexture,
DataArrayTexture,
DataCubeTexture,
DataTexture,
DisplayP3ColorSpace,
FileLoader,
Expand Down Expand Up @@ -796,7 +798,6 @@ async function createRawTexture( container ) {

const mipmaps = [];


for ( let levelIndex = 0; levelIndex < container.levels.length; levelIndex ++ ) {

const levelWidth = Math.max( 1, container.pixelWidth >> levelIndex );
Expand Down Expand Up @@ -864,19 +865,55 @@ async function createRawTexture( container ) {

if ( UNCOMPRESSED_FORMATS.has( FORMAT_MAP[ vkFormat ] ) ) {

texture = container.pixelDepth === 0
? new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight )
: new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth );
if ( container.faceCount === 6 ) {

texture = new DataCubeTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight );

} else if ( container.layerCount > 1 ) {

texture = new DataArrayTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.layerCount );

} else if ( container.pixelDepth === 0 ) {

texture = new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight );

} else {

texture = new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth );

}

} else {

if ( container.pixelDepth > 0 ) throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );
if ( container.faceCount === 6 ) {

texture = new CompressedCubeTexture( mipmaps );

texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );
} else if ( container.layerCount > 1 ) {

texture = new CompressedArrayTexture( mipmaps, container.pixelWidth, container.pixelHeight, container.layerCount );

} else if ( container.pixelDepth === 0 ) {

texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );

} else {

throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );

}

}

texture.mipmaps = mipmaps;
if ( texture.isDataCubeTexture ) {

texture.mipmaps = mipmaps.map( ( mip ) => new DataCubeTexture( mip.data, mip.width, mip.height ) );

} else {

texture.mipmaps = mipmaps;

}

texture.type = TYPE_MAP[ vkFormat ];
texture.format = FORMAT_MAP[ vkFormat ];
Expand Down
Binary file modified examples/textures/compressed/2d_rgba16_linear.ktx2
Binary file not shown.
Binary file modified examples/textures/compressed/2d_rgba32_linear.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/3d_etc1s.ktx2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/compressed/3d_rgba32_lut.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/3d_rgba8.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/3d_rgba8_linear.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/3d_uastc.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/array_etc1s.ktx2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/compressed/array_rgba8.ktx2
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/compressed/array_uastc.ktx2
Binary file not shown.
Binary file added examples/textures/compressed/cubemap_etc1s.ktx2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/compressed/cubemap_rgba8.ktx2
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/compressed/cubemap_uastc.ktx2
Binary file not shown.
89 changes: 49 additions & 40 deletions examples/webgl_loader_texture_ktx2.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl - KTX2 texture loader<br />
<a href="http://github.khronos.org/KTX-Specification/" target="_blank" rel="noopener">KTX2</a> with
<a href="https://github.com/binomialLLC/basis_universal" target="_blank">Basis Universal GPU Texture Codec</a>
<a href="http://github.khronos.org/KTX-Specification/" target="_blank" rel="noopener">KTX2</a>
with various layouts and compression
</div>

<script type="importmap">
Expand All @@ -29,19 +29,46 @@

import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { TextureHelper } from 'three/addons/helpers/TextureHelper.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer, controls, loader, material;
let camera, scene, renderer, controls, loader, helper;

const SAMPLES = {
'BasisU ETC1S': '2d_etc1s.ktx2',
'BasisU UASTC': '2d_uastc.ktx2',
'RGBA8 sRGB': '2d_rgba8.ktx2',
'RGBA8 Linear': '2d_rgba8_linear.ktx2',
// 'RGBA8 Display P3': '2d_rgba8_displayp3.ktx2',
'RGBA16 Linear': '2d_rgba16_linear.ktx2',
'RGBA32 Linear': '2d_rgba32_linear.ktx2',
'ASTC 6x6 (mobile)': '2d_astc_6x6.ktx2',
// 2D
'2D / BasisU ETC1S': '2d_etc1s.ktx2',
'2D / BasisU UASTC': '2d_uastc.ktx2',
'2D / RGBA8 sRGB': '2d_rgba8.ktx2',
'2D / RGBA8 Linear': '2d_rgba8_linear.ktx2',
// '2D / RGBA8 Display P3': '2d_rgba8_displayp3.ktx2',
'2D / RGBA16 Linear': '2d_rgba16_linear.ktx2',
'2D / RGBA32 Linear': '2d_rgba32_linear.ktx2',
'2D / ASTC 6x6 (mobile)': '2d_astc_6x6.ktx2',

// 3D
'3D / BasisU ETC1S': '3d_etc1s.ktx2',
'3D / BasisU UASTC': '3d_uastc.ktx2',
'3D / RGBA8 sRGB': '3d_rgba8.ktx2',
'3D / RGBA8 Linear': '3d_rgba8_linear.ktx2',
'3D / RGBA16 Linear': '3d_rgba16_linear.ktx2',
'3D / RGBA32 Linear': '3d_rgba32_linear.ktx2',
'3D / RGBA32 LUT': '3d_rgba32_lut.ktx2',

// Cube
'Cube / BasisU ETC1S': 'cubemap_etc1s.ktx2',
'Cube / BasisU UASTC': 'cubemap_uastc.ktx2',
'Cube / RGBA8 sRGB': 'cubemap_rgba8.ktx2',
'Cube / RGBA8 Linear': 'cubemap_rgba8_linear.ktx2',
'Cube / RGBA16 Linear': 'cubemap_rgba16_linear.ktx2',
'Cube / RGBA32 Linear': 'cubemap_rgba32_linear.ktx2',

// Array
'Array / BasisU ETC1S': 'array_etc1s.ktx2',
'Array / BasisU UASTC': 'array_uastc.ktx2',
'Array / RGBA8 sRGB': 'array_rgba8.ktx2',
'Array / RGBA8 Linear': 'array_rgba8_linear.ktx2',
'Array / RGBA16 Linear': 'array_rgba16_linear.ktx2',
'Array / RGBA32 Linear': 'array_rgba32_linear.ktx2',
};

const FORMAT_LABELS = {
Expand Down Expand Up @@ -87,7 +114,6 @@
window.addEventListener( 'resize', onWindowResize );

scene = new THREE.Scene();
scene.background = new THREE.Color( 0x202020 );

camera = new THREE.PerspectiveCamera( 60, width / height, 0.1, 100 );
camera.position.set( 0, 0, 2.5 );
Expand All @@ -96,16 +122,6 @@

controls = new OrbitControls( camera, renderer.domElement );

// PlaneGeometry UVs assume flipY=true, which compressed textures don't support.
const geometry = flipY( new THREE.PlaneGeometry() );
material = new THREE.MeshBasicMaterial( {
color: 0xFFFFFF,
side: THREE.DoubleSide,
transparent: true,
} );
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

loader = new KTX2Loader()
.setTranscoderPath( 'jsm/libs/basis/' )
.detectSupport( renderer );
Expand Down Expand Up @@ -146,10 +162,19 @@

const texture = await loader.loadAsync( `./textures/compressed/${path}` );
texture.minFilter = THREE.NearestMipmapNearestFilter;
texture.needsUpdate = true;

if ( helper ) {

scene.remove( helper );
helper.dispose();

}

material.map = texture;
material.needsUpdate = true;
helper = new TextureHelper( texture );
scene.add( helper );

console.info( `class: ${ texture.constructor.name }` );
console.info( `format: ${ FORMAT_LABELS[ texture.format ] }` );
console.info( `type: ${ TYPE_LABELS[ texture.type ] }` );
console.info( `colorSpace: ${ texture.colorSpace }` );
Expand All @@ -162,22 +187,6 @@

// NOTE: Call `loader.dispose()` when finished loading textures.


}

/** Correct UVs to be compatible with `flipY=false` textures. */
function flipY( geometry ) {

const uv = geometry.attributes.uv;

for ( let i = 0; i < uv.count; i ++ ) {

uv.setY( i, 1 - uv.getY( i ) );

}

return geometry;

}

</script>
Expand Down
1 change: 1 addition & 0 deletions src/Three.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export { FramebufferTexture } from './textures/FramebufferTexture.js';
export { Source } from './textures/Source.js';
export { DataTexture } from './textures/DataTexture.js';
export { DataArrayTexture } from './textures/DataArrayTexture.js';
export { DataCubeTexture } from './textures/DataCubeTexture.js';
export { Data3DTexture } from './textures/Data3DTexture.js';
export { CompressedTexture } from './textures/CompressedTexture.js';
export { CompressedArrayTexture } from './textures/CompressedArrayTexture.js';
Expand Down
35 changes: 35 additions & 0 deletions src/textures/DataCubeTexture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Texture } from './Texture.js';
import { CubeReflectionMapping } from '../constants.js';

class DataCubeTexture extends Texture {

constructor( data, width, height ) {

super( data, CubeReflectionMapping );

this.isDataCubeTexture = true;
this.isCubeTexture = true;

this.image = { data: data, width: width, height: height };

this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;

}

get images() {

return this.image;

}

set images( value ) {

this.image = value;

}

}

export { DataCubeTexture };

0 comments on commit 4031585

Please sign in to comment.