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

Conversation

CoryG89
Copy link
Contributor

@CoryG89 CoryG89 commented Aug 19, 2023

Description

I recently started working on a project that involves visualizing some astronomical data that exists in the form of high resolution HDR textures in the EXR format. The textures are very large so I needed to look into the best way possible to get the size down. I was able to compress the textures into BC6H format using NVIDIA Texture Tools using the DDS container file format, though when I tried it in three.js I realized that BC6H textures were not yet supported.

Compressed HDR textures in BC6H format are a relatively new thing, however from what I read, this should be available to GPUs that support DirectX 11+. In order to use BC6H textures in WebGL, your platform must support the EXT_texture_compression_bptc WebGL extension. I checked WebGL Report, and sure enough it seemed like BC6H textures should be supported in WebGL on my system (Windows 11/Chrome/NVIDIA RTX 3090). Although it looked like support was there, I was surprised to find that not only did three.js not have support for them yet, but I was also unable to find a single example of anyone using BC6H textures in WebGL at all despite significant effort.

After looking into it a bit more and studying Microsoft's documentation for BC6H textures as supported in DirectX 11 through the DDS file format, I decided to attempt implementing support myself. I successfully created a small proof of concept demo in pure WebGL, extending the DDS loading logic from toji/webgl-texture-utils. After the basic WebGL proof of concept was successful, I moved on to implementing support in three.js itself, leading to this pull request.

The three.js implemntation was also a success, allowing me to load compressed HDR textures in both signed and unsigned BC6H format using the DDS container file format. Please let me know if any additional changes are needed. Thank you.

Changes

  • Added values for BC6H formats to src/constants.js

  • Added logic for returning proper extension when BC6H formats were detected in src/renderers/webgl/WebGLUtils.js

  • Added support for parsing the DX10 extended header used for supporting BC6H textures in the DDS file format within examples/jsm/loaders/DDSLoader.js

  • Added unit tests for new constants in test/unit/src/constants.tests.js

  • Saved an existing DDS texture used in the examples in different BC6H variants:

    • examples/textures/compressed/disturb_dx10_bc6h_signed_mip.dds

    • examples/textures/compressed/disturb_dx10_bc6h_signed_nomip.dds

    • examples/textures/compressed/disturb_dx10_bc6h_unsigned_mip.dds

    • examples/textures/compressed/disturb_dx10_bc6h_unsigned_nomip.dds

  • Added logic to demonstrate the use of the 4 new sample BC6H variant formatted textures in the existing DDS example examples/webgl_loader_texture_dds.html

Related Links and Further Reading

  • EXT_texture_compression_bptc — MDN documentation for the related WebGL extension

  • NVIDIA Texture Tools Exporter — free utility capable of saving/converting textures to both the signed and unsigned variants of BC6H, with or without mipmaps (in addition to many other formats)

  • toji/webgl-texture-utils — Pure WebGL library with support for loading various kinds of DDS textures that the DDSLoader in three.js was originally based on.

  • BC6H Format — Microsoft's DirectX 11 documentation for the BC6H texture format

  • DDS_HEADER structure — Microsoft's documentation detailing the byte layout of the header used for the DDS file format

  • DDS_HEADER_DXT10 structure — Microsoft's documentation detailed the byte layout of the extended header for the DDS file format, which must be parsed in addition to the base header when loading DDS textures formatted using BC6H.

@github-actions
Copy link

github-actions bot commented Aug 19, 2023

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
646.2 kB (160.3 kB) 646.4 kB (160.3 kB) +262 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Filesize dev Filesize PR Diff
439.1 kB (106.4 kB) 439.3 kB (106.4 kB) +164 B

@Mugen87
Copy link
Collaborator

Mugen87 commented Aug 20, 2023

Do you mind removing the build files from your PR?

@Mugen87 Mugen87 added this to the r156 milestone Aug 20, 2023
Code style clean up.
@Mugen87 Mugen87 changed the title Support for BC6H textures DDSLoader: Add support for BC6H textures. Aug 20, 2023
@CoryG89
Copy link
Contributor Author

CoryG89 commented Aug 21, 2023

Do you mind removing the build files from your PR?

@Mugen87 Sure thing. Though I think removing the build files will cause the e2e test for examples/webgl_loader_texture_dds.html to start failing again. Without the build files, the test was just drawing solid black instead of the expected image. After looking into it, I found that this was happening because without the build files, the following error was being thrown:

SyntaxError: The requested module 'three' does not provide an export named 'RGB_BPTC_SIGNED_Format'

@Mugen87 Mugen87 merged commit f53bb7d into mrdoob:dev Aug 21, 2023
@Mugen87
Copy link
Collaborator

Mugen87 commented Aug 21, 2023

The E2E test automatically perform a build on the latest src so there should be no need to update build files.

@@ -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

@donmccurdy donmccurdy Aug 21, 2023

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.


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.


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

@donmccurdy donmccurdy Aug 21, 2023

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants