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

Importing .blend file results in Roughness texture being used as Metallic texture #82455

Closed
tobloef opened this issue Sep 27, 2023 · 10 comments · Fixed by #96782
Closed

Importing .blend file results in Roughness texture being used as Metallic texture #82455

tobloef opened this issue Sep 27, 2023 · 10 comments · Fixed by #96782

Comments

@tobloef
Copy link

tobloef commented Sep 27, 2023

Godot version

v4.1.1.stable.official [bd6af8e]

System information

Godot v4.1.1.stable - Windows 10.0.22621 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3070 (NVIDIA; 31.0.15.3713) - AMD Ryzen 7 5800X 8-Core Processor (16 Threads)

Issue description

When importing .blend files, the Roughness texture is used for both the Roughness and the Metallic properties of the imported material. I would expect the imported model to use the Metallic texture that was set up in Blender.

image

image

image

Steps to reproduce

In Blender (3.6.3):

  • Layout > Add > Mesh > Monkey
  • Shading > New
  • Create Metallic texture
    • Add > Texture > Image Texture
    • Connect Color to Metallic
    • Click New on the Image Texture and create image "Metallic"
    • Change the Image Texture's Color Space to Non-Color
    • Switch to Texture Paint and draw some shapes on the texture
  • Create Roughness texture
    • Similar to steps for Metallic
  • File > Save
  • File > External Data > Pack Resources

In Godot (4.1.1):

  • Create a new Forward+ project
  • Drag .blend file into FileSystem's "res://" folder.
  • Select it in the FileSystem, go to Import and click "ReImport"
    • Note: I had to do this in order to make the material have any textures at all. May be a separate bug.
  • Create a 3D Node
  • Drag .blend file from FileSystem to be a child of the 3D Node
  • Open the imported scene in the editor (Click "Open Anyway")
  • Inspect the mesh's surface material and observe that the Metallic and Roughness textures are both the Roughness texture that was created earlier.

Minimal reproduction project

Godot project: MetallicImportBugRepro_Godot.zip

Blender project: MetallicImportBugRepro_Blender.zip

@Calinou
Copy link
Member

Calinou commented Sep 27, 2023

Can you reproduce this when exporting a .gltf file and importing it in Godot? (Godot internally tells Blender to export a .gltf file.)

This may be a bug in Blender's glTF exporter, especially if you can't reproduce this with another tool that exports glTF files.

@tobloef
Copy link
Author

tobloef commented Sep 27, 2023

When exporting a .gltf file from Blender and importing it in Godot, I get a combined Metallic/Roughness texture file. This is loaded into the material correctly as the two textures are indeed the same file, just different channels.

image

I assume this "combine into one texture" behavior is the intention for the .blend import as well?

As an aside, I personally find it somewhat unintuitive that the textures are automatically combined instead of just using the two image textures I set up in Blender. I wonder, what's the reason for this being the default?

@Calinou
Copy link
Member

Calinou commented Sep 27, 2023

I assume this "combine into one texture" behavior is the intention for the .blend import as well?

Yes; I don't know why it's not happening when Godot imports a .blend file directly.

As an aside, I personally find it somewhat unintuitive that the textures are automatically combined instead of just using the two image textures I set up in Blender. I wonder, what's the reason for this being the default?

Using this approach results in better performance (fewer textures need to be used for the material), as you can use ORMMaterial3D instead of StandardMaterial3D. See also godotengine/godot-proposals#2955.

@tobloef
Copy link
Author

tobloef commented Sep 27, 2023

Using this approach results in better performance (fewer textures need to be used for the material), as you can use ORMMaterial3D instead of StandardMaterial3D. See also godotengine/godot-proposals#2955.

Makes sense. Do you know if it's possible to disable this behavior? I can't seem to find something like that in the import settings. If not, that's totally fine. It's not what this issue is about anyway 😅

Regarding the actual issue, if someone could point me to the right corner of the codebase I would also be happy to look into the issue myself.

@Calinou
Copy link
Member

Calinou commented Sep 27, 2023

Makes sense. Do you know if it's possible to disable this behavior?

Not that I know of.

Regarding the actual issue, if someone could point me to the right corner of the codebase I would also be happy to look into the issue myself.

The Blender importer code is here: https://github.com/godotengine/godot/blob/ec62b8a3ee1d731387a440b4d2abb7961aa28322/modules/gltf/editor/editor_import_blend_runner.cpp

As you can see, Godot executes Blender with a specific Python payload designed to make it export a glTF file.

@tobloef
Copy link
Author

tobloef commented Oct 1, 2023

I have been looking into this more over the weekend. This will be a somewhat long post with the details of my findings. I hope it can serve as a jumping-off point for any potential fixes.

Forgive me if some of this is obvious to veterans of the engine, I'm a very recent immigrant from the Unity fiasco. If you have corrections, please let me know!

Blender glTF export

Basic theory

Blender has 3 main modes of exporting gLTF files: Binary (.glb), Embedded (.gltf), and Separate (.gltf + .bin + textures).

Note that by default, whether using embedded textures or not, Blender will combine the Metallic and Roughness into the texture we previously talked about in this thread. It is possible to disable this behavior by toggling the Keep original option when using the Separate mode, but this does come with the following very relevant warning:

⚠️ If you use more than one texture, where PBR requires only one, only one texture will be used. This can lead to unexpected results.

Godot's settings

When importing a .blend file, Godot will behind the scenes call Blender and perform a gLTF export, just like Calinou said. This export uses the Separate mode, along with Keep original set to True.

