KhronosGroup / glTF

glTF – Runtime 3D Asset Delivery
Other
7.13k stars 1.13k forks source link

glTF 2.0: texture packing for Metallic-Roughness? #857

Closed donmccurdy closed 7 years ago

donmccurdy commented 7 years ago

From this paragraph, I see that the Metallic-Roughness workflow will make use of texture packing by assigning:

Channel Map
R Metallic
G Roughness
B
A

Were there plans for using the B channel later? If Occlusion is the obvious next choice, is it worth altering the order to match UE4's Occlusion/Roughness/Metallic R/G/B ordering?

I'm not very familiar with texture creation workflows, so maybe this is a non-issue and easy for exporters/converters to deal with. But thought I'd ask, as THREE.MeshStandardMaterial is already configured for that OcclusionRoughnessMetallic ordering. Thanks!

pjcozzi commented 7 years ago

@mlimper?

mlimper commented 7 years ago

That actually sounds like a reasonable proposal - especially as it's already being used elsewhere like that.

The ordering should not be an issue IMHO, if we can make it fit existing conventions, that sounds like a plus.

Only thing we might want to make sure is that people can use the extension safely without having an occlusion map... which then probably means that somewhere inside the glTF material description we will want to specify whether the texture content has an occlusion channel or not.

@sbtron and colleagues, what do you think?

lexaknyazev commented 7 years ago

I fully support merging them and defining static channel mapping at least for MR. Texture swizzling isn't available in WebGL, so engines would need to maintain multiple versions of shader code to support different mappings.

How would SpecGloss model fit with such change?

lexaknyazev commented 7 years ago

Without swizzling support, this would require shader regeneration to cover arbitrary cases.

mlimper commented 7 years ago

One fixed mapping sounds OK. Why have multiple ones? Separate textures seems like an unnecessary step, given that we're aiming for a delivery format - it's not supposed to be authored as-is.

sbtron commented 7 years ago

The idea with the additional maps in the core spec was to be able to share them across multiple material models so other material models defined through extensions could also use them. The spec gloss material defined in extension can also use the common occlusion map as its currently proposed - https://github.com/sbtron/glTF/tree/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness#additional-maps.

Packing it with metal roughness while useful for metal roughness would make it unavailable to spec gloss or other future material extensions.

emackey commented 7 years ago

@sbtron But an exported spec/gloss model wouldn't want a loose occlusion map would it? It would be more useful to bundle the occlusion and gloss maps together for a spec/gloss model, I would think. The ability to deliver a tightly packed model is more in line with the goals of glTF than the ability to re-use loose textures across extensions, I would think.

sbtron commented 7 years ago

@emackey the current specgloss texture doesn't have additional channels available as it is already packing spec (RGB) and gloss (A) together - https://github.com/sbtron/glTF/tree/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness#specularglossinesstexture

emackey commented 7 years ago

Ah OK, understood. Even so, the spec/gloss extension could simply define its own occlusion map and not rely on the core one, right? A single model won't use both approaches in the same file, so each approach should be optimized for itself, as opposed to re-usability between approaches.

bghgary commented 7 years ago

A single model won't use both approaches in the same file

The intention is that there can be both approaches in the same file. See https://github.com/sbtron/glTF/tree/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness#conformance-and-best-practices

The example models have both at the same time. https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/BoomBox/glTF-pbrSpecularGlossiness

emackey commented 7 years ago

there can be both approaches in the same file.

My mistake again. Is there no way to implement this without causing pain to the spec/gloss workflow? Since the proposal is Occlusion (R), Roughness (G), Metallic (B), could we say that rough/metal (G/B) are optional when extensions are present, and a grayscale version of the image can be supplied offering only occlusion?

I do think there's some value in conforming to an existing RGB mapping instead of inventing a new one, albeit limited value, not worth messing up the spec/gloss extension.

That said, the original post above contains a link to Substance Painter export settings, and I just confirmed that Substance Painter 2.4 can have user-defined channel mappings on export. So even if we stick to a channel mapping that's unique to glTF, it's not unreasonable to expect existing authoring tools to produce it.

lexaknyazev commented 7 years ago

