Skip to content

Commit 4031585

Browse files
committed
KTX2Loader: Add support for u8, f16, and f32 array and cube textures (WIP)
Add DataCubeTexure Add TextureHelper. Improve TextureHelper, show slices. Clean up Fix issues in data textures Tmp remove textureHelper
1 parent 99fd53f commit 4031585

25 files changed

+129
-47
lines changed

examples/jsm/loaders/KTX2Loader.js

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
CompressedArrayTexture,
1717
CompressedCubeTexture,
1818
Data3DTexture,
19+
DataArrayTexture,
20+
DataCubeTexture,
1921
DataTexture,
2022
DisplayP3ColorSpace,
2123
FileLoader,
@@ -796,7 +798,6 @@ async function createRawTexture( container ) {
796798

797799
const mipmaps = [];
798800

799-
800801
for ( let levelIndex = 0; levelIndex < container.levels.length; levelIndex ++ ) {
801802

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

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

867-
texture = container.pixelDepth === 0
868-
? new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight )
869-
: new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth );
868+
if ( container.faceCount === 6 ) {
869+
870+
texture = new DataCubeTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight );
871+
872+
} else if ( container.layerCount > 1 ) {
873+
874+
texture = new DataArrayTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.layerCount );
875+
876+
} else if ( container.pixelDepth === 0 ) {
877+
878+
texture = new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight );
879+
880+
} else {
881+
882+
texture = new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth );
883+
884+
}
870885

871886
} else {
872887

873-
if ( container.pixelDepth > 0 ) throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );
888+
if ( container.faceCount === 6 ) {
889+
890+
texture = new CompressedCubeTexture( mipmaps );
874891

875-
texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );
892+
} else if ( container.layerCount > 1 ) {
893+
894+
texture = new CompressedArrayTexture( mipmaps, container.pixelWidth, container.pixelHeight, container.layerCount );
895+
896+
} else if ( container.pixelDepth === 0 ) {
897+
898+
texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );
899+
900+
} else {
901+
902+
throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );
903+
904+
}
876905

877906
}
878907

879-
texture.mipmaps = mipmaps;
908+
if ( texture.isDataCubeTexture ) {
909+
910+
texture.mipmaps = mipmaps.map( ( mip ) => new DataCubeTexture( mip.data, mip.width, mip.height ) );
911+
912+
} else {
913+
914+
texture.mipmaps = mipmaps;
915+
916+
}
880917

881918
texture.type = TYPE_MAP[ vkFormat ];
882919
texture.format = FORMAT_MAP[ vkFormat ];
Binary file not shown.
Binary file not shown.
29.7 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
94.4 KB
Binary file not shown.
Binary file not shown.
72.7 KB
Binary file not shown.
29.7 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
94.4 KB
Binary file not shown.
Binary file not shown.
72.7 KB
Binary file not shown.
22.6 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
71.1 KB
Binary file not shown.
Binary file not shown.
54.4 KB
Binary file not shown.

examples/webgl_loader_texture_ktx2.html

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

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

1717
<script type="importmap">
@@ -29,19 +29,46 @@
2929

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

34-
let camera, scene, renderer, controls, loader, material;
35+
let camera, scene, renderer, controls, loader, helper;
3536

3637
const SAMPLES = {
37-
'BasisU ETC1S': '2d_etc1s.ktx2',
38-
'BasisU UASTC': '2d_uastc.ktx2',
39-
'RGBA8 sRGB': '2d_rgba8.ktx2',
40-
'RGBA8 Linear': '2d_rgba8_linear.ktx2',
41-
// 'RGBA8 Display P3': '2d_rgba8_displayp3.ktx2',
42-
'RGBA16 Linear': '2d_rgba16_linear.ktx2',
43-
'RGBA32 Linear': '2d_rgba32_linear.ktx2',
44-
'ASTC 6x6 (mobile)': '2d_astc_6x6.ktx2',
38+
// 2D
39+
'2D / BasisU ETC1S': '2d_etc1s.ktx2',
40+
'2D / BasisU UASTC': '2d_uastc.ktx2',
41+
'2D / RGBA8 sRGB': '2d_rgba8.ktx2',
42+
'2D / RGBA8 Linear': '2d_rgba8_linear.ktx2',
43+
// '2D / RGBA8 Display P3': '2d_rgba8_displayp3.ktx2',
44+
'2D / RGBA16 Linear': '2d_rgba16_linear.ktx2',
45+
'2D / RGBA32 Linear': '2d_rgba32_linear.ktx2',
46+
'2D / ASTC 6x6 (mobile)': '2d_astc_6x6.ktx2',
47+
48+
// 3D
49+
'3D / BasisU ETC1S': '3d_etc1s.ktx2',
50+
'3D / BasisU UASTC': '3d_uastc.ktx2',
51+
'3D / RGBA8 sRGB': '3d_rgba8.ktx2',
52+
'3D / RGBA8 Linear': '3d_rgba8_linear.ktx2',
53+
'3D / RGBA16 Linear': '3d_rgba16_linear.ktx2',
54+
'3D / RGBA32 Linear': '3d_rgba32_linear.ktx2',
55+
'3D / RGBA32 LUT': '3d_rgba32_lut.ktx2',
56+
57+
// Cube
58+
'Cube / BasisU ETC1S': 'cubemap_etc1s.ktx2',
59+
'Cube / BasisU UASTC': 'cubemap_uastc.ktx2',
60+
'Cube / RGBA8 sRGB': 'cubemap_rgba8.ktx2',
61+
'Cube / RGBA8 Linear': 'cubemap_rgba8_linear.ktx2',
62+
'Cube / RGBA16 Linear': 'cubemap_rgba16_linear.ktx2',
63+
'Cube / RGBA32 Linear': 'cubemap_rgba32_linear.ktx2',
64+
65+
// Array
66+
'Array / BasisU ETC1S': 'array_etc1s.ktx2',
67+
'Array / BasisU UASTC': 'array_uastc.ktx2',
68+
'Array / RGBA8 sRGB': 'array_rgba8.ktx2',
69+
'Array / RGBA8 Linear': 'array_rgba8_linear.ktx2',
70+
'Array / RGBA16 Linear': 'array_rgba16_linear.ktx2',
71+
'Array / RGBA32 Linear': 'array_rgba32_linear.ktx2',
4572
};
4673

