Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DDSLoader: Add support for BC6H textures. #26608

Merged
merged 6 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 46 additions & 3 deletions examples/jsm/loaders/DDSLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
RGBA_S3TC_DXT3_Format,
RGBA_S3TC_DXT5_Format,
RGB_ETC1_Format,
RGB_S3TC_DXT1_Format
RGB_S3TC_DXT1_Format,
RGB_BPTC_SIGNED_Format,
RGB_BPTC_UNSIGNED_Format
} from 'three';

class DDSLoader extends CompressedTextureLoader {
Expand Down Expand Up @@ -56,6 +58,9 @@ class DDSLoader extends CompressedTextureLoader {
// const DDPF_YUV = 0x200;
// const DDPF_LUMINANCE = 0x20000;

const DXGI_FORMAT_BC6H_UF16 = 95;
const DXGI_FORMAT_BC6H_SF16 = 96;

function fourCCToInt32( value ) {

return value.charCodeAt( 0 ) +
Expand Down Expand Up @@ -108,8 +113,10 @@ class DDSLoader extends CompressedTextureLoader {
const FOURCC_DXT3 = fourCCToInt32( 'DXT3' );
const FOURCC_DXT5 = fourCCToInt32( 'DXT5' );
const FOURCC_ETC1 = fourCCToInt32( 'ETC1' );
const FOURCC_DX10 = fourCCToInt32( 'DX10' );

const headerLengthInt = 31; // The header length in 32 bit ints
const extendedHeaderLengthInt = 5; // The extended header length in 32 bit ints

// Offsets into the header array

Expand All @@ -135,6 +142,9 @@ class DDSLoader extends CompressedTextureLoader {
// const off_caps3 = 29;
// const off_caps4 = 30;

// If fourCC = DX10, the extended header starts after 32
const off_dxgiFormat = 0;

// Parse header

const header = new Int32Array( buffer, 0, headerLengthInt );
Expand All @@ -152,6 +162,8 @@ class DDSLoader extends CompressedTextureLoader {

let isRGBAUncompressed = false;

let dataOffset = header[ off_size ] + 4;

switch ( fourCC ) {

case FOURCC_DXT1:
Expand All @@ -178,6 +190,39 @@ class DDSLoader extends CompressedTextureLoader {
dds.format = RGB_ETC1_Format;
break;

case FOURCC_DX10:

dataOffset += extendedHeaderLengthInt * 4;
const extendedHeader = new Int32Array( buffer, ( headerLengthInt + 1 ) * 4, extendedHeaderLengthInt );
const dxgiFormat = extendedHeader[ off_dxgiFormat ];
switch ( dxgiFormat ) {

case DXGI_FORMAT_BC6H_SF16: {

blockBytes = 16;
dds.format = RGB_BPTC_SIGNED_Format;
break;

}

case DXGI_FORMAT_BC6H_UF16: {

blockBytes = 16;
dds.format = RGB_BPTC_UNSIGNED_Format;
break;

}

default: {

console.error( 'THREE.DDSLoader.parse: Unsupported DXGI_FORMAT code ', dxgiFormat );
return dds;

}

}
break;

default:

if ( header[ off_RGBBitCount ] === 32
Expand Down Expand Up @@ -226,8 +271,6 @@ class DDSLoader extends CompressedTextureLoader {
dds.width = header[ off_width ];
dds.height = header[ off_height ];

let dataOffset = header[ off_size ] + 4;

// Extract mipmaps buffers

const faces = dds.isCubemap ? 6 : 1;
Expand Down
Binary file modified examples/screenshots/webgl_loader_texture_dds.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
61 changes: 53 additions & 8 deletions examples/webgl_loader_texture_dds.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
function init() {

camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.z = 10;
camera.position.z = 15;

scene = new THREE.Scene();

Expand Down Expand Up @@ -83,6 +83,23 @@
map6.anisotropy = 4;
map6.colorSpace = THREE.SRGBColorSpace;

const map7 = loader.load( 'textures/compressed/disturb_dx10_bc6h_signed_nomip.dds' );
map6.anisotropy = 4;
map6.colorSpace = THREE.SRGBColorSpace;

const map8 = loader.load( 'textures/compressed/disturb_dx10_bc6h_signed_mip.dds' );
map6.anisotropy = 4;
map6.colorSpace = THREE.SRGBColorSpace;

const map9 = loader.load( 'textures/compressed/disturb_dx10_bc6h_unsigned_nomip.dds' );
map6.anisotropy = 4;
map6.colorSpace = THREE.SRGBColorSpace;

const map10 = loader.load( 'textures/compressed/disturb_dx10_bc6h_unsigned_mip.dds' );
map6.anisotropy = 4;
map6.colorSpace = THREE.SRGBColorSpace;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My (macOS) computer doesn't support BPTC to test this, but I think the correct color space here is THREE.LinearSRGBColorSpace? Shouldn't affect rendering either way, but just to avoid any confusion!



const cubemap1 = loader.load( 'textures/compressed/Mountains.dds', function ( texture ) {

texture.magFilter = THREE.LinearFilter;
Expand Down Expand Up @@ -121,51 +138,79 @@
const material6 = new THREE.MeshBasicMaterial( { envMap: cubemap3 } );
const material7 = new THREE.MeshBasicMaterial( { map: map5 } );
const material8 = new THREE.MeshBasicMaterial( { map: map6 } );
const material9 = new THREE.MeshBasicMaterial( { map: map7 } );
const material10 = new THREE.MeshBasicMaterial( { map: map8 } );
const material11 = new THREE.MeshBasicMaterial( { map: map9 } );
const material12 = new THREE.MeshBasicMaterial( { map: map10 } );

let mesh = new THREE.Mesh( new THREE.TorusGeometry(), material1 );
mesh.position.x = - 6;
mesh.position.x = - 10;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material2 );
mesh.position.x = - 2;
mesh.position.x = - 6;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material3 );
mesh.position.x = - 2;
mesh.position.x = - 6;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material4 );
mesh.position.x = - 6;
mesh.position.x = - 10;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material5 );
mesh.position.x = 2;
mesh.position.x = -2;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material6 );
mesh.position.x = 2;
mesh.position.x = -2;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material7 );
mesh.position.x = 6;
mesh.position.x = 2;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material8 );
mesh.position.x = 2;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material9 );
mesh.position.x = 6;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material10 );
mesh.position.x = 6;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material11 );
mesh.position.x = 10;
mesh.position.y = - 2;
scene.add( mesh );
meshes.push( mesh );

mesh = new THREE.Mesh( geometry, material12 );
mesh.position.x = 10;
mesh.position.y = 2;
scene.add( mesh );
meshes.push( mesh );
Expand Down
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ export const RGBA_ASTC_10x10_Format = 37819;
export const RGBA_ASTC_12x10_Format = 37820;
export const RGBA_ASTC_12x12_Format = 37821;
export const RGBA_BPTC_Format = 36492;
export const SRGB_ALPHA_BPTC_Format = 36493;
export const RGB_BPTC_SIGNED_Format = 36494;
export const RGB_BPTC_UNSIGNED_Format = 36495;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: SRGB_ALPHA_BPTC_Format appears to be an unused constant for BC7. It is also the only format constant in three.js that implies a particular transfer function. I think we should instead remove the unused constant, and choose between SRGB_ALPHA_BPTC and RGBA_BPTC WebGL extensions in WebGLUtils.js based on the .colorSpace property.

export const RED_RGTC1_Format = 36283;
export const SIGNED_RED_RGTC1_Format = 36284;
export const RED_GREEN_RGTC2_Format = 36285;
Expand Down
8 changes: 5 additions & 3 deletions src/renderers/webgl/WebGLUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBAFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, _SRGBAFormat, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, SRGBColorSpace, NoColorSpace } from '../../constants.js';
import { RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBAFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, SRGB_ALPHA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, _SRGBAFormat, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, SRGBColorSpace, NoColorSpace } from '../../constants.js';

function WebGLUtils( gl, extensions, capabilities ) {

Expand Down Expand Up @@ -207,13 +207,15 @@ function WebGLUtils( gl, extensions, capabilities ) {

// BPTC

if ( p === RGBA_BPTC_Format ) {
if ( p === RGBA_BPTC_Format || p === SRGB_ALPHA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {

extension = extensions.get( 'EXT_texture_compression_bptc' );

if ( extension !== null ) {

if ( p === RGBA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
if ( p === RGBA_BPTC_Format || p === SRGB_ALPHA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: See above, I think we can remove SRGB_ALPHA_BPTC_Format here.

if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;

} else {

Expand Down
3 changes: 3 additions & 0 deletions test/unit/src/constants.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ export default QUnit.module( 'Constants', () => {
assert.equal( Constants.RGBA_ASTC_12x10_Format, 37820, 'Constants.RGBA_ASTC_12x10_Format is equal to 37820' );
assert.equal( Constants.RGBA_ASTC_12x12_Format, 37821, 'Constants.RGBA_ASTC_12x12_Format is equal to 37821' );
assert.equal( Constants.RGBA_BPTC_Format, 36492, 'Constants.RGBA_BPTC_Format is equal to 36492' );
assert.equal( Constants.SRGB_ALPHA_BPTC_Format, 36493, 'Constants.SRGB_ALPHA_BPTC_Format is equal to 36493' );
assert.equal( Constants.RGB_BPTC_SIGNED_Format, 36494, 'Constants.RGB_BPTC_SIGNED_Format is equal to 36494' );
assert.equal( Constants.RGB_BPTC_UNSIGNED_Format, 36495, 'Constants.RGB_BPTC_UNSIGNED_Format is equal to 36495' );
assert.equal( Constants.RED_RGTC1_Format, 36283, 'Constants.RED_RGTC1_Format is equal to 36283' );
assert.equal( Constants.SIGNED_RED_RGTC1_Format, 36284, 'Constants.SIGNED_RED_RGTC1_Format is equal to 36284' );
assert.equal( Constants.RED_GREEN_RGTC2_Format, 36285, 'Constants.RED_GREEN_RGTC2_Format is equal to 36285' );
Expand Down