Since the proposal is Occlusion (R), Roughness (G), Metallic (B), could we say that rough/metal (G/B) are optional when extensions are present, and a grayscale version of the image can be supplied offering only occlusion?

This also frees one texture unit. Possible layout with both models (note, that we still have unpopulated A channel in textures 2, 5, and 6):

  1. MR: BaseColor (RGB) + alpha-coverage (A)
  2. Occlusion (R) + Metallic-Roughness (GB)
  3. SpecGloss: Diffuse (RGB) + alpha-coverage (A)
  4. SpecGloss: Specular (RGB) + Glossiness (A)
  5. Normal - RGB (X/Y/Z)
  6. Emissive - RGB

One more possible caveat: we can't use JPEG for BaseColor / Diffuse textures, when they contain alpha channel. Is it OK with established workflows?

bghgary commented 7 years ago

Another thing to consider is whether the occlusion channel is in sRGB or linear space. Unity imports models using a grayscale texture in sRGB space while Unreal uses the aforementioned packed structure but in linear space. Supposedly using linear can cause banding, but I still have yet to find any real evidence that supports this.

javagl commented 7 years ago

Although the compression for JPG heavily depends on the image contents, consider, for example, the baseColor texture of the BoomBox sample, and the following file types and sizes:

When the spec dictates (for example, for Spec/Gloss case) that the images must have an alpha channel, and thus, that they must be stored as PNG, then the arguments for combining these channels into a single (namely, that "glTF is a transmission format and has to be compact") are rendered absurd by the fact that two images could be created which (essentially) contain the same information, but only have one tenth of the size of the proposed format.

Disclaimer: I don't have a clue about other image formats, KTX and whatnot. All I can say is that "common" textures as (highly-compressed) PNGs are still up to 10 times larger than a JPG with a high quality setting that is hardly distinguishable from the original PNG. So I'd at least advocate for not enforcing the use of PNG in the spec.

emackey commented 7 years ago

Lossy JPG, even at high quality settings, may not be the best format for metal/rough/occlusion. In JPG, high-contrast lines in a single color channel tend to bleed into the other two channels, because for normal images that's not too noticable to the eye. JPG lossiness is based on what human vision can't see in an image. When the 3 channels represent un-related linear values, such as occlusion, metal, and roughness, a high-contrast boundary in one channel may not be present in the other channels, and JPG could easly allow such details to bleed into the wrong channels. PNG is non-lossy compression and shouldn't have this particular problem (although browsers do a terrible job auto-converting color spaces in PNG files in uncontrollable ways, but I digress).

lexaknyazev commented 7 years ago

In JPG, high-contrast lines in a single color channel tend to bleed into the other two channels,...

That's valid reason against JPGs for MR textures. What about baseColor + alpha-coverage?

although browsers do a terrible job auto-converting color spaces in PNG files in uncontrollable ways

An updated texture/image definitions PR explicitly demands disabling any browser conversions. Please see #860.

emackey commented 7 years ago

That's valid reason against JPGs for MR textures. What about baseColor + alpha-coverage?

JPG should be fine for basecolor RGB. It does not support Alpha, though.

