Community
Arnold for Cinema 4D Forum
Rendering with Arnold in CINEMA 4D using the C4DtoA plug-in.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Bitmap Node zu Arnold Node - Python

20 REPLIES 20
SOLVED
Reply
Message 1 of 21
vockC3F3P
635 Views, 20 Replies

Bitmap Node zu Arnold Node - Python

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

 

20 REPLIES 20
Message 2 of 21
peter_horvath
in reply to: vockC3F3P

In recent versions there's a simple python API to edit Arnold materials. See https://help.autodesk.com/view/ARNOL/ENU/?guid=arnold_for_cinema_4d_ci_python_api_ci_arnold_material...

You can check library/scripts/arnold_material_examples.py for examples.

 

In your case you can do something like this:

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

for mat in doc.GetMaterials():
    arnoldMaterial = ArnoldLegacyMaterial(mat)
    
    shaders = arnoldMaterial.GetShaders()
    connections = arnoldMaterial.GetConnections()

    # find Bitmap shaders
    for shader in shaders:
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_C4D_BITMAP:
            bitmap = shader

            # create an image shader
            image = arnoldMaterial.AddShader(C4DAIN_IMAGE, "my_image")

            # copy filename
            filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
            arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("image.filename"), filename)

            ...

 


// Peter Horvath
// C4DtoA developer
Message 3 of 21
peter_horvath
in reply to: vockC3F3P

But if you just need to specify an Arnold color space, you can enable the "Use custom color space" option.

Something like:

C4DAI_GVC4DSHADER_BITMAP_COLOR_SPACE = 10101
C4DAI_GVC4DSHADER_BITMAP_USE_COLOR_SPACE = 10102

shader[C4DAI_GVC4DSHADER_BITMAP_USE_COLOR_SPACE] = True
shader[C4DAI_GVC4DSHADER_BITMAP_COLOR_SPACE] = "sRGB"

 


// Peter Horvath
// C4DtoA developer
Message 4 of 21
vockC3F3P
in reply to: peter_horvath

thx for your quick reply.

i get the following error back

--

Traceback (most recent call last):
File "scriptmanager", line 26, in <module>
NameError: name 'C4DAIN_IMAGE' is not defined. Did you mean: 'C4DAIN_TRIGO'?

--

would you like to help me what this means?

thx for the tip with the other examples. Im a beginner in python and its still confusing for me to see a lot of different options:)

 

much thanks

Message 5 of 21
peter_horvath
in reply to: vockC3F3P

You can add

C4DAIN_IMAGE = 262700200

to your script (ids are in the C4DtoA/res/arnold_node_ids.h header).

 

Or just use arnold_util.GenerateId like this:

image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), "my_image")

 


// Peter Horvath
// C4DtoA developer
Message 6 of 21
vockC3F3P
in reply to: peter_horvath

with the second line its sort of works.

Image node is there but not conected because the bitmap still is in place.

is it possible to delet the bitmap node and autoconnect the image node automaticly to the port where the bitmap was?

Message 7 of 21
peter_horvath
in reply to: vockC3F3P


@vockC3F3P wrote:

is it possible to delet the bitmap node and autoconnect the image node automaticly to the port where the bitmap was?


You have to do it manually. Check the connections of the Bitmap shader, add the same ones to the image and then remove the Bitmap shader. Note, that connections to the material root ports (like, shader, viewport, etc.) are different, than connections to other nodes (AddRootConnection vs AddConnection).

 

For instance:

# 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)

 


// Peter Horvath
// C4DtoA developer
Message 8 of 21
vockC3F3P
in reply to: vockC3F3P

so far so good. 

bitmatshaders are changed to image and bitmap deleted. but as soon as i try to connect the standard suface shader to the viewport and change the specular color port to the roughness port  it stops working??

 

this is the working script till deleting the bitmapshaders

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

for mat in doc.GetMaterials():
    arnoldMaterial = ArnoldLegacyMaterial(mat)

    shaders = arnoldMaterial.GetShaders()
    connections = arnoldMaterial.GetConnections()

    # find Bitmap shaders
    for shader in shaders:
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_C4D_BITMAP:
            bitmap = shader

            # create an image shader
            image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), "my_image")


            # copy filename
            filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
            arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)

how do i manage to always connect the surface shader to the viewport? I tried bot of the tips as you mentioned before AddRoot/AddConnec...

Message 9 of 21
peter_horvath
in reply to: vockC3F3P

Connecting standard_surface to viewport:

