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

GLTFLoader does not support texCoord fields #12608

Closed
1 of 3 tasks
stevenvergenz opened this issue Nov 8, 2017 · 19 comments · Fixed by #25721
Closed
1 of 3 tasks

GLTFLoader does not support texCoord fields #12608

stevenvergenz opened this issue Nov 8, 2017 · 19 comments · Fixed by #25721

Comments

@stevenvergenz
Copy link
Contributor

Description of the problem

Today, the Three.js engine does not allow the use of arbitrary UV coordinate sets for textures. Instead, they're hardcoded to channel 0 for all textures, except for lightMap which uses channel 1. As a result, the texCoord property of glTF textureInfo objects are ignored. Thus, the glTF loader is not compliant to the spec.

Once the engine supports UV channels better, this issue is a reminder to update the loader too.

Three.js version
  • Dev
  • r87
  • ...
@donmccurdy
Copy link
Collaborator

donmccurdy commented Nov 8, 2017

Hi @stevenvergenz — this requirement that most textures use uv1, except aoMap and lightMap which use uv2, is shared across all of three.js. It isn't possible to fix it just for a single loader without using a bunch of ShaderMaterials, which we don't want to do.

I'm not sure if there is interest/support for allowing per-texture UV sets in three.js. See: #8278

@donmccurdy
Copy link
Collaborator

^Which is not to say I'm opposed at all to supporting per-texture UV sets in three.js... I just don't know what the concerns/obstacles were with that previous PR.

@mrdoob
Copy link
Owner

mrdoob commented Nov 11, 2017

GLTF supports per-map uvs?

@donmccurdy
Copy link
Collaborator

Yes, each map can specify a UV set. But also:

Client implementations must support at least two UV texture coordinate sets, one vertex color, and one joints/weights set.

So, there is an expectation that for best compatibility models should not use more than 2 UV sets.

@MiiBond
Copy link
Contributor

MiiBond commented Apr 12, 2018

Just to chime in on this, Adobe Dimension's glTF exporter (which I'm currently writing) requires the second UV channel to display decals correctly.
We'll also be supporting separate transforms per texture in the near future which will also be problematic for three.js. Time for a refactor of how three.js materials use textures :) #8278

@mrdoob
Copy link
Owner

mrdoob commented Apr 13, 2018

@MiiBond Good to know. Thanks!

@donmccurdy
Copy link
Collaborator

@MiiBond could you say more about how you might use separate transforms per texture? A diffuse and occlusion map with different transforms, for example?

@donmccurdy
Copy link
Collaborator

If someone were to rebase and resolve conflicts on #8278, are there any changes that would make us more comfortable with it?

I like the fact that #8278 is so flexible and has a clear API, but if it seems like too much of a change, some ideas...

A. Give each material two (2) slots, rather than per-map slots.

// .map, .normalMap, .emissiveMap, ...
material.mapSlot = new THREE.MapSlot( channel1, transform1 );

// .aoMap, .lightMap, ...
material.mapSlot2 = new THREE.MapSlot( channel2, transform2 );

B. Put .channel on the Texture object, similar to .rotation:

material.map.channel = 1;

I don't like (b) as much, unless we can fix the issue that texture.clone() causes additional texture uploads.

@MiiBond
Copy link
Contributor

MiiBond commented Apr 16, 2018

@donmccurdy The most common use case would be for something like a detail map, typically a highly-tiled normal map to add detail at a far smaller scale than the rest of the map.

I would prefer a way to explicitly assign a UV channel and transform per map. Having slots locked to specific maps seems unnecessarily restrictive. In the case of Adobe Dimension, we will have separate transforms for each map. And, upon export to glTF, I'll be using UV1 to apply decals while still using UV0 for the underlying material (e.g. normal map).

When choosing a "channel" (i.e. UV0 or UV1), we might want to add options for common generated UV's. e.g. equirectangular projection, etc.

@goetzmoritz
Copy link

I started a disussion about this topic including some test-files here:
https://github.com/KhronosGroup/glTF-Blender-Exporter/issues/194