Likewise, for a specular map (although I've demonstrated some spec/gloss ignorance in this thread already), I'd wager that an RGB specular map is essentially an image that JPG would preserve nicely. But again, the gloss map needs the alpha channel, which JPG does not offer. So that's a non-starter unless the gloss map is moved elsewhere.

I'm not sure what JPG would do to a normal map. At least it doesn't need the alpha channel, and the RGB channels are more directly related than a roughness channel is to a metallic channel. Even so I'm not sure what damage JPG's compression would do to vectors.

javagl commented 7 years ago

@emackey Sure, sharp edges may cause artifacts. And it's more likely that the "bleeding" will be more visible when it affects e.g. an emission channel than e.g. an occlusion channel. So in general, it's difficult to make a statement about how "noticable" they are for certain channels, certain textures and certain compression factors.

I'm just mentioning this, and leave it to others to either draw conclusions from that or not, but the point is: The potential size difference between PNG and JPG is huge. So huge that one Metallic/Roughness/Occlusion PNG may easily still be three times larger than three individual JPGs, each storing one channel...

emackey commented 7 years ago

The potential size difference between PNG and JPG is huge.

Agreed, but keep in mind, this size difference is only in terms of file size or network bandwidth, not GPU memory. Both formats result in un-compressed arrays of pixels in memory. So using three JPGs in place of a single PNG may save network traffic, but costs both texture memory and texture units.

Here's my impression of the various goals and priorities that have been discussed on this thread so far. Let me know if I got this all straight.

bghgary commented 7 years ago

I'm not an expert on loading images on the web. Is there an efficient way to load two images (say an RGB jpg and a grayscale jpg) into a single 4-channel texture (where the grayscale jpg is loaded into the alpha channel)?

I had always assumed that separating the images for each type of data would be an issue for texture bandwidth, but if it's efficient to load multiple images into one texture, then perhaps it's not an issue. If it is efficient, then maybe we should separate each type of data as different unpacked images so that jpg can be used when appropriate?

lexaknyazev commented 7 years ago

All WebGL texture functions operate on one texture source at a time. So one option is to manually manipulate ImageData before texture upload (JS loop through all pixels), other option is to use GPU and render-to-texture pre-pass to combine two textures.

Thoughts?

bghgary commented 7 years ago

I propose that we move the discussion about png/jpg into a separate issue where I will try to quote / summarize what happened here. The original issue is regarding packing of the textures which we can continue to resolve here. Any objections?

emackey commented 7 years ago

I think the core issue here is selecting which channels go where, and unfortunately JPG has some influence on that by failing to provide a proper alpha channel, encouraging us to sway towards RGB textures instead of RGBA in the spec.

There's another reason (outside of JPG) to sway towards RGB as well: Many image manipulation software packages deliberately ignore or discard RGB data for pixels where alpha == 0. Sometimes this is done in the name of information security, preventing your paint program from "leaking" data that you though you erased from your image when you cleared the alpha channel for a certain range of pixels.

<anecdote> In fact, my very first encounter with a sample PBR model was one that had a roughness map wedged into the alpha channel of a texture with metallic and ambient occlusion (with the blue channel unused!) and this caused me a fair amount of grief attempting to extract the original channels without them getting premultiplied by the roughness channel. </anecdote>

Obviously this is not a problem for the baseColor or diffuse map (as the alpha, if supplied, is intended to be used the traditional way where zero values mean discard). I suspect this may not be a problem for Spec/Gloss (Does the spec color matter at all when gloss == 0? I would expect it to not matter). But I would advise against dumping occlusion into some random alpha channel of an unrelated map.

option is to use GPU and render-to-texture pre-pass to combine two textures

Now this is an interesting option: Any given glTF runtime implementation has the option to do this kind of pre-pass on any glTF assets, to make them conform to the local engine's needs. If an engine wants the occlusion channel jammed into the alpha channel of the normal map, sure, do it in a prepass step, the glTF spec doesn't mind at all. glTF is a "transmission format" spec after all, we should worry less about what layout the engine needs internally and more about how to best pack these assets for transmission, with the knowledge that engines can unpack and rearrange assets at will. I could imagine a prepass step to convert any metal/rough-only assets to spec/gloss, and then offering support of both types of glTF while internally only needing a spec/gloss PBR shader with a condensed set of maps.

So in summary

After all this discussion, I'm still leaning back to the same idea we had a few days ago for the transmission format, now with the knowledge that individual engines have the option to remap all this during a pre-pass step if they don't like the delivered channel mappings.

  1. MR: BaseColor (RGB) + alpha-coverage (A)
  2. Occlusion (R) + Metallic-Roughness (GB)
  3. SpecGloss: Diffuse (RGB) + alpha-coverage (A)
  4. SpecGloss: Specular (RGB) + Glossiness (A)
  5. Normal - RGB (X/Y/Z)
  6. Emissive - RGB

All of these alpha channels are optional (for models that don't use translucency, which no web developer expects JPG to provide), with the exception of (4) the glossiness one. But that's in an extension, so if someone thought it was critical to avoid, they could avoid the extension, and produce a core glTF 2.0 file with no alpha channels at all. Their engine could remap the channels at load time and maybe save a texture unit or two without their knowledge. Thoughts?

emackey commented 7 years ago

Whoops, correction on (2) above:

Occlusion is (R), Roughness is (G), and Metallic is (B), per the original post in this issue.

lexaknyazev commented 7 years ago

Since GPU can't render to compressed texture formats, insisting on runtime remapping could reduce efficiency. Such remapping is possible, but I don't think it should be encouraged as default approach.

bghgary commented 7 years ago

Occlusion is (R), Roughness is (G), and Metallic is (B)

I'm trying to see how to make this work with the JSON.

Here is what the current JSON looks like with both metallic-roughness and specular-glossiness right now:

"materials": [
    {
        "pbrMetallicRoughness": {
            "metallicRoughnessTexture": {
                "index": 1
            }
        },
        "occlusionTexture": {
            "strength": 0.75,
            "index": 2
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 3
                }
            }
        }
    }
]

