Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

Bitmap Node zu Arnold Node - Python

Bitmap Node zu Arnold Node - Python

vockC3F3P
Contributor Contributor
1,770 Views
20 Replies
Message 1 of 21

Bitmap Node zu Arnold Node - Python

vockC3F3P
Contributor
Contributor

Hallo Zusammen

Beim Umwandeln von einem Asset zum Arnold Legacy Material erhalte ich eine Bitmapnode welche ich alle sehr aufwendig zu image nodes umwandeln muss da ich im ACES Farbraum arbeite.

Nun habe ich versucht per Pyton ein script zu schreiben welches erstens:

das Standardmaterial mit Shader und Viewport Port verknüpft und den bitmapnode mit dem Imagenode austauschen soll. 

Leider scheint das nicht zu klappen.

Hier das Script mit Versionsprüfung:

import c4d
import os
import sys

# Fügt das Skriptverzeichnis zum Systempfad hinzu
scripts_folder = "C:\\Program Files\\Maxon Cinema 4D 2023\\library\\scripts\\arnold"
if scripts_folder not in sys.path:
sys.path.append(scripts_folder)

# Importiert die spezifischen Arnold-Module
import arnold.util as arnold_util
import arnold

ARNOLD_SCENE_HOOK = 1032309
C4DTOA_MSG_TYPE = 1000
C4DTOA_MSG_GET_VERSION = 1040
C4DTOA_MSG_RESP1 = 2011
C4DTOA_MSG_RESP2 = 2012
C4DTOA_MSG_RESP3 = 2013

def GetC4DtoAVersion():
arnoldSceneHook = doc.FindSceneHook(ARNOLD_SCENE_HOOK)
if arnoldSceneHook is None:
return ""

msg = c4d.BaseContainer()
msg.SetInt32(C4DTOA_MSG_TYPE, C4DTOA_MSG_GET_VERSION)
arnoldSceneHook.Message(c4d.MSG_BASECONTAINER, msg)

return msg.GetString(C4DTOA_MSG_RESP1)

def GetC4DtoAVersionNum():
arnoldSceneHook = doc.FindSceneHook(ARNOLD_SCENE_HOOK)
if arnoldSceneHook is None:
return ""

msg = c4d.BaseContainer()
msg.SetInt32(C4DTOA_MSG_TYPE, C4DTOA_MSG_GET_VERSION)
arnoldSceneHook.Message(c4d.MSG_BASECONTAINER, msg)

arch = msg.GetInt32(3000)
major = msg.GetInt32(3001)
minor = msg.GetInt32(3002)
fix = msg.GetInt32(3003)
dev = msg.GetString(3004)
return (arch, major, minor, fix, dev)

def GetArnoldVersion():
arnoldSceneHook = doc.FindSceneHook(ARNOLD_SCENE_HOOK)
if arnoldSceneHook is None:
return ""

msg = c4d.BaseContainer()
msg.SetInt32(C4DTOA_MSG_TYPE, C4DTOA_MSG_GET_VERSION)
arnoldSceneHook.Message(c4d.MSG_BASECONTAINER, msg)

return msg.GetString(C4DTOA_MSG_RESP2)

def GetArnoldVersionNum():
arnoldSceneHook = doc.FindSceneHook(ARNOLD_SCENE_HOOK)
if arnoldSceneHook is None:
return ""

msg = c4d.BaseContainer()
msg.SetInt32(C4DTOA_MSG_TYPE, C4DTOA_MSG_GET_VERSION)
arnoldSceneHook.Message(c4d.MSG_BASECONTAINER, msg)

arch = msg.GetInt32(4000)
major = msg.GetInt32(4001)
minor = msg.GetInt32(4002)
fix = msg.GetString(4003)
return (arch, major, minor, fix)

def main():
print("C4DtoA version:", GetC4DtoAVersion())
print("C4DtoA version num:", GetC4DtoAVersionNum())
print("Arnold version:", GetArnoldVersion())
print("Arnold version num:", GetArnoldVersionNum())

# Durchläuft alle Materialien im Material-Manager
for mat in doc.GetMaterials():
# Bearbeitet das Material
edit_material(mat)

def edit_material(mat):
# Sucht nach dem Hauptknoten (main)
main_node = mat[arnold.C4DAIN_MATERIAL_MAIN]