4774
const FORMAT_LABELS = {
@@ -87,7 +114,6 @@
87114
window.addEventListener( 'resize', onWindowResize );
88115

89116
scene = new THREE.Scene();
90-
scene.background = new THREE.Color( 0x202020 );
91117

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

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

99-
// PlaneGeometry UVs assume flipY=true, which compressed textures don't support.
100-
const geometry = flipY( new THREE.PlaneGeometry() );
101-
material = new THREE.MeshBasicMaterial( {
102-
color: 0xFFFFFF,
103-
side: THREE.DoubleSide,
104-
transparent: true,
105-
} );
106-
const mesh = new THREE.Mesh( geometry, material );
107-
scene.add( mesh );
108-
109125
loader = new KTX2Loader()
110126
.setTranscoderPath( 'jsm/libs/basis/' )
111127
.detectSupport( renderer );
@@ -146,10 +162,19 @@
146162

147163
const texture = await loader.loadAsync( `./textures/compressed/${path}` );
148164
texture.minFilter = THREE.NearestMipmapNearestFilter;
165+
texture.needsUpdate = true;
166+
167+
if ( helper ) {
168+
169+
scene.remove( helper );
170+
helper.dispose();
171+
172+
}
149173

150-
material.map = texture;
151-
material.needsUpdate = true;
174+
helper = new TextureHelper( texture );
175+
scene.add( helper );
152176

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

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

165-
166-
}
167-
168-
/** Correct UVs to be compatible with `flipY=false` textures. */
169-
function flipY( geometry ) {
170-
171-
const uv = geometry.attributes.uv;
172-
173-
for ( let i = 0; i < uv.count; i ++ ) {
174-
175-
uv.setY( i, 1 - uv.getY( i ) );
176-
177-
}
178-
179-
return geometry;
180-
181190
}
182191

183192
</script>

src/Three.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export { FramebufferTexture } from './textures/FramebufferTexture.js';
3131
export { Source } from './textures/Source.js';
3232
export { DataTexture } from './textures/DataTexture.js';
3333
export { DataArrayTexture } from './textures/DataArrayTexture.js';
34+
export { DataCubeTexture } from './textures/DataCubeTexture.js';
3435
export { Data3DTexture } from './textures/Data3DTexture.js';
3536
export { CompressedTexture } from './textures/CompressedTexture.js';
3637
export { CompressedArrayTexture } from './textures/CompressedArrayTexture.js';

src/textures/DataCubeTexture.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Texture } from './Texture.js';
2+
import { CubeReflectionMapping } from '../constants.js';
3+
4+
class DataCubeTexture extends Texture {
5+
6+
constructor( data, width, height ) {
7+
8+
super( data, CubeReflectionMapping );
9+
10+
this.isDataCubeTexture = true;
11+
this.isCubeTexture = true;
12+
13+
this.image = { data: data, width: width, height: height };
14+
15+
this.generateMipmaps = false;
16+
this.flipY = false;
17+
this.unpackAlignment = 1;
18+
19+
}
20+
21+
get images() {
22+
23+
return this.image;
24+
25+
}
26+
27+
set images( value ) {
28+
29+
this.image = value;
30+
31+
}
32+
33+
}
34+
35+
export { DataCubeTexture };

0 commit comments

Comments
 (0)