DLR-RM / BlenderProc

A procedural Blender pipeline for photorealistic training image generation
GNU General Public License v3.0
2.7k stars 441 forks source link

Render Roughness Metallic or others #1105

Open zsy1987 opened 2 months ago

zsy1987 commented 2 months ago

Describe the issue

Hey, I want to render roughness, I see the code you gave at #282 but I can't render it, can you help me with this? Thank you very much! I noticed that the code you gave is different from the one in SegMapRender. the first one use get_all_mesh_objects() but the second one use "get_all_blender_mesh_objects()". It seems that one returns a MeshObject, while the second returns an Object.

Minimal code example

# your code at issue 282
objects = get_all_mesh_objects()
for obj in objects:
    materials = obj.get_materials()
    for material in materials:
        principled_bsdf = material.get_the_one_node_with_type("BsdfPrincipled")
        for key in ["Roughness", "Metallic", "Specular"]:
            obj.set_cp("cp_"+ key,  principled_bsdf.inputs[key].default_value)

# code in SegMapRendererUtility.py
objs_with_mats = get_all_blender_mesh_objects()

Files required to run the code

Nothing

Expected behavior

render segmap such as roughness.

BlenderProc version

2.7

cornerfarmer commented 2 months ago

Hey @zsy1987,

could you please provide the error message you get when using the code?

get_all_blender_mesh_objects() gives you a list of the raw blender objects, so get_all_mesh_objects() should be correct.

adkAurora commented 1 month ago

About the code you gave at #282 , Where should this part of the code be modified? Is it in the SegMapRendererUtility.py file?

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering?

bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

cornerfarmer commented 1 month ago

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering?

bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

Yes that should be the way to go. Does it work?

bbbbubble commented 1 month ago

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering? bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

Yes that should be the way to go. Does it work?

@cornerfarmer It doesn't work. This is my code:

for key in ["Roughness", "Metallic", "Specular"]:
    obj.set_cp("cp_"+ key,  principled_bsdf.inputs[key].default_value)
bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", "cp_Specular", 'instance'],default_values={'roughness': None, 'metallic': None, 'specular': None})

It shows error:

The object "World" does not have the attribute: "cp_roughness". Either set the attribute for every object or pass a default value to bproc.renderer.enable_segmentation_output(default_values={'cp_roughness': None}).

If I change the code to

bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", "cp_Specular", 'instance'],default_values={'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None} )

It does't show any error, but after render, the result data does not contain any metallic and roughness values.