C4DAIN_STANDARD_SURFACE = arnold_util.GenerateId("standard_surface")

# first you need to find the standard_surface shader
for shader in shaders:
    shaderId = arnoldMaterial.GetShaderId(shader)
    if shaderId == C4DAIN_STANDARD_SURFACE:
        # connect the shader to the viewport root port
        arnoldMaterial.AddRootConnection(shader, None, "viewport")

 

"change the specular color port to the roughness port"

Not sure what do you mean by this.


// Peter Horvath
// C4DtoA developer
Message 10 of 21
vockC3F3P
in reply to: peter_horvath

hmm.. thats almost what i had too, but its not working somehow. no error but also no conection to viewport. I tried to search for the id as listed in the arnold_node_ids but that does not work too...

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

for mat in doc.GetMaterials():
    arnoldMaterial = ArnoldLegacyMaterial(mat)

    shaders = arnoldMaterial.GetShaders()
    connections = arnoldMaterial.GetConnections()

    # find Bitmap shaders
    for shader in shaders:
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_C4D_BITMAP:
            bitmap = shader

            # create an image shader
            image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), "my_image")


            # copy filename
            filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
            arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)
            
C4DAIN_STANDARD_SURFACE = arnold_util.GenerateId("standard_surface")

# first you need to find the standard_surface shader
for shader in shaders:
    shaderId = arnoldMaterial.GetShaderId(shader)
    if shaderId == C4DAIN_STANDARD_SURFACE:
        # connect the shader to the viewport root port
        arnoldMaterial.AddRootConnection(shader, None, "viewport")

 what i meant with specular color and roughness was:

often the specularmaps ar conected to the port color in the specular from standard surface. but it almost ever should go into the roughness port from specular in the standard surface

roughness.jpg

Message 11 of 21
peter_horvath
in reply to: vockC3F3P

It's working fine for me, but watch the indentation: move the last part within the material for loop.

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

for mat in doc.GetMaterials():
    arnoldMaterial = ArnoldLegacyMaterial(mat)

    shaders = arnoldMaterial.GetShaders()
    connections = arnoldMaterial.GetConnections()

    # find Bitmap shaders
    for shader in shaders:
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_C4D_BITMAP:
            bitmap = shader

            # create an image shader
            image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), "my_image")


            # copy filename
            filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
            arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)
            
    C4DAIN_STANDARD_SURFACE = arnold_util.GenerateId("standard_surface")

    # first you need to find the standard_surface shader
    for shader in shaders:
        print("processing shader: ", shader)
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_STANDARD_SURFACE:
            # connect the shader to the viewport root port
            print("connecting shader to viewport")
            arnoldMaterial.AddRootConnection(shader, None, "viewport")

You can also print some messages to the console to follow what's going on.


// Peter Horvath
// C4DtoA developer
Message 12 of 21
peter_horvath
in reply to: vockC3F3P

About the specular map, so you want to change the connection from the color to roughness. You can do it with this code:

            # move specular color input to specular roughness
            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)

The entire script:

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")

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

    shaders = arnoldMaterial.GetShaders()
    connections = arnoldMaterial.GetConnections()

    # find Bitmap shaders
    for shader in shaders:
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_C4D_BITMAP:
            bitmap = shader

            # create an image shader
            image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), "my_image")

            # copy filename
            filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
            arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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
            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)
            
    # find the standard_surface shader
    for shader in shaders:
        print("processing shader: ", shader)
        shaderId = arnoldMaterial.GetShaderId(shader)
        if shaderId == C4DAIN_STANDARD_SURFACE:
            # 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
            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)
                    

 


// Peter Horvath
// C4DtoA developer
Message 13 of 21
vockC3F3P
in reply to: vockC3F3P

Good morning

Thank you very much for the tip with the indentation. And the print to console is very cool. didnt know thats possible:)

I have a very odd problem know:

I started with a fresh scene and run the script copied 1:1 from you (no messing from my side;))

This is the console output

--

