Three.js: Support for MTL map_Ns (shininess map)

Created on 15 Jul 2016  ·  23Comments  ·  Source: mrdoob/three.js

Currently/To the best of my knowledge the only shininess setting for phong material is shininess (mtl Ns) but mtl supports a shininess map (map_Ns). I'm sure it's a pretty big deal but I'd be eternally grateful if this feature was added.

Three.js version
  • [x] Dev
  • [x] r79
  • [ ] ...

    Browser
  • [x] All of them

  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer

    OS
  • [x] All of them

  • [ ] Windows
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
Enhancement

Most helpful comment

@WestLangley wrote:

@bhouston Our implementation of MeshPhongMaterial is not a physically correct model in any respect.

The ThreeJS implementation of BlinnPhong is not physically correct, that is true. Other renders do have much more physically correct implementations -- V-Ray and PRMan have really good implementations of BlinnPhong that are essentially as physically correct as MeshSTandardMAterial/MeshPhysicalMaterial -- they differ only in terms of parameterization.

The reason why ThreeJS's MeshPhongMaterial are so bad is because of three issues with our implementation:

(1) We are not energy conserving. Energy reflected by specular layer should not be made available to the diffuse layer. If specular is 1, 1, 1 (which means the surface is metallic and fully reflective) then the light getting to the diffuse layer should be 0,0,0. (This energy conservation is part of MeshStandardMaterial in the way that increasing metalness reduces the intensity of the diffuse layer.)

(2) ShininessMap should modulate shininess.

(3) SpecularMap should be a color map that modulates specularColor.

This would be useful to have right because then ThreeJS can load MTL, FBX and other BlinnPhong model using files with as full fidelity as other professional rendering packages.

All 23 comments

We do not support shininess material on MeshPhongMaterial. We could considering adding it though.

MeshPhongMaterial.specularMap, which takes values in [ 0, 1 ], attenuates the specular component on a per-pixel-basis. When using it, you may have to set a fairly high MeshPhongMaterial.shininess value to begin with.

Perhaps that is a work-around for you.

Ah, I see the issue, "material.specularStrength" is applied to the whole of the Phong Specular BRDF instead of just applied to the shininess parameter. I'd suggest that we replace specularStrengthn with shinininessMap that modulates the shininess instead. I think that is actually much more useful and more physically correct.

@bhouston Our implementation of MeshPhongMaterial is not a physically correct model in any respect. Personally, I do not think it matters. I would focus on the physical materials, instead.

But if you want to change the model, I would not oppose. The thing to do would be to add shininessMap, which would be modulated by shininess. Leave specularMap, alone for backward-compatibility or remove it.

But if you want to change the model, I would not oppose. The thing to do would be to add shininessMap, which would be modulated by shininess. Leave specularMap, alone for backward-compatibility or remove it.

👍

@WestLangley wrote:

@bhouston Our implementation of MeshPhongMaterial is not a physically correct model in any respect.

The ThreeJS implementation of BlinnPhong is not physically correct, that is true. Other renders do have much more physically correct implementations -- V-Ray and PRMan have really good implementations of BlinnPhong that are essentially as physically correct as MeshSTandardMAterial/MeshPhysicalMaterial -- they differ only in terms of parameterization.

The reason why ThreeJS's MeshPhongMaterial are so bad is because of three issues with our implementation:

(1) We are not energy conserving. Energy reflected by specular layer should not be made available to the diffuse layer. If specular is 1, 1, 1 (which means the surface is metallic and fully reflective) then the light getting to the diffuse layer should be 0,0,0. (This energy conservation is part of MeshStandardMaterial in the way that increasing metalness reduces the intensity of the diffuse layer.)

(2) ShininessMap should modulate shininess.

(3) SpecularMap should be a color map that modulates specularColor.

This would be useful to have right because then ThreeJS can load MTL, FBX and other BlinnPhong model using files with as full fidelity as other professional rendering packages.

Just as a point of reference in defense of properly implemented Blinn-Phong, V-Ray uses Blinn-Phong almost exclusively and its stuff looks amazing:

https://www.google.ca/search?q=v-ray+architecture&source=lnms&tbm=isch

@bhouston I agree, your suggestions make perfect sense. I wonder why it wasn't implemented that way in the first place...

There was a previous attempt to implement energy conservation in BlinnPhong -- I think it was relatively correct as it followed roughly how professional renderers do it. It is important to note that one doesn't have to use a Fresnel term in the energy conservation as it isn't done this way in Standard/Physical either when blending towards metallic just linearly decreases available light at the diffuse layer.

https://github.com/mrdoob/three.js/pull/7324/commits/b10172933174870821f776fe9be30b3c46fd3b80#diff-3d33ad8ea54d86cc060ca7b09c39d896R11

@mrdoob I didn't think so. I would like it very much if you did consider it.
@WestLangley I'm already using the specular.map and it is enough to get by with what I'm doing but having a map for shininess to go with it would really make my day.
@bhouston you're way smarter than me. keep it up!

This is turning out to be an enormous change. Here is some code for reference.

float specularStrength;
#ifdef USE_SPECULARMAP
    vec4 texelSpecular = texture2D( specularMap, vUv );
    specularStrength = texelSpecular.r;
#else
    specularStrength = 1.0;
#endif

#ifdef ENVMAP_BLENDING_MULTIPLY
    outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );
#elif defined( ENVMAP_BLENDING_MIX )
    outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );
#elif defined( ENVMAP_BLENDING_ADD )
    outgoingLight += envColor.xyz * specularStrength * reflectivity;