(Pdb) data["instance_attribute_maps"]
[[{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}], [{'idx': 0, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}, {'idx': 1, 'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None}]]
adkAurora commented 1 month ago

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering? bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

Yes that should be the way to go. Does it work?

I have tried, but it didn't work. I have rewritten the code using origin bpy to create ShaderNodeOutputAOV, and it works now. Thank you for your help. If possible, I will submit a PR in the future.

bbbbubble commented 1 month ago

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering? bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

Yes that should be the way to go. Does it work?

I have tried, but it didn't work. I have rewritten the code using origin bpy to create ShaderNodeOutputAOV, and it works now. Thank you for your help. If possible, I will submit a PR in the future.

I've been struggling with this issue for a week now and would very much look forward to your PR. ^v^ Could you please share the code here first, or maybe when will you submit a PR? Thank you so much!

cornerfarmer commented 1 month ago

Hey @bbbbubble,

how do your material nodes look like? For the roughness/metallic/specular socket, do you have a default_value set or did you connect it with an image texture for example? The code from the other issue only works if a default value is set there.

So could you please print principled_bsdf.inputs[key].default_value inside your first loop. Does this output the correct values?

bbbbubble commented 1 month ago

Hey @bbbbubble,

how do your material nodes look like? For the roughness/metallic/specular socket, do you have a default_value set or did you connect it with an image texture for example? The code from the other issue only works if a default value is set there.

So could you please print principled_bsdf.inputs[key].default_value inside your first loop. Does this output the correct values?

@cornerfarmer Thank you for your reply! I tested with multiple objects. I'm actually new in this field, but I think the default values in correctly set. This is my code:

# some objects' normals are affected by textures
mesh_objects = convert_to_meshes([obj for obj in scene_meshes()])
for obj in mesh_objects:
    for mat in obj.get_materials():
        mat.set_principled_shader_value("Normal", [1,1,1])
        principled_bsdf = mat.get_the_one_node_with_type("BsdfPrincipled")
        import pdb; pdb.set_trace()
        for key in ["Roughness", "Metallic", "Specular"]:
            obj.set_cp("cp_"+ key,  principled_bsdf.inputs[key].default_value)

The first object: image default_values:

-> for key in ["Roughness", "Metallic", "Specular"]:
(Pdb) principled_bsdf.inputs["Roughness"].default_value
0.5
(Pdb) principled_bsdf.inputs["Metallic"].default_value
0.0
(Pdb) principled_bsdf.inputs["Specular"].default_value
0.5

The second object: image default_values:

(Pdb) principled_bsdf.inputs["Roughness"].default_value
1.0
(Pdb) principled_bsdf.inputs["Metallic"].default_value
0.0
(Pdb) principled_bsdf.inputs["Specular"].default_value
0.5
cornerfarmer commented 1 month ago

Hey @bbbbubble,

thanks for the detailed infos. I think I found the reason why it is not working. The segmentation renderer maps all keys to lower case internally (see https://github.com/DLR-RM/BlenderProc/blame/main/blenderproc/python/postprocessing/PostProcessingUtility.py#L352), I dont know why yet.

But to make it working for you, you just need to make every custom property lowercase:

            obj.set_cp("cp_"+ key.lower(),  principled_bsdf.inputs[key].default_value)

and

bproc.renderer.enable_segmentation_output(map_by=["cp_roughness", "cp_metallic", "cp_specular", 'instance'],default_values={'cp_roughness': None, 'cp_metallic': None, 'cp_specular': None} )

Then everything should work.

adkAurora commented 1 month ago

Hey cornerfarmer,

I have a question. For models with roughness and metallic textures, can this method still be used? I tried it, but it seems to only return default values.

for key in ["Roughness", "Metallic"]:
    if len(principled_bsdf.inputs[key].links) == 0:
        obj.set_cp("cp_"+ key.lower(),  principled_bsdf.inputs[key].default_value)
    else:
        print(principled_bsdf.inputs[key].value)
        link_roughness = principled_bsdf.inputs[key].links[0]
        # should be like this?
        # obj.set_cp("cp_"+ key.lower(),  link_roughness.from_socket.name)    
        # what i want like this in bpy 
        # mat_links.new(link_metallic.from_node.outputs[link_metallic.from_socket.name], node_combine_color.inputs["B"])
cornerfarmer commented 1 month ago

No, as I mentioned above, this code only cares about the default values. If you want to render the textures, you need to change the materials and the rendering parameters, it gets more complex. Please open another issue if you want to discuss that.

bbbbubble commented 1 month ago

No, as I mentioned above, this code only cares about the default values. If you want to render the textures, you need to change the materials and the rendering parameters, it gets more complex. Please open another issue if you want to discuss that.

Yes, I can confirm that this code only cares about the default values. Here is the roughness / metallic rendering result of the first object I mentioned above, which isn't what I expected: image

@cornerfarmer @adkAurora I opened a new issue #1131 , look forward to some discussions with you. Thank you!

bbbbubble commented 1 month ago

Or is it simply a matter of incorporating this code into the main rendering code and utilizing it for rendering? bproc.renderer.enable_segmentation_output(map_by=["cp_Roughness", "cp_Metallic", 'instance'],default_values={'roughness': None, 'metallic': None} ) data = bproc.renderer.render()

Yes that should be the way to go. Does it work?

I have tried, but it didn't work. I have rewritten the code using origin bpy to create ShaderNodeOutputAOV, and it works now. Thank you for your help. If possible, I will submit a PR in the future.

Could you please share the ShaderNodeOutputAOV and related code with us here? Thank you!

bbbbubble commented 3 weeks ago

No one can answer this question? It seems like a very basic problem...