processing shader: <c4d.modules.graphview.GvNode object called main/Arnold Shader with ID 1001101 at 1948322427840>
connecting shader to viewport
processing shader: <dead c4d.modules.graphview.GvNode object at 0x000001C5A1106F40>
Traceback (most recent call last):
File "C:\Users\MarcVock\Desktop\Materialexch-Sup.py", line 53, in <module>
shaderId = arnoldMaterial.GetShaderId(shader)
File "C:\Program Files\Maxon Cinema 4D 2023\library\scripts\arnold\material.py", line 187, in GetShaderId
if shader.GetOperatorID() == ARNOLD_SHADER_GV:
ReferenceError: the object 'c4d.modules.graphview.GvNode' is not alive
processing shader: <c4d.modules.graphview.GvNode object called main/Arnold Shader with ID 1001101 at 1948414658112>
connecting shader to viewport
processing shader: <c4d.modules.graphview.GvNode object called my_image/Arnold Shader with ID 1001101 at 1948414670656>
Traceback (most recent call last):
File "C:\Users\MarcVock\Desktop\Materialexch-Sup.py", line 44, in <module>
if src== bitmap:
ReferenceError: the object 'c4d.modules.graphview.GvNode' is not alive

--

if I press run the first time only the first material gets converted like it should (side note: no specular chanel, only Base color bitmap). the second material is not converted, still bitmap shader and no connection to viewport.

If I hit run again the second and third one is converted. this can be repeated for many times and eventualy all are converted. But in a scene with 200 materials its a lot of clicking:)

Whats odd is the info about the line 187.

I attached a printscreen from two materials befor and after.

One only with a color node and one with a specular node.

 

what do you think?

Message 14 of 21
peter_horvath
in reply to: vockC3F3P

It's because the material is modified, while iterating over the shader and connection list. Here's an updated script, which first collects the relevant shaders, before modifying the material.

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")

# 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:
        print("processing Bitmap shader: ", bitmap)

        # create an image shader
        image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), bitmap.GetName())

        # copy filename
        filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
        arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)
        
    # 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)
                    
    arnoldMaterial.AlignShaders()

 


// Peter Horvath
// C4DtoA developer
Message 15 of 21
vockC3F3P
in reply to: peter_horvath

Thank you very much. It works perfect. I added also all specular colors to white. What is not working is to remove all unused Ports in Standard Surface. 

I simply tried to  - arnold.Material.RemoveUnusedPorts() 

here the code with all spec to white implemented

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")

# 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:
        print("processing Bitmap shader: ", bitmap)

        # create an image shader
        image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), bitmap.GetName())

        # copy filename
        filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
        arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)

    # 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)

    # Set specular color to white
    for shader in standardSurfaceShaders:
       print("  specular to white")
       arnoldMaterial.SetShaderValue(shader,801517079, c4d.Vector(1, 1, 1))

    arnoldMaterial.AlignShaders()
Message 16 of 21
peter_horvath
in reply to: vockC3F3P

Try 

shader.RemoveUnusedPorts()

 after you've done with modifying the connections.


// Peter Horvath
// C4DtoA developer
Message 17 of 21
vockC3F3P
in reply to: vockC3F3P

TADAA.

Thank you very much for your help.

Here to code with the remove Ports part.

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")

# 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:
        print(" processing Bitmap shader: ", bitmap)

        # create an image shader
        image = arnoldMaterial.AddShader(arnold_util.GenerateId("image"), bitmap.GetName())

        # copy filename
        filename = arnoldMaterial.GetShaderValue(bitmap, c4d.BITMAPSHADER_FILENAME)
        arnoldMaterial.SetShaderValue(image, arnold_util.GenerateId("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)
        
           # 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)
                
        # remove unused Ports
        print("     remove unused ports")
        shader.RemoveUnusedPorts()

    # Set specular color to white
    for shader in standardSurfaceShaders:
       print("      specular to white")
       arnoldMaterial.SetShaderValue(shader,801517079, c4d.Vector(1, 1, 1))

    arnoldMaterial.AlignShaders()

Thank you again.

Message 18 of 21
vockC3F3P
in reply to: vockC3F3P

Hi Peter

Would it be possible to script the following into this script:

Check if the nomral/Geometry port is used

if yes, check if a normal node or a bump 2D is linked

if Bump 2D is linked check the filenam of the Image node conected to Inputport Bumpmap is a normal or a bump map

if normal map, delete bump 2d node and replace it with normal node and conect it to the geomettry Normal port of standard surface and conect image node to input normal port from normal node.

 

Usualy the normal maps have "nrm" or "normal" written in the filename (i.e. "pot_normal15sbtde.jpg", "v1texture nrm"), or maybe there is a better solution to chek if its a normal map?

 

Best,

Marc

Message 19 of 21
peter_horvath
in reply to: vockC3F3P

Sure, here you go:

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)

    arnoldMaterial.AlignShaders()
    c4d.EventAdd()    
    

// Peter Horvath
// C4DtoA developer
Message 20 of 21
vockC3F3P
in reply to: vockC3F3P

That is a perfect script. Thank you very much!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums