Exporters (add-ons and compiled) need to be updated to support new fully dynamic material assignment possible from Geometry Nodes #96721

Open
opened 2022-03-23 02:23:53 +01:00 by Colin Knueppel · 18 comments

Blender Version
Broken: version: 3.1.0, branch: master, commit date: 2022-03-08 18:16, hash: blender/blender@c77597cd0e
Worked: Uncertain

Short description of error
The apply modifiers doesn't work properly with geonodes in the instance of combining two geos with two separate materials. The combine object will only have one material assigned. However, if you apply the modifier and then export, the reimport will look correct with multiple materials.

Exact steps for others to reproduce the error

  1. Set the material color on the default cube

  2. Duplicate the default cube, create a new material on it and change its color.

  3. Select the original and create geometry node network.
    3a. Add a object info node and select the duplicate cube.
    3b. Offset the object info geometry with a Transform geometry node with translation xyz vals.
    3c. Join Geometry the original geometry and the transformed object info.
    3d. Hide original duplicate cube.

  4. Select geonodes cubes and export with export selected and apply modifiers to an fbx. (or gltf2)

  5. Reimport into scene and observe the single material on the imported object (the bug)

  6. Select the geonodes cubes, apply the modifier, export it and reimport it. Observe two materials on the imported geo (the way it should work if apply modifiers was working correctly).

Test File:
#96721.blend


Confirmed formats with the issue currently (there are most likely more):

Formats which exporters are already working fine with this new material assignment behavior:

    • OBJ - existing python add-on
**Blender Version** Broken: version: 3.1.0, branch: master, commit date: 2022-03-08 18:16, hash: `blender/blender@c77597cd0e` Worked: Uncertain **Short description of error** The apply modifiers doesn't work properly with geonodes in the instance of combining two geos with two separate materials. The combine object will only have one material assigned. However, if you apply the modifier and then export, the reimport will look correct with multiple materials. **Exact steps for others to reproduce the error** 1. Set the material color on the default cube 2. Duplicate the default cube, create a new material on it and change its color. 3. Select the original and create geometry node network. 3a. Add a object info node and select the duplicate cube. 3b. Offset the object info geometry with a Transform geometry node with translation xyz vals. 3c. Join Geometry the original geometry and the transformed object info. 3d. Hide original duplicate cube. 4. Select geonodes cubes and export with export selected and apply modifiers to an fbx. (or gltf2) 5. Reimport into scene and observe the single material on the imported object (the bug) 6. Select the geonodes cubes, apply the modifier, export it and reimport it. Observe two materials on the imported geo (the way it should work if apply modifiers was working correctly). Test File: [#96721.blend](https://archive.blender.org/developer/F12940802/T96721.blend) --------------- Confirmed formats with the issue currently (there are most likely more): * - [ ] USD * - [x] FBX 893100d8e3. * - [x] glTF blender/blender-addons@8b57a74629333852f3f7cbbafee63d747ff0c989 * - [x] OBJ - new C++ exporter blender/blender@d3eef4d22a Formats which exporters are already working fine with this new material assignment behavior: * - [x] OBJ - existing python add-on
Author

Added subscriber: @Colin_Knu

Added subscriber: @Colin_Knu
Member

Added subscriber: @PratikPB2123

Added subscriber: @PratikPB2123
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'

Added subscriber: @dfelinto

Added subscriber: @dfelinto

I can reproduce the bug and it also happens with GLTF2.

I can reproduce the bug and it also happens with GLTF2.

Added subscriber: @mont29

Added subscriber: @mont29

