KhronosGroup / glTF

glTF – Runtime 3D Asset Delivery
Other
7.16k stars 1.14k forks source link

glTF 2.0: Occlusion strength wrong description #884

Closed McNopper closed 7 years ago

McNopper commented 7 years ago

In my opinion, it should be like this:

"A scalar multiplier controlling the amount of occlusion applied. A value of 0.0 means full occlusion. A value of 1.0 means no occlusion. This value is ignored if the corresponding texture is not specified. This value is linear."

0.0 is full occlusion and 1.0 is no occlusion. I assume, these values are multiplied with the occlusion map texture,

emackey commented 7 years ago

Nice catch! :+1:

stevenvergenz commented 7 years ago

Wait, I'm confused. If you have an AO texture, and multiply its influence by 0.0, you would get no occlusion, not full occlusion, right?

emackey commented 7 years ago

The confusion is because "occlusion" is one of those negative concepts: the more occlusion you have, the less light shines through. Thus, black on an occlusion map means "full" occlusion, or no light. White on the occlusion map means there's no occlusion and the other material properties shine through full strength.

Perhaps there's better wording yet to be found.

stevenvergenz commented 7 years ago

Intuitively, I think of these scalar multipliers as influence weights, as that seems to work with the other texture factors (baseColorFactor, etc.). Applying that thinking to an occlusion map, I would expect a value of 1.0 to be "full influence", meaning that occluded areas of the mesh are rendered fully dark, and non-occluded areas are fully light. By comparison, a value of 0.0 would be as if you didn't supply an occlusion map at all, i.e. there are effectively no occluded areas.

Perhaps something like:

A scalar multiplier controlling the amount of occlusion applied. A value of 0.0 means this texture has no effect on the shading of the object. A value of 1.0 means this texture has full effect, i.e. triangles mapped to dark regions of the texture are rendered dark. This value is ignored if the corresponding texture is not specified. This value is linear.

McNopper commented 7 years ago

Its the same with transparent and opaque.

Occlusion is happing through covering, so going to 0.0, makes things darker and increases the occlusion. If it is going closer to 1.0, less covering happens and though less occlusion.

Important is, that "occlusionTexture * strength" is correct.

McNopper commented 7 years ago

Because finally, in a simple, extracted form: occludedColor = color occlusionTexture strength

stevenvergenz commented 7 years ago

@McNopper By that math, a strength value of zero would render the whole object solid black. I thought occlusion only applied to the dark regions:

occludedColor = mix(color, color * occlusionTexture, strength)

McNopper commented 7 years ago

But if u have black texels inside the occlusion texture, you have the same effect, that some pixels are black. And how strength is "weaking" the AO, should be better described anyway.

But also in your case, strength can be calculated in.

emackey commented 7 years ago

Occlusion is the way it is both because it "looks right" to artists, and because is easy to multiply in the shader. If it were reversed, the English definition would match better, but the shader would be more complex, and the image would look like a photo-negative to artists.

Here's the ambient occlusion channel from one of Substance Painter's demo objects:

ambientocclusiondemo

McNopper commented 7 years ago

So, as I am not a native english speaker, I suggest to enhance a liitle bit the description. Furthermore, it would be interesting how the strength should be applied.

stevenvergenz commented 7 years ago

@McNopper After re-reading our thread, I think I've pinpointed our mutual misunderstanding. Within a texture, a texel value of 0.0 is considered fully occluded, and 1.0 is non-occluded. With respect to the strength field though, a value of 1.0 means that the texture is fully applied, and a value of 0.0 means the texture is not applied.

From material.schema.json:

The occlusion map is a greyscale texture, with white indicating areas that should receive full indirect lighting and black indicating no indirect lighting.

You're right, the strength field description could be more explicit. Perhaps:

A scalar multiplier controlling the amount of influence the occlusion map is given. A value of 0.0 means no influence. A value of 1.0 means full influence. This value is ignored if the corresponding texture is not specified. This value is linear.