I'm not sure what it would look like if we packed occlusion with metallicRoughness. Here is an attempt at it:

"materials": [
    {
        "pbrMetallicRoughness": {
            "occlusionRoughnessMetallicTexture": {
                "occlusionStrength": 0.75,
                "index": 1
            }
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 2
                }
            }
        }
    }
]

Are we saying the specular glossiness extension should use the occlusionRoughnessMetallicTexture for the occlusion data?

bghgary commented 7 years ago

@emackey Does the spec color matter at all when gloss == 0?

Yes, spec color matters a lot when gloss is 0.

See https://bghgary.github.io/glTF/convert-between-workflows-bjs/ and play with the spec gloss values to see for yourself.

emackey commented 7 years ago

Are we saying the specular glossiness extension should use the occlusionRoughnessMetallicTexture for the occlusion data?

Is that too clumsy? My thought earlier was that rough/metal would be optional, and you could supply a grayscale image in its place with only occlusion. But seeing the JSON makes it clear that the full name occlusionRoughnessMetallicTexture would still be in there even if the intention was to omit rough/metal. That seems a little clumsy. Could the spec/gloss extension supply its own optional occlusionTexture for use only on models that don't include a core occlusionRoughnessMetallicTexture? The shader code should be the same, using only the red channel from whichever one was supplied. (This isn't a new idea: ThreeJS already implemented it, which is what spawned this very issue.)

spec color matters a lot when gloss is 0

See, for me at least, this is a strong argument to pull that gloss channel out of alpha and put it elsewhere, for fear that evil paint programs could destroy the spec color of zero-gloss texels. That and the JPG fans of the world want it out of there too, for different reasons. But, that brings us to:

GPU can't render to compressed texture formats

Ouch. Now here's a solid argument for supplying pre-compressed assets that are already packed full with 4 channels each and arranged the way the engine expects to use them, verbatim. This implies that the various engines can all accept our stock channel mapping, though. For example, if some engine was going to accept a metal/rough glTF and pre-convert it to spec/gloss before rendering, any GPU compression in the metal/rough texture would be lost.

Can we really expect most engines by default to accept texture-compressed assets with our chosen channel mappings (whatever they end up being) and use them as-is?

stevenvergenz commented 7 years ago

Could it be feasible to add a field to the texture data structure to sort of "swizzle" the image channels? Like include the RGBA image, then create two textures from it that use different combinations of channels. This would allow you to specify a texture for each field in the material, without worrying about channel coherence. I imagine something like this:

"images": [ {"uri": "my_uri.png", ...} ],
"textures": [
  {"source": 0, "channels": "A", ...},
  {"source": 0, "channels": "RGB", ...}
]

I know nothing about render pipelines, so I speak from an API design background. Let me know if the above is nonsense :)

emackey commented 7 years ago

@stevenvergenz No, I don't think so. One goal of glTF is to place any burdens on the authoring tools, not the runtime engines. We want to ship a format that is as ready-to-render as possible. (see more comments)

bghgary commented 7 years ago

Could the spec/gloss extension supply its own optional occlusionTexture for use only on models that don't include a core occlusionRoughnessMetallicTexture?

This would result in duplicate data. If different extensions all wanted to use the occlusion texture, the worst case would be that each extension defines its own copy of the occlusion data.

bghgary commented 7 years ago

evil paint programs could destroy the spec color of zero-gloss texels

