mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.51k stars 35.37k forks source link

Support for MTL map_Ns (shininess map) #9339

Closed daveo1001 closed 4 years ago

daveo1001 commented 8 years ago

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
mrdoob commented 8 years ago

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

WestLangley commented 8 years ago

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.

bhouston commented 8 years ago

I thought shininess is here: https://github.com/mrdoob/three.js/blob/master/src/materials/MeshPhongMaterial.js#L59

And also here: https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl#L32

So I think it is supported.

bhouston commented 8 years ago

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.

WestLangley commented 8 years ago

@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.

mrdoob commented 8 years ago

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.

👍

bhouston commented 8 years ago

@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.

bhouston commented 8 years ago

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

WestLangley commented 8 years ago

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

bhouston commented 8 years ago

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

daveo1001 commented 8 years ago

@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!

WestLangley commented 7 years ago

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.

pailhead commented 7 years ago
#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?

donmccurdy commented 7 years ago

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

donmccurdy commented 7 years ago

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?

bhouston commented 7 years ago

@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.

WestLangley commented 7 years ago

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.

bhouston commented 7 years ago

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.

donmccurdy commented 7 years ago

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. 😬

WestLangley commented 6 years ago

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.

WestLangley commented 6 years ago

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.

bhouston commented 6 years ago

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.

Mugen87 commented 4 years ago

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