#endif

Objective

  1. Use specularMap to modulate MeshPhongMaterial.specular, assume specularMap is RGB-valued, not grayscale. (easy)
  2. Add shininessMap to modulate MeshPhongMaterial.shininess. shininessMap is grayscale. (also easy)

Consequences

  1. The leaves no per-pixel map to modulate reflectivity. We could add a reflectivityMap, too, but the ENVMAP_BLENDING modes are such a hack, I hate to go down that path. Why create such hacks when we have MeshStandard/PhysicalMaterial available?
  2. MeshBasicMaterial and MeshLambertMaterial support specularMap, and would either need to have that property renamed to reflectivityMap or -- my preference -- remove the support for per-pixel reflectivity from those two materials -- and MeshPhongMaterial, too, for that matter.
  3. Whatever we do, there are huge ramifications for the loaders.

Previously, we have wondered why we are supporting MeshPhongMaterial when we have the properly-designed MeshStandardMaterial to replace it. I think that is a good question.

#else
    specularStrength = 1.0;
#endif

should not be constant, as with other parameters there should be a float available to override the texture. If one has the ability to use a texture containing values in the 0-1 range, why is the alternative locked to 1? Why not 0, or .5346?

This feature is under consideration for the glTF 2.0 Blinn-Phong extension (see discussion), so I will be interested in what is decided here as well. It was mentioned by @bhouston that our MeshPhong model is spec-gloss — is it possible to implement this with the PBR spec-gloss material already checked into GLTF2Loader?

/cc @takahirox

Previously, we have wondered why we are supporting MeshPhongMaterial when we have the properly-designed MeshStandardMaterial to replace it. I think that is a good question.

IMO, there is still need for more performance-tuned materials on mobile devices e.g. Cardboard/Daydream/GearVR.

The leaves no per-pixel map to modulate reflectivity. We could add a reflectivityMap, too, but the ENVMAP_BLENDING modes are such a hack, I hate to go down that path. Why create such hacks when we have MeshStandard/PhysicalMaterial available?

I don't think I follow... Is there something about this proposal that makes reflectivityMap necessary? Or are you mentioning it to round out remaining foo/fooMap pairs?

@donmccurdy The implementation of "BlinnPhong" in Three.JS is fairly wrong compared to the correct implementation in V-Ray and other top quality renderers. I describe the real issues here and how to address them:

https://github.com/mrdoob/three.js/issues/9339#issuecomment-233160823

My recommendations are not that hard to implement and but it is a breaking change for a bunch of people who are already suing the incorrect BlinnPhong.

IMO, there is still need for more performance-tuned materials on mobile devices

I don't expect Phong will suffice for that purpose.

I don't think I follow... Is there something about this proposal that makes reflectivityMap necessary? Or are you mentioning it to round out remaining foo/fooMap pairs?

What we are currently calling specularMap would be changed from a single-channel map to a 3-channel map used for a different purpose. So, we either have to remove the current specular map functionality completely (from Basic and Lambert) or rename the former specularMap to something else -- like reflectivityMap.

I mentioned it because these are breaking changes.

IMO, there is still need for more performance-tuned materials on mobile devices

Properly implemented BlinnPhong should be computationally equivalent to properly implemented Physical materials within some small margin of error.

I don't expect Phong will suffice for that purpose.

Properly implemented BlinnPhong should be computationally equivalent to properly implemented Physical materials within some small margin of error.

Thanks @WestLangley @bhouston! In that case I don't have an opinion about maintaining MeshPhongMaterial alongside MeshStandardMaterial. Unlit shading is probably what I need to be looking at; I'd like to get that definition updated for glTF2.0. I will retire from this thread. 😬

For the record, I implemented .shininessMap for MeshPhongMaterial and ultimately abandoned it. It was difficult for me to get predictable results modulating .shininess with a per-pixel map.

The primary reason is .shininess is unbounded, and not a measure of "perceptual shininess". Hot spots are often over-bright to begin with, and modulating shininess can still result in an over-bright hot spot, with little perceptible visual difference. MeshStandardMaterial has a much better parameterization; .roughness is, in fact, "perceptual roughness".

Regarding an RGB.specularMap, I now see little benefit to adding this. Such a feature may be useful in modeling metals, but MeshPhongMaterial does not do a good job of representing metals, anyway. MeshStandardMaterial, on the other hand, does. Consequently, I have abandoned adding an RGB .specularMap to MeshPhongMaterial.

My recommendation at this point is to leave MeshPhongMaterial as-is. Sophisticated users can use MeshStandardMaterial.

I still would be in favor of renaming the current grayscale .specularMap to .reflectivityMap, as it modulates the .reflectivity property in the MeshBasic/Lambert/Phong materials.

Note, we use the property .specularMap elsewhere. An RGB .specularMap is used in the glTF Specular-Glossiness extension, where it modulates .specular, the specular reflectance of the material.

I would suggest studying V-Ray, Blender's Cycles and Unity to figure out what they do and then take the average solution in terms of how things are modulated and what things are called.

This would achieve the most compatibility possible as these are the tools that I think have the most widely accepted Blinn-Phong shading models.

Closing in favor of #7290 which tracks the mentioned changes to specularMap and reflectivityMap.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

akshaysrin picture akshaysrin  ·  3Comments

seep picture seep  ·  3Comments

danieljack picture danieljack  ·  3Comments

Horray picture Horray  ·  3Comments

boyravikumar picture boyravikumar  ·  3Comments