This is premultiplied or associated alpha. Paint programs hopefully are not saving PNG with premultiplied alpha since it is defined by the PNG specification that PNGs are not premultiplied (see https://tools.ietf.org/html/rfc2083#page-75)

12.8. Non-premultiplied alpha

 PNG uses "unassociated" or "non-premultiplied" alpha so that
 images with separate transparency masks can be stored losslessly.
 Another common technique, "premultiplied alpha", stores pixel
 values premultiplied by the alpha fraction; in effect, the image
 is already composited against a black background.  Any image data
 hidden by the transparency mask is irretrievably lost by that
 method, since multiplying by a zero alpha value always produces
 zero.
emackey commented 7 years ago

This would result in duplicate data.

Sorry, my intention was for the spec to forbid this: The user can supply either occlusionTexture or occlusionRoughnessMetallicTexture, but not both. The provided texture ends up in the same sampler2D regardless of the name, and the red channel (only) is used for occlusion. The green and blue channels are optional, and supplying them implies compatibility with the metal/rough workflow.

bghgary commented 7 years ago

either occlusionTexture or occlusionRoughnessMetallicTexture, but not both

  1. Asset only has metallic-roughness, use occlusionRoughnessMetallicTexture
  2. Asset only has specular-glossiness, use occlusionTexture and specularGlossinessTexture
  3. Asset has both workflows, use occlusionTexture, occlusionRoughnessMetallicTexture (where the R channel is ignored because occlusionTexture has been provided), and specularGlossinessTexture

Is this what you mean? 3 seems pretty clunky.

emackey commented 7 years ago

My apologies for not being clear.

  1. Asset only has metallic-roughness, use occlusionRoughnessMetallicTexture
  2. Asset only has specular-glossiness, use occlusionTexture and specularGlossinessTexture (expecting a grayscale occlusionTexture, but specifically reading only the r channel so the shader is reusable)
  3. Asset has both workflows, use occlusionRoughnessMetallicTexture and specularGlossinessTexture. The spec/gloss workflow gets its occlusion from the r channel of occlusionRoughnessMetallicTexture, and ignores the g and b channels.
donmccurdy commented 7 years ago

Similarly, occlusionTexture could always use the r channel. Assets with both workflows would specify the same texture index for both occlusionTexture and occlusionRoughnessMetallicTexture.

"materials": [
    {
        "pbrMetallicRoughness": {
            "occlusionRoughnessMetallicTexture": {
                "occlusionStrength": 0.75,
                "index": 1
            }
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "occlusionTexture": {
                  "occlusionStrength": 0.75,
                  "index": 1
                },
                "specularGlossinessTexture": {
                    "index": 2
                }
            }
        }
    }
]
emackey commented 7 years ago

Always the r channel, yes. @donmccurdy's re-use of an index is perhaps cleaner than my attempt to make the two mutually exclusive.

bghgary commented 7 years ago

We probably should move the occlusionTexture out to the root level and have occlusionRoughnessMetallicTexture override the occlusionTexture. This way if another extension wants to use the occlusionTexture, it doesn't have to repeat the definition.

  1. metallic-roughness only

    "materials": [
    {
        "pbrMetallicRoughness": {
            "occlusionRoughnessMetallicTexture": {
                "occlusionStrength": 0.75,
                "index": 1
            }
        }
    }
    ]
  2. specular-glossiness only

    "materials": [
    {
        "occlusionTexture": {
            "strength": 0.75,
            "index": 1
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 2
                }
            }
        }
    }
    ]
  3. both workflows

    "materials": [
    {
        "pbrMetallicRoughness": {
            "occlusionRoughnessMetallicTexture": {
                "occlusionStrength": 0.75,
                "index": 1
            }
        },
        "occlusionTexture": {
            "strength": 0.75,
            "index": 1
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 2
                }
            }
        }
    }
    ]
bghgary commented 7 years ago

Now that we have a proposal for this, let's evaluate the options:

  1. Stay as currently proposed. Benefits: Easier to explain, understand, and parse. No change to existing implementations (i.e. BabylonJS, Sketchfab).

  2. Switch to occlusionRoughnessMetallic. Benefits: Matches UE4 packing scheme. Uses one less sample instruction in shader?

Is there anything else to consider?

emackey commented 7 years ago

