Simple exporter script - need some Python advice

Viewed 4 times


I am trying to script a simple exporter that would help me get material data to a webGL engine from Blender 2.8. I am able to get default values of roughness, metallic and transparency. For now this is how it looks:

import bpy

materials_list = []

for mat in    
    mat_dict = {}
    mat_dict["name"] =
    mat_dict["roughness"] = mat.node_tree.nodes.get("Principled BSDF").inputs["Roughness"].default_value
    mat_dict["metallic"] = mat.node_tree.nodes.get("Principled BSDF").inputs["Metallic"].default_value
    mat_dict["opacity"] = 1 - mat.node_tree.nodes.get("Principled BSDF").inputs["Transmission"].default_value


I am can’t find a way to check if the Principled BSDF has textures attached controlling this values and save their paths. How can I extend this script to get the texture information?

Here how I would do it, perhaps there is another way but it works.


Hi @const, thank you for your answer! Unfortunatelly it doesn’t work on my side. Gives me an error:
KeyError : 'bpy_prop_collection[key]: key “Material” not found. Not sure how to interpret it.

Anyway I got some ideas from your code and tried to incorporate it into my script but with no success. Here is what I tried:

import bpy

materials_list = []

for mat in    
    mat_dict = {}
    prinBSDF = mat.node_tree.nodes["Principled BSDF"]

    mat_dict["name"] =

    if prinBSDF.inputs["Roughness"].type == 'TEX_IMAGE':
        mat_dict["roughness"] = prinBSDF.inputs["Roughness"].image.filepath
        mat_dict["roughness"] = prinBSDF.inputs["Roughness"].default_value


but I get an error "AttributeError: ‘NodeSocketFloatFactor’ object has no attribute ‘image’.

Do you have any idea what is missing here? Or am I completely wrong about it?

Code updated here as well…

Hi @const, thank you very much for your time! It all seems very logical for me but unfortunately doesn’t work. It still collects only default values and ignores the bitmaps. I checked a simplified version of the script to ignore default value and force writing textures and I get an error "AttributeError: ‘NodeSocketFloatFactor’ object has no attribute ‘image’ ". Do you have any idea how to move forward with it?

This time I tried to get access to the data types more properly. It would be fun though if Python allowed direct access, less code to type.

import bpy

def get_materials():
    # a list of dictionaries
    matlist = []
    # iterating all of the materials
    for mat in    
        # get the bsdf node
        bsdf = None
        if mat.node_tree != None: # should have node tree
            for n in mat.node_tree.nodes.keys(): # searching all nodes
                node = mat.node_tree.nodes[n]
                if node.type == 'BSDF_PRINCIPLED': # node type should be bdsf
                    bsdf = node # setting the node
                    break # exit node tree
        # bsdf not found, skipping
        if bsdf == None:
        # dictionary
        d = {} # create a dictionary
        d["name"] = # set material name

        # get roughness socket
        roughness = bsdf.inputs.get("Roughness")

        # ensure input node is an image
        if len(roughness.links) == 1 and roughness.links[0].from_node.type == 'TEX_IMAGE':
            d["roughness"] = roughness.links[0].from_node.image.filepath
            d["roughness"] = roughness.default_value

        # list
        matlist.append(d) # appending to list
    # return
    return matlist

m = get_materials()

I tried also some tests in various cases. With an image and then without one. You should see the same results.

2020-07-06 12_42_14-D__programs_graphics_blender28_blender.exe

Thank you very much @const! Now it is working.

I faced another challenge trying to collect information about lights in the scene. I can easily get all properties of the lights but can’t find a way to get location and rotation of all instances of the lights. How should I approach this?

For now this is how it looks like:

import bpy
import math

def get_lights():
    lights_list = []
    for light in
        light_dict = {}
        light_dict['type'] = light.type
        light_dict['name'] =
        if light.type == 'SPOT':
            light_dict['angle'] = int(light.spot_size*180/math.pi)

        if light.type == 'SPOT' or light.type == 'POINT':
            light_dict['size'] = light.shadow_soft_size
        light_dict['strength'] =
        light_color = []
        light_color.append(round(light.color.r, 2))
        light_color.append(round(light.color.g, 2))
        light_color.append(round(light.color.b, 2))
        light_dict['color'] = light_color
    return lights_list

l = get_lights()

To get location and rotation you can do this

>>> bpy.context.active_object.location
Vector((4.076245307922363, 1.0054539442062378, 5.903861999511719))

>>> bpy.context.active_object.rotation_euler
Euler((0.6503279805183411, 0.055217113345861435, 1.8663908243179321), 'XYZ')

Note that the rotation is in radians, so it means that 360deg = 2*Pi.