emackey commented 7 years ago

How about:

"A scalar multiplier used indicate how exposed each point is to indirect lighting. A value of 1.0 means full indirect lighting, and a value of 0.0 means that indirect lighting is completely occluded."

stevenvergenz commented 7 years ago

@emackey I think your description has the opposite meaning of the current description. This field describes the strength of the occlusion, not the strength of the light. Furthermore, the strength field has no direct effect on the lighting, it is only a piece of an occlusion map, so I don't think the word "light" should appear in its description.

Do you propose that we invert the values of strength fields, or is there still confusion somewhere?

McNopper commented 7 years ago

@stevenvergenz Your description is clearer for me. It would be great, if somewhere the formula does also appear:

occludedColor = mix(color, color * occlusionTexture, strength)

But we should all agree on this, as e.g. in substance painter they do not mix. There is "AmbiIntensity", which does strengthen/weaken the occlusion texture.

From my point of view, I do not care, which ambient occlusion formula is used. In both cases, it is an artistic value. But it has to be defined, which one it is.

bghgary commented 7 years ago

The strength value is supposed to represent how strong the occlusion is. The formula for occlusion should be:

occlusion = (1 - occlusionStrength * (1 - sampledOcclusionValue))

We will add this formula to the description.

McNopper commented 7 years ago

See #885 Disagree on this, as this is too much bound to Unity.

McNopper commented 7 years ago

Please compare AO at page 18: https://www.allegorithmic.com/system/files/software/download/build/PBR_volume_02_rev05.pdf

stevenvergenz commented 7 years ago

When omitted, the strength value defaults to 1.0, which is the exact same behavior as Unreal does. What's the harm in supporting both types?

McNopper commented 7 years ago

Please also read #885

Unreal Engine 4 has a node based Material system, where the output has a dedicated AO input parameter: see https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/MaterialInputs/index.html "Ambient Occlusion

Ambient Occlusion is used to help simulate the self-shadowing that happens within crevices of a surface. Generally, this input will be connected to an AO map of some type, which is often created within 3D modeling packages such as Maya, 3ds Max, or ZBrush."

grafik

The AO image is directly connected to the AO input parameter. If an artist wants to tweak this, he/she can create the functionality from the nodes.

So, I recommend not to use this parameter at all. Just provide the the AO map. Give the freedom to the artists and its tools, to tweak the AO map how they want.

If the parameter "strength" is inside glTF, it has to have an exact meaning. Otherwise content will look differently. It is like opening a PNG file with GIMP or PhotoShop, and the output is slightly different.

I already suggested to make these factors all as extensions, if someone really needs it (what I understand). But please, please, do not put it in core.

McNopper commented 7 years ago

If we take the strength, we should choose one of these formulas:

  1. occludedColor = color sampledOcclusionValue occlusionStrength
  2. occludedColor = color (1 - occlusionStrength (1 - sampledOcclusionValue))
  3. occludedColor = mix(color, color * occlusionTexture, occlusionStrength)
bghgary commented 7 years ago

I think 2 and 3 are the same thing. Will post my math in a minute.

bghgary commented 7 years ago
  1. occludedColor = color (1 - occlusionStrength (1 - sampledOcclusionValue)) occludedColor = color (1 - occlusionStrength + sampledOcclusionValue occlusionStrength)

  2. occludedColor = mix(color, color sampledOcclusionValue, occlusionStrength) occludedColor = color (1 - occlusionStrength) + color sampledOcclusionValue occlusionStrength occludedColor = color (1 - occlusionStrength + sampledOcclusionValue occlusionStrength)

McNopper commented 7 years ago

So it is either multiply or mix.

bghgary commented 7 years ago

My vote is mix. If we end up with multiply, it should not be called occlusion strength.

McNopper commented 7 years ago

Mix is okay for me as well.

stevenvergenz commented 7 years ago

+1 for mix.

McNopper commented 7 years ago

Let's do mix and any further discussion can be found here about factors #885