@bghgary I like it!

One more question: Can the spec indicate that occlusion is intended to share an index with occlusionRoughnessMetallic? What happens if a wayward gltf file specifies different indicies? (I guess that implies data duplication, maybe the M/R workflow gets a different occlusion map than S/G for such cases. Or maybe the validator could just tell those people to use the same index).

emackey commented 7 years ago

Can anyone from the 2.0 early adopters (BabylonJS, Sketchfab, others?) chime in and tell us if this causes grief or makes life better with the reduced texture usage?

bghgary commented 7 years ago

Can the spec indicate that occlusion is intended to share an index with occlusionRoughnessMetallic?

I would probably just put an implementation note but not enforce it. If people want to duplicate the data for whatever reason, they should be free to do so.

bghgary commented 7 years ago

Argh, just thought of something that will unravel this again.

With the new proposal, runtimes that want to use the specular-glossiness workflow of assets that have both workflows will have to download/read the whole occlusionRoughnessMetallic texture even though it only needs occlusion. That is very inefficient.

The only option is to duplicate the data if we pack with metallic-roughness?

donmccurdy commented 7 years ago

This feels more implicit than I would like, but:

Metallic-Rough only:

"materials": [
    {
        "pbrMetallicRoughness": {
            "roughnessMetallicTexture": {
                "index": 1
            }
        },
        "occlusionTexture": {
            "strength": 0.75,
            "index": 1
        },
    }
]

Spec-Gloss only:

"materials": [
    {
        "occlusionTexture": {
            "strength": 0.75,
            "index": 1
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 2
                }
            }
        }
    }
]

Both workflows:

"materials": [
    {
        "pbrMetallicRoughness": {
            "roughnessMetallicTexture": {
                "index": 1
            }
        },
        "occlusionTexture": {
            "strength": 0.75,
            "index": 2
        },
        "extensions": {
            "KHR_materials_pbrSpecularGlossiness": {
                "specularGlossinessTexture": {
                    "index": 3
                }
            }
        }
    }
]

Channels, in all cases:

Map Channel
Occlusion r
Roughness g
Metallic b
Specular rgb
Glossiness a

EDIT: This is a bit inconsistent, in that roughnessMetallicTexture is combined but could have been separate roughnessTexture and metallicTexture, more like occlusionTexture, that presumably always will share the same index. :/

bghgary commented 7 years ago

If runtime wants to use metallic-roughness and the asset only has metallic-roughness, then it behaves one way, but if the asset also has specular-glossiness, then it behaves in a different way. This causes inconsistent behavior that may be unexpected. Do we want this complexity?

donmccurdy commented 7 years ago

I can't say for other runtimes, but for three.js I don't believe this is more complex. roughnessMap, metalnessMap, and aoMap will each be assigned individually, whether there are 1, 2, or 3 total textures. The references to channels in that documentation are incorrect: three.js assumes Occlusion/Roughness/Metallic = R/G/B.

But from a spec perspective, grouping some maps that share textures (metallic-roughness) but not others (occlusion) does feel more complicated, yes.

bghgary commented 7 years ago

I understand the setup is the same. Will the runtime performance be different if occlusion is in a separate texture? I would want to avoid an asset behaving differently between having an extension or not.

bghgary commented 7 years ago

Also note that the download behavior will be different because of the additional texture.

donmccurdy commented 7 years ago

I don't know what the effect is, but that concern makes sense.

Would it be kicking the can down the road to change the metallicRoughness texture to use the b and g channels respectively, with no other immediate changes to the spec?

Original post notwithstanding, I don't have a strong preference here. Wanted to suggest UE4's ordering as nice-to-have in the absence of other considerations, of which there are apparently plenty. 🙂

emackey commented 7 years ago

the asset only has metallic-roughness, then it behaves one way, but if the asset also has specular-glossiness, then it behaves in a different way

Hmm, I don't think so. With @donmccurdy's most recent proposal, the difference is really whether or not occlusion shares an index with metalRough, regardless of the presence of other workflows.

I like the strategy of saying occlusion is always r and rough/metal, if present, is always g/b, and the author then has the option of providing separate maps or using the same index to reference the same map when that's possible.

Does that resolve any of the concerns here?