Actually, right now it seems that the ao-map just gets ignored when parsed by three-js gltf-plugin.

@donmccurdy
Copy link
Collaborator

donmccurdy commented Apr 18, 2018

Actually, right now it seems that the ao-map just gets ignored when parsed by three-js gltf-plugin.

Cross-posting from the other thread: "three.js is very particular about how multiple UV sets may be used. Most textures MUST use the first UV set, and ambient occlusion MUST use the second UV set. If ambient occlusion is present and only 1 set of UVs are available, a second set is automatically created at load time."

I would prefer a way to explicitly assign a UV channel and transform per map. Having slots locked to specific maps seems unnecessarily restrictive. In the case of Adobe Dimension, we will have separate transforms for each map. And, upon export to glTF, I'll be using UV1 to apply decals while still using UV0 for the underlying material (e.g. normal map).

If you're creating a new UV set for decals, why also use a per-map transform, as opposed to baking the transform into those UVs?

@MiiBond
Copy link
Contributor

MiiBond commented Apr 18, 2018

If you're creating a new UV set for decals, why also use a per-map transform, as opposed to baking the transform into those UVs?

We don't want separate UV channels for each map. All maps share UV0 and use transforms to tile (or rotate/translate) differently. The decals are a special case where Dimension is doing an intelligent application (i.e. a non-affine projection) of the decal on top of the material and generating its own UV's to avoid stretching, repetition, etc.

@goetzmoritz
Copy link

Thank you very much for your explanations.

How should the case of model-scale normal-maps be handled in the occasion that a tiling texture-map has it‘s own normals that should tile, too?

@donmccurdy
Copy link
Collaborator

donmccurdy commented Apr 18, 2018

Ok, thanks for clarifying @MiiBond.

@goetzmoritz three.js does not support this in default materials, sorry. You would need to use a custom ShaderMaterial.

@bhouston
Copy link
Contributor

bhouston commented May 7, 2018

I am currently running into this issue with our glTF exports from Clara.io. We should make Three.JS up to specification and it is also just an important feature for Three.JS.

@pailhead
Copy link
Contributor

pailhead commented May 30, 2018

It's conceptually trivial to solve this problem with existing Material functionality.

http://dusanbosnjak.com/test/webGL/three-materials-extended/webgl_materials_extended_multiple_uvs_props.html

With onBeforeCompile each "built-in" material can be selectively modified. For this use case, there are several texture2D( <mapName>, vUv) calls. One can add additional inputs for each map (i added two vec2 but could be the same pattern as the new texture transforms) and override vUv. One can safely ignore the remaining 1000+ lines of the shader.

@donmccurdy
Copy link
Collaborator

This is working nicely with NodeMaterial. Still constrained to two UV slots for now, but the textures can be assigned arbitrarily.

MeshStandardMaterial StandardNodeMaterial
screen shot 2018-07-14 at 11 10 37 pm screen shot 2018-07-14 at 11 31 17 pm

model from sketchfab and modified GLTFLoader code

@OlafHaag
Copy link

OlafHaag commented Aug 8, 2021

Hi! What's the current solution to this? For avatars (that don't need AO or a lightmap), we'd like to experiment with using the second UV channel for different purposes, like decoupling basecolor from the other channels. Other WebGL renderers display it just fine.

FYI: Unity on the other hand, assigns the GLTFUtility/URP/Standard(Metallic) material by default which uses UV0 for all sampler nodes, even for occlusion.

@donmccurdy
Copy link
Collaborator

Hi @OlafHaag – this is an unsolved issue currently. I had experimented with having GLTFLoader output NodeMaterial instead of base materials at one point (see previous comment), which does let you re-assign UV slots flexibly. But this isn't a general enough solution to merge into official GLTFLoader at the moment, IMHO, mostly because NodeMaterial doesn't support MeshPhysicalMaterial properties. Eventually I hope that will happen but I don't have a timeline.

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

Successfully merging a pull request may close this issue.

8 participants