-
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
KHR_texture_transform #1015
KHR_texture_transform #1015
Conversation
Couple notes:
|
|
extensions/README.md
Outdated
@@ -10,6 +10,9 @@ _Draft Khronos extensions are not ratified yet._ | |||
* [KHR_materials_common](Khronos/KHR_materials_common/README.md) | |||
* [KHR_technique_webgl](Khronos/KHR_technique_webgl/README.md) | |||
|
|||
#### Vendor extensions | |||
* [AVR_sampler_offset_tile](Vendor/AVR_sampler_offset_tile/README.md) |
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.
Please, update this line.
|
||
### Example JSON | ||
|
||
This example utilizes only the top left quadrant of the source image. |
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.
Given that offsetS
is 0.5, it seems like top right quadrant is used.
@stevenvergenz Could you check?
}, | ||
"tileS": { | ||
"type": "number", | ||
"description": "How many times the texture is repeated across the surface, in the S direction.", |
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.
Since tile
is [-1, 1]
, could description be rephrased to not use "How many times"?
Text from readme (size of region) seems to be more precise, imho.
Fixed those oversights, and reworded the descriptions in the schema. |
Not a very strong opinion, but there could be benefits (as well as drawbacks) of moving this extension to With current design, {
"materials": [
{
"emmissiveTexture": {
"index": 0
}
},
{
"emmissiveTexture": {
"index": 1
}
}
],
"textures": [
{
"source": 0,
"extensions": {
"AVR_texture_offset_tile": {
"tileS": 0.5,
"tileT": 0.5
}
}
},
{
"source": 0,
"extensions": {
"AVR_texture_offset_tile": {
"tileS": 0.5,
"tileT": 0.5,
"offsetS": 0.5
}
}
}
]
} However, this could be beneficial for glTF-to-glTF processing (e.g., individual textures could be converted to atlas without touching materials). Also, this scheme allows storing only texture atlas in glTF asset without anything else. Other approach could be to move atlas information to {
"materials": [
{
"emmissiveTexture": {
"index": 0,
"texCoord": 0,
"extensions": {
"AVR_texture_offset_tile": {
"tileS": 0.5,
"tileT": 0.5
}
}
}
},
{
"emmissiveTexture": {
"index": 0,
"texCoord": 0,
"extensions": {
"AVR_texture_offset_tile": {
"tileS": 0.5,
"tileT": 0.5,
"offsetS": 0.5,
"offsetT": 0.5
}
}
}
}
],
"textures": [
{
"source": 0
}
]
} Pros: more compact representation and possibly easier runtime processing. |
The way I see it, there are two primary use cases:
Since the lightmap implementation is at a disadvantage either way, I think I'll move it to textureInfo, and handle the odd case in that extension's semantics. |
Reading through mrdoob/three.js#11577, my feeling is that the Despite the possible need for grouping by source, I think it's simpler to implement this extension, and to work out any necessary optimizations, with all properties in |
Why not use uniforms for handling |
Oh, no not copying the image data (we do use uniforms for tile and offset) but the THREE.Texture object that wraps it must be cloned to have different tile/offset values. So not particularly expensive, but complicates implementation a bit. |
Any updates here? Seems like this got a bit of an uptick in interest. Also I notice that one of your sample usages provided in the docs here is the equivalent of a FLIP_Y flag, for people who wish that glTF's vertical texture coordinates went the other way.
|
Are there any desired changes? I considered this extension complete. Though looking back, it's probably worthwhile to remove the [-1,1] restriction on the fields. There are use cases for having tile values greater than one that I hadn't considered when initially authoring this. Plus, now that AltspaceVR has been acquired by Microsoft, I probably need to change the vendor extension. |
The link to the UnityGLTF can probably be updated to the Khronos one.
Does it make sense for this to be a EXT_? |
Any updates here?I'm waiting for this feature in our project . |
I'm not sure what happens with an occlusion map actually, but otherwise that's correct.
three.js will take the first transform it finds, if any, and apply it to all textures (unsure about occlusion maps).
Agreed.
Not sure I follow... I think you're describing how a client that doesn't support texture transforms but does support multiple UVs could bake the transform to UVs on the fly, if needed? |
^I'm not sure what change(s), if any, would follow from this. Certainly there is no need to constrain this extension to three.js's current limits. I'm mostly trying to understand our fallback recommendation, and whether the Generally my sentiment is that extensions meant for optimization should never be included by model catalogs like Sketchfab or Turbosquid, but added by later tools, in which case making all extensions optional is less important. I think the Draco extension is a clear example of that. This one I'm not sure about... the "texture atlas" use case we describe is an optimization, but texture animation is not. I'm hoping this extension will be widely implemented enough that it's a moot point. |
I'm not opposed to anything here, just trying to think this one through. It strikes me as a bit odd that the seemingly common case of applying the same transform to multiple images can only be done by repeating the same transform information per image, and can only be detected by comparing such information. But I don't have a better idea how to structure the extension without limiting its flexibility. |
Yes, I suppose this also means that (in some future version where texture transforms may be animated) the animation must target each texture with a separate channel? It's verbose but does seem like the more flexible choice. |
If an optimization happens and stays within a closed ecosystem, then it's okay. If an asset ever leaves that closed ecosystem intentionally, the asset should not have any required extensions.
If someone serves an asset with Draco compression from a server intending for anyone to consume (i.e. not a closed ecosystem), then I would expect Draco to be optional. I would expect the same thing for this texture transform extension. These optimizations will offer better performance for clients that support the extension while keeping compatibility with clients that don't support the optimizations. If we don't do this, we risk fragmenting the ecosystem. In the future, when we introduce a new version (probably 3.0 because of forward compatibility requirements for 2.x) where Draco and this extension is part of the spec, these kind of problems will go away. |
This makes sense, and I'm glad that we're ensuring optional extensions are possible. But, we're making a broad recommendation here that (as written) seems to imply all exporters should always include both. I don't expect exporters to do that, nor am I sure that they should. Things get complicated if an API wants to ensure an asset includes separate
Broadly I don't think there is any single recommendation we can make for all exporters. At some point I would like to write more detailed best practices for extensions in general, based on the functional role of the extension and the sort of ecosystem in which the model will appear. I'm fine with moving forward with this extension as-is and potentially rephrasing this implementation note at a future date. The points @emackey brings up are interesting; I imagine the first exporter implementation will run into some of that. So far it does still appear that this approach is the right one. |
I basically agree with this. +1 on rephrasing the implementation note.
I think exporters will need to decide which optimization extensions to use. I don't think there will be a need for all possible permutations. For example, there can be one path for the optimized version (i.e. both Draco and texture transform together), all other cases can use core only. But I'm not sure this works out. Can we ensure that an asset is authored such that a client implementation will only load the optimized path if both Draco and texture transform are supported or else fall back to core? |
|
||
## glTF Schema Updates | ||
|
||
The `KHR_texture_transform` extension may be defined on `textureInfo` structures. It may contain the following properties: |
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.
Does
textureInfo
structures
cover inherited structures as well (i.e., occlusionTextureInfo
and normalTextureInfo
)?
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 would say yes since both occlusionTextureInfo
and normalTextureInfo
inherit from textureInfo
.
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.
OK. It would be nice to have sample models showing those cases (I've run into this internally).
I don't think that's feasible, without resorting to requirements specific to these two extensions. Let's assume both the compressed and uncompressed mesh would need to include transformed and untransformed UVs, as the client makes a decision on each extension separately. An exporter might split that as follows:
That's OK, and shouldn't be especially complex for the client to load efficiently. But whether that complexity is worthwhile probably depends on the situation:
|
Three.js is somewhat confusing when it comes to this. Depending on what combination of textures is in your material, it will randomly apply the offset to all the maps but sampling from only one. I think the relevant code is here: |
I agree with this. I had no idea that three.js is such a big authority on a format like glTF. From which point should i try to observe this situation? Three.js on it's own may not be aware of a file format like
So someone sat down, used the core of the library and wrote an example for loading the Three.js users can use the library out of the box, but can also infinitely extend it. The complicated way would be to fork it and implement your features, but it does have various apis that allow one to extend the core features. I've made a quick demo to test this claim: It uses a single texture object, with a single image source for two different map slots This one applies it to most of the maps found in three.js's rough/metal PBR material: I'm not sure if it tackled this specific issue as i've somewhat got lost in the comment but this is what it's supposed to do. Outside the demo
In the demo
Would this be a valid way to approach this? Since This one uses the same extension applied to the GLTFLoader. Ie. this version of the loader has no limitations mentioned in this thread, but it depends on another 3rd part example, not the core: |
Could the loaders transform this without sending the duplicated uvs through the wire (or even storing them)? There could still be multiple vertex buffers for each of the duplicated uvs, but at least they would be transferred as a single one. Although this seems like an optimization the client should make. Should it be baked and consume more attributes, or should it be computed on the fly (either in .fs or .vs). But writing and transferring these seems redundant. I always thought of channels as something rather specific, holding a 2d version of the mesh, but not necessarily even having the same topology. ie. UV0 could have N vertices, UV1 could have M vertices, while the mesh itself could have X vertices. This kind of stuff is important to store in its own channel. Wether some linear transformation is applied to this, i think shouldn't matter. |
I've opened up an ancient version of 3ds max to compare this, and they seem to couple this with the texture object. I'm mostly curious about how this extension would affect three.js. This screenshot corresponds to how three.js is already structured, the texture has what's called The source though is still the same bitmap, which could be a texture atlas. Animation though seems like it would be a completely different use case. Unity though looks like it has 2 (or more) channels with individual tiling controls on the material? |
I have updated this demo, to include one of the gltf models from the three.js repo: Exposed with the dat.gui are some transform parameters for the specularMap, but how it's done is just one implementation. I think it would make sense for this to be obtained from some texture object, that could share some source bitmaps. |
Hi everyone, This is not really directly a contribution to the discussion, but rather a general wondering of how using this kind of extension could be made optional? I mean, if we have a glTF using this extension: ...
"emissiveTexture" : {
"index" : 2,
"extensions": {
"KHR_texture_transform": {
"offset": [0, 0.1],
"scale": [0.2,0.2]
}
}
}
... How can a client without support for it display anything remotely usable? I mean, if it's going to use a texture atlas without knowledge of the extra parameters in Thanks a lot in advance for the clarification. |
I can reason about this better if it weren't an extension. I fear that what you're describing can be mitigated by a network of fallback options, but i don't like those solutions. I went to a recent meetup for glTF extensions, but I missed the introduction thus missing a lot. Looking forward to clarification. |
@pailhead is the Meetup: Get your glTF on with WebGL/WebVR at Microsoft! you are referring to? |
@silvainSayduck There is a note about how fallback should apply with this extension using the texCoord field:
The texture would always be an atlas but one portion of it would be applicable for clients that don't implement the extension. |
Correct. The example that stuck in my head was the LOD presentation. I didn't see what benefits the extension brings over what's already available in the format. Ie. why can't this type of management be achieved with a naming convention I think the draco one discussed fallback options, so i have a bit of bias in this topic, when i try to understand something like this:
I imagine an atlas that includes itself, and a fallback texture, ie. the client without the extension would just read (half?) the texture, which actually doesn't make sense since it would still require some kind of scale and offset. How does this sentence apply to a layout of a bitmap (that is to be used for this example)? Why would two models, one using textures, another an atlas even be considered the same? This seems like something some server side API would be doing, based on client capabilities figure out what data the client needs. I understand this would now happen in the gltf header, it notifies the client of the presence of an additional system. I don't understand what happens next conceptually. In this case i think it would be up to an implementation to store And then again, if it has fallback options, could it be a naming convention for storing in the scene graph, I think i have a hard time understanding how extensions should fit the entire ecosystem, point me in the right direction as it seems to be a bit of a digression from this topic. |
I agree 100% with this... :) If someone knows a more appropriate place for the genera discussion around this, it would be awesome!
Thanks for the clarification guys! However, we are actually planning to use this extension for tiling textures: basically, using a "low-resolution" texture that we tile across the whole mesh for high visual quality with low texture file size. And obviously in that case, unless I'm mistaken, including both a "non-tiled" texture and the tile as an atlas will defeat the original purpose. So I guess we'd have to go with the |
Some of the questions raised here are also discussed in #1256 |
Is this ready to merge? I think just update https://github.com/KhronosGroup/glTF/blob/master/extensions/README.md so that |
Merged via #1372 — opened a new PR to rebase. |
As a prerequisite to an upcoming baked lighting extension, I needed the ability to atlas textures. This is a good start I think. Any comments?