Materials have always been handled as 'fixed' info available from the object/obdata, they were never really 'editable' by the modifier stack, at least not beyond re-assigning different material indices (i.e. shuffling around assignment of materials defined 'statically' in the object's material slots.

Now geometry nodes can add random materials in a fully dynamic way, that are totally unknown from original object/obdata. So all export code (add-ons, but also most likely all our shiny brand new C++-implemented formats) will have to undergo (sometimes significant) changes to support this new behavior.

Materials have always been handled as 'fixed' info available from the object/obdata, they were never really 'editable' by the modifier stack, at least not beyond re-assigning different material indices (i.e. shuffling around assignment of materials defined 'statically' in the object's material slots. Now geometry nodes can add random materials in a fully dynamic way, that are totally unknown from original object/obdata. So all export code (add-ons, but also most likely all our shiny brand new C++-implemented formats) will have to undergo (sometimes significant) changes to support this new behavior.
Bastien Montagne changed title from Apply modifier on export breaks geonodes materials to Exporters (add-ons and compiled) need to be updated to support new fully dynamic material assignment possible from Geometry Nodes 2022-05-13 15:24:50 +02:00

Added subscriber: @scurest

Added subscriber: @scurest

So what's the correct way to fetch materials now? The old way was to read ob.material_slots- [x].material.

So what's the correct way to fetch materials now? The old way was to read `ob.material_slots- [x].material`.

I am not sure yet, I would hope that doing that on evaluated objects should give you the 'final' list of materials... But this needs to be investigated. Also need to check OBJ to understand why it's working there.

I am not sure yet, I would hope that doing that on *evaluated* objects should give you the 'final' list of materials... But this needs to be investigated. Also need to check OBJ to understand why it's working there.

This is what the Python OBJ exporter does to get the materials

import bpy

ob = bpy.context.object
depsgraph = bpy.context.evaluated_depsgraph_get()
apply_modifiers = True

ob_for_convert = ob.evaluated_get(depsgraph) if apply_modifiers else ob.original
me = ob_for_convert.to_mesh()
print(me.materials[:])

However, I notice that this does not handle materials that are overridden at the object level (material_slots- [x].link == 'OBJECT').

This is what the Python OBJ exporter does to get the materials ``` import bpy ob = bpy.context.object depsgraph = bpy.context.evaluated_depsgraph_get() apply_modifiers = True ob_for_convert = ob.evaluated_get(depsgraph) if apply_modifiers else ob.original me = ob_for_convert.to_mesh() print(me.materials[:]) ``` However, I notice that this does not handle materials that are overridden at the object level (`material_slots- [x].link == 'OBJECT'`).
Member

Added subscriber: @JulienDuroure

Added subscriber: @JulienDuroure

Added subscriber: @aras_p

Added subscriber: @aras_p

Looking at the codebase, Collada is also likely to be affected (it uses BKE_object_material_get everywhere)

Looking at the codebase, Collada is also likely to be affected (it uses `BKE_object_material_get` everywhere)

@aras_p indeed, that's why I tagged the #collada project ;)

@aras_p indeed, that's why I tagged the #collada project ;)

This issue was referenced by blender/blender@d3eef4d22a

This issue was referenced by blender/blender@d3eef4d22a021bf71c5e6cac492139cab397e4d2
Member

Hello,
Any update on how this should be handled for python add exporters?

Hello, Any update on how this should be handled for python add exporters?

I believe this works for Python

import bpy

def object_get_materials(ob, data):
    materials = []
    count = len(data.materials) if hasattr(data, "materials") else 0

    for i in range(count):
        # Check if overwritten by object
        if i < len(ob.material_slots):
            slot = ob.material_slots[i]
            if slot.link == 'OBJECT' and slot.material:
                materials.append(slot.material)
                continue

        # Otherwise use object data
        materials.append(data.materials[i])

    return materials

# Example usage
apply_modifiers = True
ob = bpy.context.object
depsgraph = bpy.context.evaluated_depsgraph_get()
ob_for_convert = ob.evaluated_get(depsgraph) if apply_modifiers else ob.original
mesh = ob_for_convert.to_mesh()
print(object_get_materials(ob, mesh))

which is basically just a Python port of BKE_object_material_get_eval.

I believe this works for Python ``` import bpy def object_get_materials(ob, data): materials = [] count = len(data.materials) if hasattr(data, "materials") else 0 for i in range(count): # Check if overwritten by object if i < len(ob.material_slots): slot = ob.material_slots[i] if slot.link == 'OBJECT' and slot.material: materials.append(slot.material) continue # Otherwise use object data materials.append(data.materials[i]) return materials # Example usage apply_modifiers = True ob = bpy.context.object depsgraph = bpy.context.evaluated_depsgraph_get() ob_for_convert = ob.evaluated_get(depsgraph) if apply_modifiers else ob.original mesh = ob_for_convert.to_mesh() print(object_get_materials(ob, mesh)) ``` which is basically just a Python port of [BKE_object_material_get_eval](https://github.com/blender/blender/blob/e22628c70bf221acf084e20373da9d40ebc2bfa8/source/blender/blenkernel/intern/material.c#L716).
Sign in to join this conversation.
No Milestone
No project
No Assignees
8 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#96721
No description provided.