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

[glTF] How to support Specular-Glossiness in Three.js #10985

Closed
3 of 12 tasks
takahirox opened this issue Mar 11, 2017 · 5 comments
Closed
3 of 12 tasks

[glTF] How to support Specular-Glossiness in Three.js #10985

takahirox opened this issue Mar 11, 2017 · 5 comments

Comments

@takahirox
Copy link
Collaborator

takahirox commented Mar 11, 2017

Description of the problem

In glTF 2.0 specification, there're two pbr workflows.
Roughness/Metallic and Specular/Glossiness

Roughness/Metallic
https://github.com/sbtron/glTF/blob/30de0b365d1566b1bbd8b9c140f9e995d3203226/specification/2.0/README.md#metallic-roughness-material

Specular/Glossiness (extension)
https://github.com/sbtron/glTF/tree/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness

Currently MeshStandardMaterial fits to Roughness/Metalic, but no material for Specular/Glossiness.

I'm considering how to support Spacular/Glossiness.

They use the following properties respectively.

Roughness/Metallic

  • roughness (float)
  • roughnessMap (texture)
  • metalness (float)
  • metalnessMap (texture)

Fragment shader

float roughnessFactor = roughness;
roughnessFactor *= texture2D( roughnessMap, vUv ).g;
float metalnessFactor = metalness;
metalnessFactor *= texture2D( metalnessMap, vUv ).b;
PhysicalMaterial material;
material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );
material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );
material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ),
                              diffuseColor.rgb, metalnessFactor );

Specular/Glossiness

  • specular (vec3)
  • specularMap (texture)
  • glossiness (float)
  • glossinessMap (float)

Fragment shader

vec3 specularFactor = specular;
specularFactor *= texture2D( specular2Map, vUv ).rgb;
float glossinessFactor = glossiness;
glossinessFactor *= texture2D( glossinessMap, vUv ).a;
PhysicalMaterial material;
material.diffuseColor = diffuseColor.rgb * ( 1.0 -
                          max( max( specularFactor.r, specularFactor.g ), specularFactor.b ) );
material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );
material.specularColor = specularFactor.rgb;

Reference https://github.com/sbtron/glTF/blob/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows/index.html

So, Specular-Glossiness can be implemented by partially replacing properties and fragment shader of MeshStandardMaterial.

To achieve this, I have three options in my mind.

  1. Add specular/glossiness properties to MeshStandardMaterial (add a property to switch shader code, like material.specularGlossiness = boolean?). PROS: relatively small change in Three.js core, CONS: dirty design?
  2. Add a new material for Specular/Glossiness. (Make basement MeshStandardMaterial and two materials, one for Roughness/Metallic and another one for Specular/Glossiness, inherit it?). PROS clear design, CONS: relatively big change in Three.js core
  3. GLTF2Loader uses (Raw)ShaderMaterial. PROS: no change in Three.js core, CONS: only GLTF2Loader can use Specular/Glossiness

I prefer 2.
Any thoughts?

BTW if there's existing threads where you folks discussed it, let me know.

Three.js version
  • Dev
  • r84
  • ...
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • Linux
  • Android
  • IOS
Hardware Requirements (graphics card, VR Device, ...)
@takahirox
Copy link
Collaborator Author

/cc @donmccurdy

@takahirox
Copy link
Collaborator Author

/cc @WestLangley

@WestLangley
Copy link
Collaborator

The short answers is yes, this is doable.

One thing about the metalness-roughness nomenclature is it is absolutely clear what these terms mean.

Also, the two concepts are separable; you can have a non-rough metal and a rough non-metal.

This is one reason we selected the metalness-roughness API for MeshStandardMaterial.

The specular-glossiness nomenclature is not so clear for novice users. Although I understand that specular is the specular reflectance of the material, I have no idea what glossiness is. According to the glTF spec, glossiness = 1 - roughness, so we can go with that.

//

Given glTF aims to be a de-facto standard, however, and given there is a proposal to support specular-glossiness workflow as an extension, it seems reasonable that three.js should support it, too.

Note that MeshStandardMaterial does not have a metalness-roughness illumination model; it has a metalness-roughness API. The illumination model itself has diffuse, specular, and roughness parameters internally.

So, if we want the option to input glossiness, glossinessMap, specular, and specularMap instead of metalness, metalnessMap, roughness, and roughnessMap , that is an easy change:

vec3 specularColor = specular;
specularColor *= texture2D( specularMap, vUv ).rgb;

float glossinessFactor = glossiness;
glossinessFactor *= texture2D( glossinessMap, vUv ).a;

PhysicalMaterial material;

material.diffuseColor = diffuseColor.rgb;

material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );

material.specularColor = specularColor.rgb;

Notice, there is no reason to "convert" from one API to the other.

//

As far as the API is concerned, I would prefer to leave MeshStandardMaterial as-is, and introduce MeshStandardMaterialSG, which would remove the roughness/metalness parameters and add

material.specular (THREE.Color)
material.specularMap (RGB channesl of RGBA texture)
material.glossiness (float, in [0,1])
material.glossinessMap (Alpha channel of RGBA texture)

I can implement this if there is agreement.

@takahirox
Copy link
Collaborator Author

Thanks for the comment.
Do you mind if I try to implement?
Because I already started in my local branch and want to study PBR.

BTW wouldn't material.diffuseColor be

material.diffuseColor = diffuseColor.rgb * ( 1.0 -
                      max( max( specularFactor.r, specularFactor.g ), specularFactor.b ) );

?

https://github.com/sbtron/glTF/blob/KHRpbrSpecGloss/extensions/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows/index.html#L57-L58

@WestLangley
Copy link
Collaborator

Do you mind if I try to implement?

Feel free!

I see no reason why the artist-specified diffuse reflectance of the material (color) should be modified in such a way.

We are not converting between workflows here.

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

No branches or pull requests

2 participants