# Verbindet den Hauptknoten (main) mit dem Arnold-Viewport und dem Arnold-Shader-Port
mat[arnold.C4DAI_VIEWPORT].SetLink(main_node)
mat[arnold.C4DAI_SHADER_PORT].SetLink(main_node)

# Ersetzt alle Bitmap-Knoten durch Image-Knoten
replace_bitmap_with_image(mat)

def replace_bitmap_with_image(mat):
# Durchläuft alle Knoten
for node in mat.GetNodes():
# Wenn der Knoten ein Bitmap-Knoten ist
if node.GetType() == arnold.C4DAI_BITMAP:
# Erstellt einen neuen Image-Knoten
image_node = arnold.AiNode("image")

# Kopiert den Dateipfad von der Bitmap zum Image-Knoten
image_node[arnold.C4DAI_IMAGE_FILENAME] = node[arnold.C4DAI_BITMAP_FILENAME]

# Ersetzt den Bitmap-Knoten durch den Image-Knoten
mat.ReplaceNode(node, image_node)

# Verbindet den Image-Knoten mit den entsprechenden Ports im Hauptknoten
node_master = mat.GetNodeMaster()
connections = node_master.GetConnections(node)
for conn in connections:
input_port_id = conn.GetInputID()
image_node.ConnectTo(main_node, input_port_id)

# Führt die Hauptfunktion aus
if __name__ == '__main__':
main()

 

Fehlermeldung:

C4DtoA version: 4.6.3
C4DtoA version num: (4, 6, 3, 0, '')
Arnold version: 7.2.2.0
Arnold version num: (7, 2, 2, '0')
Traceback (most recent call last):
File "C:\Users\MarcVock\Desktop\Materialexch.py", line 119, in <module>
main()
File "C:\Users\MarcVock\Desktop\Materialexch.py", line 83, in main
edit_material(mat)
File "C:\Users\MarcVock\Desktop\Materialexch.py", line 87, in edit_material
main_node = mat[arnold.C4DAIN_MATERIAL_MAIN]
AttributeError: module 'arnold' has no attribute 'C4DAIN_MATERIAL_MAIN'

 

Evtl. reicht es aber auch, wenn ich in der Bitmapnode den Hacken bei " Use custom color Space" setze?

Das wäre super und wenns dafür noch ein script gibt noch besser.

 

Danke für die Hilfe

 

0 Likes
Accepted solutions (3)
1,771 Views
20 Replies
Replies (20)
Message 21 of 21

vockC3F3P
Contributor
Contributor

here the code with spec to white

 

import c4d
import os
import sys

# add the script folder to the system path
scripts_folder = os.path.join(c4d.storage.GeGetC4DPath(c4d.C4D_PATH_LIBRARY), "scripts")
if scripts_folder not in sys.path:
    sys.path.append(scripts_folder)

from arnold.material import *
import arnold.util as arnold_util

C4DAIN_STANDARD_SURFACE = arnold_util.GenerateId("standard_surface")
C4DAIP_STANDARD_SURFACE_SPECULAR_COLOR = arnold_util.GenerateId("standard_surface.specular_color")
C4DAIP_STANDARD_SURFACE_SPECULAR_ROUGHNESS = arnold_util.GenerateId("standard_surface.specular_roughness")
C4DAIP_STANDARD_SURFACE_NORMAL = arnold_util.GenerateId("standard_surface.normal")
C4DAIN_BUMP2D = arnold_util.GenerateId("bump2d")
C4DAIP_BUMP2D_BUMP_MAP = arnold_util.GenerateId("bump2d.bump_map")
C4DAIN_NORMAL_MAP = arnold_util.GenerateId("normal_map")
C4DAIP_NORMAL_MAP_INPUT = arnold_util.GenerateId("normal_map.input")
C4DAIN_IMAGE = arnold_util.GenerateId("image")
C4DAIP_IMAGE_FILENAME = arnold_util.GenerateId("image.filename")

def find_input_shader(connections, shader, param):
    for connection in connections:
        src, out_port, dst, in_port = connection
        if dst == shader and in_port == param:
            return src
    return None