To me, this explains the faulty behavior originally described in this issue. Godot seemingly assumes that the Metallic and Roughness textures will be combined, while explicitly telling Blender not to do that.

Testing different formats

So perhaps we can solve the issue by changing export settings. The table below shows the results of importing gLTF files manually exported from Blender, both for projects where the texture files have and have not been packed into the .blend file.

Packed Unpacked
Binary ✅ †
Embedded ✅ †
Separate ✅ ‡ ✅ ‡
Separate + Keep original

Legend

✅ Imported with Metallic and Roughness correctly assigned

❌ Imported with Metallic incorrectly assigned to the same texture file as Roughness

† If Godot's Embedded Image Handling is set to Extract Textures in the scene import settings, you will have to trigger a second import. Otherwise, the imported scene will error due to missing images. I believe this to be a bug.

‡ You of course have to import the exported textures and the .bin file alongside the .gltf file, as they are not embedded inside the project with this export setting.

Attempted fix by changing Godot's export settings

At this point, I thought the fix would be to simply change Godot's Blender export settings to one of the working formats from the table above. This can be easily done here:

parameters_map["export_keep_originals"] = true;
parameters_map["export_format"] = "GLTF_SEPARATE";

However, all approaches I tried had issues.

Separate and Embedded

For Separate and Embedded exports, the scene has no Metallic/Roughness textures assigned at all and Godot produces the following error:

🔴 Can't find file 'res://.godot/imported/Unpacked-ef043bcaf77b3602acfd1d86d08410e3_Metallic-Roughness.png'.
🔴 No loader found for resource: res://.godot/imported/Unpacked-ef043bcaf77b3602acfd1d86d08410e3_Metallic-Roughness.png (expected type: Texture2D)
🟡 modules/gltf/gltf_document.cpp:3233 - glTF: Image index '0' couldn't be loaded with the name: Metallic-Roughness. Skipping it.

After the import has run, .godot/imported will actually contain the combined Metallic/Roughness texture in question, but Godot will not import it due to it being in the .godot folder. I assume this is on purpose to prevent an infinite loop:

if (path[i].begins_with(".")) {
return false;
}

Additionally, if the Blender project is not packed and you import the textures as well, .godot/imported will also contain a combined Metallic-Roughness.png texture. Note that this will happen despite the export mode being Embedded. There will also be the following error in the log:

🔴 No loader found for resource: res://.godot/imported/Metallic-Roughness.png (expected type: )

Binary

For both packed and unpacked Blender files, the imported scene will completely fail and get a little ❌ icon. The following will be printed in the log:

🔴 modules/gltf/gltf_document.cpp:7580 - Condition "err != OK" is true. Returning: ERR_FILE_CANT_OPEN
🔴 Error importing 'res://Unpacked.blend'.

What now?

Barring abandoning the issue, I see two potential actions to take from here:

A) Make Godot support importing gLTF files with separate textures for Metallic and Roughness. This would help not only with gLTF support in general but also allow the existing Blender file importing to Just Work™.

B) Figure out what goes wrong when Godot uses other export settings in the Blender import process. With this, Godot would not have to concern itself with separate Metallic/Roughness textures, as they would be combined during the Blender export.

I'm not sure either of these fixes would be easy for me to execute, but I would be willing to take a look if we knew what approach we wanted to go with. I'm also very open to someone more experienced with the engine taking it from here.

If you've read all this, I thank you. I would love to hear what you think. Perhaps someone would be willing to see if they get similar results and that it's not just me messing something up.

Cheers ✌️

@scurest
Copy link
Contributor

scurest commented Oct 10, 2023

glTF does not support separate textures for metal and roughness, they have to be combined into one texture. (Same for base color and alpha.)

@tobloef
Copy link
Author

tobloef commented Oct 11, 2023

glTF does not support separate textures for metal and roughness, they have to be combined into one texture. (Same for base color and alpha.)

Makes sense. So something like approach B from my previous post (quoted below) would be the way to go?

B) Figure out what goes wrong when Godot uses other export settings in the Blender import process. With this, Godot would not have to concern itself with separate Metallic/Roughness textures, as they would be combined during the Blender export.

(I've updated the wording in the wording slightly, to not emphasize using Binary mode for the export)

@aaronfranke
Copy link
Member

@tobloef As an aside, I personally find it somewhat unintuitive that the textures are automatically combined instead of just using the two image textures I set up in Blender. I wonder, what's the reason for this being the default?

This happens because glTF does not support specifying different textures for metallic as roughness, it specifies only a metallicRoughnessTexture for both: https://github.com/KhronosGroup/glTF/blob/main/specification/2.0/schema/material.pbrMetallicRoughness.schema.json#L43 Therefore, "A) Make Godot support importing gLTF files with separate textures for Metallic and Roughness" is not possible. ...uh, sorry, I missed the last part of the discussion where this was mentioned already, but I'll keep this text around instead of deleting it in case the details and link helps.

Anyway, it seems that Blender does not have a way to "unpack" the converted roughness+metallic texture. I've made two PRs to fix this problem: #96778 and #96782. However, note that you will need to uncheck this box:

Screenshot 2024-09-10 at 2 32 47 AM

@etherealxx
Copy link
Contributor

Reproducible in Godot v4.3.stable and Blender 4.1.1/4.2.2
Here's the model i use to test:
The Cartoon Knight_anim.zip

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

Successfully merging a pull request may close this issue.

7 participants