-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Basis Universal and IBL with KTX2 images #1612
Conversation
As you already created a pull request, can you please add the |
Sure. Should I simultaneously remove SH? I don't think we have decided on a final form:
|
Hmm, thought we agreed on supporting both. But it is an either or. So do not kick out SH. But either SH or the diffuseMap has to be present. |
Thanks, I'll update the PR. |
@UX3D-nopper A few actionable items that should be addressed before marking this as ready for trial implementation.
|
|
||
### Normal Quality | ||
|
||
Data must be stored as a CTTF image with alpha channel conforming to RGBD (or RGBE, **TBD**) encoding. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming that we're suggesting CTTF here so that the texture can remain compressed in memory. However, block-based compression schemes really don't work well with RGBE because they don't take into account that the alpha is being used as an exponent. The result is usually a lot of ugly banding between exponent boundaries. I don't remember how RGBD behaves when block-based compression is used but I expect it would be better. We should do some tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RGBD, RGBE or RGBM should be decoded on CPU before uploaded to GPU. So, in general, not the perfect format but defined as mostly used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming that we're suggesting CTTF here so that the texture can remain compressed in memory.
Regardless of an effective GPU format, CTTF should give us better transmission bandwidth than typical web formats.
RGBD, RGBE or RGBM should be decoded on CPU before uploaded to GPU.
CPU decoding of RGBD (RGBE) from CTTF is expected to be supported.
If we want to achieve consistency, we should only allow either SH or difusse maps in a scene. |
Agree regarding "Provide complete sampling math for SH". |
From @sebavan
The comments in the code include all the math and relevant references. |
extensions/2.0/Khronos/KHR_image_ktx2/schema/image.KHR_image_ktx2.schema.json
Show resolved
Hide resolved
|
||
## Defining an Image-Based Light | ||
|
||
The `KHR_lights_image_based` extension defines a array of image-based lights at the root of the glTF and then each scene can reference one. Each image-based light definition consists of a single cubemap that describes the specular radiance of the scene, the l=2 spherical harmonics coefficients or another cubemap for diffuse irradiance, and also rotation, brighness factor, and offset values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be helpful to call out that the specular radiance cubemap has prefiltered data in its mips and that the diffuse irradiance map has only one mip?
```json | ||
"extensions": { | ||
"KHR_lights_image_based" : { | ||
"imageBasedLights": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the vendor extension, we had a list of images and the expected image size. This allows the possibly to drop a few mip levels at the end of the mip chain. Is this possible with this extension?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KTX2 allows random access to mip levels, so loaders can do whatever they see fit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but it needs to be specified here how to interpret the mip levels or we will get inconsistent behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For simplicity, I would recommend to just use the full mip map chain. What were Babylon.JS reasons, to have this feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #1377 (comment)
{ | ||
"rotation": [0, 0, 0, 1], | ||
"brightnessFactor": 1.0, | ||
"brightnessOffset": 0.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is brightnessOffset? Is this supposed to be a color? If so, why do we want this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
brightnessOffset
is for shifting the color range more into the darker or brighter area. E.g. required if the HDR maps are RGBM encoded and to support negative values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below, this section says:
finalSampledColor = sampledColor * brightnessFactor + brightnessOffset;
brightnessOffset
is currently a number. Is it supposed to be an offset per component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
finalSampledColor = sampledColor * vec3(brightnessFactor) + vec3(brightnessOffset);
Maybe more obvious like this.
In |
@zeux |
@lexaknyazev to my understanding a
At least for the use case of Basis textures referenced by materials, none of these reasons are self-explanatory to me... when might a Basis file be incompatible in a way that can only be known from the header? What implementations preallocate GPU resources this way? I'm a bit worried this is extra data that implementations will not actually use, and it has the side effect that users cannot easily swap out textures without modifying the JSON. It would be helpful to have a clear and robust example of why the extra data is necessary. |
Maybe another way of putting this – why are we using a KTX2 wrapper if we're going to replicate everything that wrapper provides? |
We're not going to use
Mip-levels cannot be generated online for compressed textures, so they have to be provided by an application. Without JSON form, apps would have to make an additional request (or two) to download texture file header to be able to progressively stream mip levels.
JSON copy of the header makes glTF clients simpler since they would be able to skip parsing the binary header and pull texture data directly.
Putting extra burden on exporters is aligned with other glTF choices. Geometry cannot be easily swapped out either. |
Ok, that's good thanks!
This seems like a very minor simplification, and in my opinion should be considered a non-argument compared to more important pros (fewer requests) and cons (confusing user workflows, redundant data).
We discussed a number of concerns about this on our call today, namely – the data is redundant, and common workflows today involve unpacking a We discussed an alternative – that the header information could be optional, or could be provided by a separate extension, such that it can be omitted until/unless tools exist that are actually progressively streaming mip levels. I am still open to that alternative, but an even better outcome would be this: can we get at least one common engine to implement support with streaming before ratification? The scenario I strongly want to avoid here is one where we've complicated the format for hypothetical streaming support, but later find that no one has actually implemented the perceived benefit, or that other features are actually necessary for that benefit to be practical. If we knew, for certain, that streaming textures will be implemented without requiring additional extensions, I'd be much more open to accepting the known cost of end-user confusion when externally referenced |
The size of the KTX2 header index fields is:
For 16384*16384 textures (currently the second most common max texture size), the This already unlocks streaming at the cost of one extra request compared to having all indices in JSON. |
I have a working prototype implementing parts of this PR. Still very raw, but a first step: I tested it on 4 models DGG3D kindly provided to me. Now I'd like to encode more glTFs to do more testing/stabilizing, but I could not get glTF-Compressonator to build yet. Asking for support did not yield in a response so far. Thanks! |
When we took over the Compressonator project, it did not build for us on Linux and/or Mac either. If you need the IBL images, please use this tool: |
Does anybody know if any web glTF viewer implements KHR_image_ktx2 (possibly in some development branch)? I'd like to add support to this to gltfpack but not sure how to test the resulting files. |
I could provide a Unity project + WebGL build with an URL input field. Current alpha state can load glTF (non-binary; separate files) with KTX textures (no levels, no mipmaps yet). Should take me a day or two to. I'm much interested in test files and ktx support in gltfpack on the other hand. Would be awesome if you share your results! |
|
||
JSON type of each metadata entry depends on the type of the original value. The JSON-Schema provides types for metadata keys defined in the KTX2 specification. | ||
|
||
This extension does not restrict texel formats or other features of the KTX2 images. Such limitations must be defined by other glTF extensions referring to this extension. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this necessary when the extension is marked as required? (I understand that it's possible to replace references to KTX2 images in "texture" object with references through extensions, but I'm not sure I understand why this is better than simply using an image/ktx2
MIME type on the image objects that are referenced directly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that KHR_image_ktx2
may be dropped entirely, and that the other extensions in this PR would simply independently allow KTX2 images. @lexaknyazev @bghgary is that a correct understanding of #1705 (comment)? This was confusing me as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(quick clarification, the comment got misplaced and refers to line 65 - implementation note - of the spec, not line 63)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KHR_image_ktx2 may be dropped entirely
This was my suggestion after attempting to implement it in Babylon. Unless we need some other metadata that goes with the extension, it will likely end up with a no-op implementation.
|
||
The `KHR_texture_basisu` extension is added to the `textures` node and specifies a `source` property that points to the index of the `images` node which defines a reference to the KTX2 image with Basis Universal supercompression. | ||
|
||
The following glTF will load `image.ktx2` in clients that support this extension, and otherwise fall back to `image.png`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(just clarifying) I am assuming that in absence of "source" property on the original texture JSON element, the loaders that support the extension must use the image specified through the extension metadata?
I've implemented support for these extensions in gltfpack: zeux/meshoptimizer#81. To build this yourself, make sure you have Here's an example - it's the Corset model from glTF-Sample-Models, converted to .glb with embedded KTX2 images: Note that the code is somewhat untested; please let me know if there are any issues with this! It's hard to test this without renderer support... |
@zeux, what software can I use to view |
@MarkCallow This file requires support for KHR_texture_basisu, KHR_image_ktx2 and KHR_mesh_quantization so I would not expect existing renderers to open it, but it could be used to validate support for the extensions from this PR in some work-in-progress renderer... |
hehe happy that the models were helpful we have an experimental KTX2 encoder branch, it was tested with a special (also experimental) BabylonJS branch for our joint demos for the BOF at SIGGRAPH the main reason it is called "experimental" is because the spec is still in draft state would it help if our devs run it on a couple of samples? |
I tried to load this glb in my prototype but I get an |
@atteneder please provide more details and, if it looks like a bug in KTX-Software, open an issue over there. How can I extract the ktx2 file(s) from the .glb? I tried opening with 7-zip but it says it can't open it. I also tried The Unarchiver on macOS. Be aware that ktxinfo just looks at the file header. I'd suggest trying ktx2check but I know it will fail as I haven't yet updated it for the latest KTX2 spec. draft and I know @zeux's files are compliant to that draft. However loading should still work, providing the file doesn't have other issues. |
I'll investigate this, since this implementation is written from scratch this is probably a bug on my end. Also attaching a .zip file where texture files aren't embedded into .glb for easier analysis. |
Ah, the mip levels are written from smallest to largest but the mip level index must be written from largest to smallest :-/ ktxcheck doesn't catch this, but loading the entire file does. After fixing this, the only other change that seems to be needed to get libktx to load these files is to align the last mip by 8 bytes. I'm not sure why this is necessary - the spec seems to explicitly call out that last mip doesn't need to be padded? - but libktx texture2.c has the following code that necessitates this:
|
Here's a new version; for easier testing, it contains the .glb (with embedded textures) as well as .gltf (with separate .bin + texture files) |
glb works smooth now! found some remaining bugs on my side though. |
Please file an issue at KTX-Software. |
how do you generate glb file? I am able to create glTF + bin + basis texture files but unable to pack them into one glb file using gltf-pipeline. Which tool are you using to output glb file? |
@ShantanuSriv These files are produced by gltfpack (https://github.com/zeux/meshoptimizer#gltfpack); |
Per discussion earlier, we are planning to:
@lexaknyazev or @bghgary would you be able to open a new issue for (3)? |
The story continues in #1751. |
Here's a set of work-in-progress extensions that will provide high-quality IBL with GPU-compressed textures.
Glossary
KTX2 - An image container file format optimized for GPU uploads. The spec is available here.
Basis Universal - Texture compression technology developed by Binomial. It enables JPEG-sized textures that can be transcoded on-the-fly to natively supported compressed GPU formats.
ASTC HDR - Block-compressed floating point GPU image format. Supported by many mobile devices and some desktop platforms.
BC6H - Block-compressed floating point GPU image format. Supported by many desktop and console platforms.
Proposed extensions
KHR_image_ktx2
Defined on glTF
image
, provides JSON form of the KTX header for better workflow on the web.Does not restrict allowed KTX2 features / formats.
KHR_texture_basisu
(requiresKHR_image_ktx2
)Defined on glTF
texture
, similar to WebP extension with optional fallback.This allows usage of Basis Universal images for IBL (normal quality) and material textures (albedo, roughness, etc).
EXT_texture_bc6h
andEXT_texture_astc_hdr
(requireKHR_image_ktx2
)Defined on glTF
texture
. The same texture object should haveKHR_texture_basisu
extension object for better compatibility.KHR_lights_image_based
(requiresKHR_image_ktx2
andKHR_texture_basisu
)Defines image-based lights on
scene
.