def bitmap_to_image(arnoldMaterial, bitmap):
    print("processing Bitmap shader: ", bitmap)

    # create an image shader
    image = arnoldMaterial.AddShader(C4DAIN_IMAGE, bitmap.GetName())

    # copy filename
    filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
    arnoldMaterial.SetShaderValue(image, C4DAIP_IMAGE_FILENAME, filename)

    # if the Bitmap is connected to the "shader" port of the material
    if arnoldMaterial.GetRootShader("shader") == bitmap:
        arnoldMaterial.AddRootConnection(image, None, "shader")

    # copy all output connections to other nodes
    connections = arnoldMaterial.GetConnections()
    for connection in connections:
        src, out_port, dst, in_port = connection
        if src== bitmap:
            arnoldMaterial.AddConnection(image, out_port, dst, in_port)

    # remove the bitmap shader
    arnoldMaterial.RemoveShader(bitmap)

def bump_to_normal(arnoldMaterial, shader):
    if arnoldMaterial.GetShaderId(shader) != C4DAIN_STANDARD_SURFACE:
        return

    connections = arnoldMaterial.GetConnections()

    # find the shader connected to the normal input
    normalShader = find_input_shader(connections, shader, C4DAIP_STANDARD_SURFACE_NORMAL)

    # check if a bump2d shader is connected
    if normalShader is not None and arnoldMaterial.GetShaderId(normalShader) == C4DAIN_BUMP2D:
        bump = normalShader
        print(" checking bump2d shader: ", bump)

        # find the image shader connected to bump_map
        image = find_input_shader(connections, bump, C4DAIP_BUMP2D_BUMP_MAP)
        if image is not None and arnoldMaterial.GetShaderId(image) == C4DAIN_IMAGE:
            # verify the filename
            filename = arnoldMaterial.GetShaderValue(image, C4DAIP_IMAGE_FILENAME)
            if "nrm" in filename or "normal" in filename:
                print(" normal map found in bump, replace with normal_map shader")
                print("  %s" % filename)

                # create a normal_map shader
                normal_map = arnoldMaterial.AddShader(C4DAIN_NORMAL_MAP, "normal_map")

                # connect image to normal_map input
                arnoldMaterial.AddConnection(image, 0, normal_map, C4DAIP_NORMAL_MAP_INPUT)
                # connect normal_map to standard_surface.normal
                arnoldMaterial.AddConnection(normal_map, 0, shader, C4DAIP_STANDARD_SURFACE_NORMAL)

                # remove the bump2d shader
                arnoldMaterial.RemoveShader(bump)

# iterate over the materials in the scene
for mat in doc.GetMaterials():
    arnoldMaterial = ArnoldLegacyMaterial(mat)

    # collect Bitmap and standard_surface shaders
    shaders = arnoldMaterial.GetShaders()
    bitmapShaders = [shader for shader in shaders if arnoldMaterial.GetShaderId(shader) == C4DAIN_C4D_BITMAP]
    standardSurfaceShaders = [shader for shader in shaders if arnoldMaterial.GetShaderId(shader) == C4DAIN_STANDARD_SURFACE]

    # process Bitmap shaders
    for bitmap in bitmapShaders:
        bitmap_to_image(arnoldMaterial, bitmap)

    # process standard_surface shaders
    for shader in standardSurfaceShaders:
        print("processing standard_surface shader: ", shader)

        # connect the shader to the viewport root port
        print(" connecting shader to viewport")
        arnoldMaterial.AddRootConnection(shader, None, "viewport")

        # move specular color input to specular roughness
        connections = arnoldMaterial.GetConnections()
        for connection in connections:
            src, out_port, dst, in_port = connection
            if dst == shader and in_port == C4DAIP_STANDARD_SURFACE_SPECULAR_COLOR:
                print(" moving specular color input to specular roughness")
                arnoldMaterial.AddConnection(src, out_port, shader, C4DAIP_STANDARD_SURFACE_SPECULAR_ROUGHNESS)
                arnoldMaterial.RemoveConnection(shader, C4DAIP_STANDARD_SURFACE_SPECULAR_COLOR)

        # replace bump2d with normal map if needed
        bump_to_normal(arnoldMaterial, shader)
        
# Set specular color to white
    for shader in standardSurfaceShaders:
       print("      specular to white")
       arnoldMaterial.SetShaderValue(shader,801517079, c4d.Vector(1, 1, 1))

    arnoldMaterial.AlignShaders()
    c4d.EventAdd()
0 Likes