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

Blender/GLTF material "specular" attribute is ignored #83320

Open
lorddevereux opened this issue Oct 14, 2023 · 12 comments
Open

Blender/GLTF material "specular" attribute is ignored #83320

lorddevereux opened this issue Oct 14, 2023 · 12 comments

Comments

@lorddevereux
Copy link

Godot version

4.1.1 stable

System information

Linux Mint 21, AMDGPU, Forward+

Issue description

When using automatic Blender import (or GLB/GLTF export from Blender and import into Godot), material specular values are ignored and set to a default of 0.5.

This issue is also referenced in godotengine/collada-exporter#57 and I can confirm that this issue still exists in Godot 4.1.1.

When using a large set of models imported from Blender, the only sensible way around this issue is to script every object load to correct the materials manually, which is quite annoying, or be stuck with the sheen on every object.

Steps to reproduce

  1. Create any model in Blender which has a material "Specular" set to any value other than 0.5
  2. Add the Blender file to a Godot project and open it for viewing
  3. The object will have its material Metallic > Specular set to 0.5

Minimal reproduction project

N/A

@4CoDev
Copy link

4CoDev commented Feb 27, 2024

Is there any progress on fixing this problem?

@clayjohn
Copy link
Member

This should be an easy first issue to tackle, here is where we set metallic in the GLTF importer:

if (mr.has("metallicFactor")) {
material->set_metallic(mr["metallicFactor"]);
} else {
material->set_metallic(1.0);
}

As you can see, we never touch specular. So an interested contributor just needs to check what the name of the specular component and then parse it the same as we do metallic.

@cosparks
Copy link
Contributor

cosparks commented Feb 28, 2024

@lorddevereux @4CoDev which blender material properties do you want to be interpreted as metallic specular values in godot's material settings? Blender's principled BSDF material has a few different params for specular settings (IOR, tint, etc.) but I haven't seen just a single specular or metallic/specular value.

It would be useful to you provided an example material or gltf file and its expected specular value in godot.

According to this documentation, gltf format doesn't have specular values under pbrMetallicRoughness, but a specular value could be computed from KHR_material_specular and KHR_material_ior extensions.

@lorddevereux
Copy link
Author

lorddevereux commented Mar 3, 2024

Thanks for the pointers folks, I'll have a look and see what might work best. I was looking at using this Specular value, as it seems to best represent the effect that would be caused by Specular in Godot

image

@Scarface1809
Copy link

I managed to create a simple 3D scene to try and recreate the issue, and I can confirm that when you change the specular value in blender, the value does not change in godot.

@lorddevereux
Copy link
Author

lorddevereux commented Mar 3, 2024

I think I can see why this wasn't implemented originally, it's not a straightforward read of a property.

The Blender GLTF exporter doesn't export that Specular value. Instead, it converts the Blender Specular properties (IOR/Specular and specular tint. See this (referred to in the gltf exporter code) https://gist.github.com/proog128/d627c692a6bbe584d66789a5a6437a33

I think the best way to implement this is to mirror the logic that is used in the Blender gltf IMPORTER to convert gltf material properties back to Blender Specular properties, but implemented in the Godot gltf importer.

I'll admit to being far from an expert in graphics terms but I could implement it so that Blender specular value became the Godot specular value. That would be a start

@cosparks
Copy link
Contributor

cosparks commented Mar 3, 2024

I was looking at using this Specular value, as it seems to best represent the effect that would be caused by Specular in Godot

It looks like you're using blender 3.0. In blender 4.0, they've removed that specular property and added a number of fields for specularity which can be used to augment the base IOR. Below is a screenshot of some of the properties of the new principled BSDF material in blender 4.0

I don't have blender 3.0 installed. Could you have a look at the GLTF export to see what that specular value maps to? I'm assuming godot should still properly import blender 3 materials, and for blender 4 materials it might be worth looking into using the ior to compute an appropriate specular value.

edit: good to know that that specular value isn't being exported. I think the ior/specular and specular tint will show up in the gltf file as the KHR material extensions that I mentioned above.

@lorddevereux
Copy link
Author

lorddevereux commented Mar 4, 2024

I've done some experimentation and it seems that the KHR material extensions section only gets generated if there is only 1 material present in the model. As soon as you add a second material, it is no longer generated and changes to the specular value in Blender do not result in any changes to the GLTF. Therefore, it would be impossible to support Specular in Blender 3.6 for a model with more than one material without modifying the gltf exporter.

edit 1: but you are right, the when there is only one material then the specular value does get mapped indirectly into values in KHR material extensions

I am downloading 4.0 and will look into what gets generated there.

edit 2: in blender 4.0 the exporter generates a KHR section per material, so I can work with that. It seems the "IOR Level" field under Specular maps to what older versions of blender just had labelled as "Specular".

edit 3: it seems, according to the GLTF spec, that "KHR_materials_specular" replaces the archived "KHR_materials_pbrSpecularGlossiness" item (which Godot does have support for). See the KHR_materials_specular documentation.

edit 4: this works. If the specular value is set higher than 0.5 it will be stored as specularColorFactor, less than 0.5 will be stored as specularFactor as long as the tint is RGB (1,1,1). As the comment notes - if the specular Tint (in Blender) is set to something other than 1,1,1 (white) then it will import wrong. The GLTF format stores colorFactor as an RGB value for which each channel is effectively:
specular_tint.r * 2.0 * specular_factor.
With 2 unknowns it's impossible to get that back to a factor and a tint
image

In an ideal world, I think the specular tint would have an effect on the albedo colour of the material in Godot (which is loaded always as RGB 1,1,1 if a texture is applied to the material). As I say, I'm far from a CG expert, but to me Specular Tint in Blender seems to have a similar effect to Albedo colour in Godot.

If no-one has any strong objections I can PR this patch.

@clayjohn
Copy link
Member

clayjohn commented Mar 4, 2024

@lorddevereux I took a quick look at the Blender Principled BRDF docs https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/principled.html

I don't think Godot supports anything close to "specular tint". Specular tint is meant to only modify the specular reflections and not diffuse. Albedo is always used for both. So tinting albedo with "specular tint" will result in wrong results.

That being said, it seems like what blender is calling "IOR level" is exactly what we call "specular".

What we call "specular" is unrelated to the old "specular/glossiness" workflow, its just a coincidence in naming.

Since we don't support specular tint, we should just ignore the specularColorFactor and specularColorTexture for now

Accordingly, I think you can probably just simplify the code you have in your last message to only contain the specularFactor part. Unless I am misunderstanding something about what Blender does?

@lorddevereux
Copy link
Author

Makes sense on the colour tint, I will leave that alone.

The GLTF exporter is a bit weird (on the face of it, I'm sure there's a reason):

  • It takes the "IOR Level" and multiplies it by 2.
  • If the result is less than 1.0, it will just store specularFactor
  • If the result is more than 1.0, OR the specular tint (in Blender) is set to something other than RGB(1.0,1.0,1.0), it will generate specularColorFactor instead with the maths: specularTint * IOR level.

This behaviour is why I added the comment in about the three components of specularColorFactor being the same, and why the Godot importer needs to handle specularColorFactor (otherwise IOR level > 0.5 would not be imported).

It's not ideal, but I think hands are tied here by the gltf spec.

@clayjohn
Copy link
Member

clayjohn commented Mar 5, 2024

@lorddevereux When the result is more than 1.0, does it store anything in specularFactor?

@lorddevereux
Copy link
Author

No, it does not create the specularFactor field at all in that case.

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

No branches or pull requests

7 participants