Last active
March 1, 2024 08:32
-
-
Save moorage/02099837cfb9b1f8279b76c79f348325 to your computer and use it in GitHub Desktop.
Extract BSDF values from Blender in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import colorsys | |
import json | |
# https://blender.stackexchange.com/a/80047/58635 | |
def _convert_rgb_to_hsv(red, green, blue): | |
return colorsys.rgb_to_hsv(*_linear_to_srgb(red, green, blue)) | |
# https://blender.stackexchange.com/a/80047/58635 | |
def _linear_to_srgb(r, g, b): | |
def linear(c): | |
a = .055 | |
if c <= .0031308: | |
return 12.92 * c | |
else: | |
return (1+a) * c**(1/2.4) - a | |
return tuple(linear(c) for c in (r, g, b)) | |
def exportMaterials(obj=None): | |
''' find the material we want''' | |
if obj: | |
# list mats for selected objects | |
for mat in obj.data.materials: | |
if pbsdf != None: | |
print("-------",mat.name,"-------") | |
print(json.dumps(nodeToJSON(mat))) | |
print("-------") | |
else: | |
# list all materials in scene | |
for mat in bpy.data.materials: | |
pbsdf = nodeToJSON(mat) | |
if pbsdf != None: | |
print("-------",mat.name,"-------") | |
print(json.dumps(nodeToJSON(mat))) | |
print("-------") | |
def nodeToJSON(mat): | |
'''converts principled materials nodes to a set of list/dictionaries''' | |
principledNodeCount = 0 | |
volumeNodeCount = 0 | |
pbsdf = {"Name": mat.name} | |
for node in mat.node_tree.nodes: | |
if node.type == 'BSDF_PRINCIPLED': | |
principledNodeCount += 1 | |
base_color_rgb=[1,1,1] | |
base_color_rgb[0] = node.inputs[0].default_value[0] | |
base_color_rgb[1] = node.inputs[0].default_value[1] | |
base_color_rgb[2] = node.inputs[0].default_value[2] | |
pbsdf["BaseColorHue"], pbsdf["BaseColorSaturation"], pbsdf["BaseColorValue"] = _convert_rgb_to_hsv(*base_color_rgb) | |
pbsdf["BaseColorAlpha"] = node.inputs[0].default_value[3] | |
pbsdf["Subsurface"] = node.inputs[1].default_value | |
pbsdf["SubsurfaceRadiusX"] = node.inputs[2].default_value[0] | |
pbsdf["SubsurfaceRadiusY"] = node.inputs[2].default_value[1] | |
pbsdf["SubsurfaceRadiusZ"] = node.inputs[2].default_value[2] | |
subsurface_color_rgb = [1,1,1] | |
subsurface_color_rgb[0] = node.inputs[3].default_value[0] | |
subsurface_color_rgb[1] = node.inputs[3].default_value[1] | |
subsurface_color_rgb[2] = node.inputs[3].default_value[2] | |
pbsdf["SubsurfaceColorHue"], pbsdf["SubsurfaceColorSaturation"], pbsdf["SubsurfaceColorValue"] = _convert_rgb_to_hsv(*subsurface_color_rgb) | |
pbsdf["SubsurfaceColorAlpha"] = node.inputs[3].default_value[3] | |
pbsdf["Metallic"] = node.inputs[4].default_value | |
pbsdf["Specular"] = node.inputs[5].default_value | |
pbsdf["SpecularTint"] = node.inputs[6].default_value | |
pbsdf["Roughness"] = node.inputs[7].default_value | |
pbsdf["Anisotropic"] = node.inputs[8].default_value | |
pbsdf["AnisotropicRotation"] = node.inputs[9].default_value | |
pbsdf["Sheen"] = node.inputs[10].default_value | |
pbsdf["SheenTint"] = node.inputs[11].default_value | |
pbsdf["Clearcoat"]= node.inputs[12].default_value | |
pbsdf["ClearcoatRoughness"] = node.inputs[13].default_value | |
pbsdf["IndexOfRefraction"] = node.inputs[14].default_value | |
pbsdf["Transmission"] = node.inputs[15].default_value | |
elif node.type == 'CUSTOM' and node.name == 'Principled Volume': | |
volumeNodeCount += 1 | |
pbsdf['HasPBSDFVolume'] = "true" | |
vol_color_rgb = [1,1,1] | |
vol_color_rgb[0] = node.inputs[0].default_value[0] | |
vol_color_rgb[1] = node.inputs[0].default_value[1] | |
vol_color_rgb[2] = node.inputs[0].default_value[2] | |
pbsdf["VolumeColorHue"], pbsdf["VolumeColorSaturation"], pbsdf["VolumeColorValue"] = _convert_rgb_to_hsv(*vol_color_rgb) | |
pbsdf["VolumeColorAlpha"] = node.inputs[0].default_value[3] | |
pbsdf["VolumeDensity"] = node.inputs[2].default_value | |
pbsdf["VolumeAnisotropy"] = node.inputs[4].default_value | |
vol_absorb_rgb = [1,1,1] | |
vol_absorb_rgb[0] = node.inputs[5].default_value[0] | |
vol_absorb_rgb[1] = node.inputs[5].default_value[1] | |
vol_absorb_rgb[2] = node.inputs[5].default_value[2] | |
pbsdf["VolumeAbsorptionColorHue"], pbsdf["VolumeAbsorptionColorSaturation"], pbsdf["VolumeAbsorptionColorValue"] = _convert_rgb_to_hsv(*vol_absorb_rgb) | |
pbsdf["VolumeAbsorptionColorAlpha"] = node.inputs[5].default_value[3] | |
pbsdf["VolumeEmissionStrength"] = node.inputs[6].default_value | |
vol_emiss_rgb = [1,1,1] | |
vol_emiss_rgb[0] = node.inputs[7].default_value[0] | |
vol_emiss_rgb[1] = node.inputs[7].default_value[1] | |
vol_emiss_rgb[2] = node.inputs[7].default_value[2] | |
pbsdf["VolumeEmissionColorHue"], pbsdf["VolumeEmissionColorSaturation"], pbsdf["VolumeEmissionColorValue"] = _convert_rgb_to_hsv(*vol_emiss_rgb) | |
pbsdf["VolumeEmissionColorAlpha"] = node.inputs[7].default_value[3] | |
pbsdf["VolumeBlackbodyIntensity"] = node.inputs[8].default_value | |
vol_bbtint_rgb = [1,1,1] | |
vol_bbtint_rgb[0] = node.inputs[9].default_value[0] | |
vol_bbtint_rgb[1] = node.inputs[9].default_value[1] | |
vol_bbtint_rgb[2] = node.inputs[9].default_value[2] | |
pbsdf["VolumeBlackbodyTintHue"], pbsdf["VolumeBlackbodyTintSaturation"], pbsdf["VolumeBlackbodyTintValue"] = _convert_rgb_to_hsv(*vol_bbtint_rgb) | |
pbsdf["VolumeBlackbodyTintAlpha"] = node.inputs[9].default_value[3] | |
pbsdf["VolumeTemperature"] = node.inputs[10].default_value | |
if principledNodeCount > 1: | |
print("Warning: More than one principled Node for material", mat.name) | |
if volumeNodeCount > 1: | |
print("Warning: More than one volume Node for material", mat.name) | |
if principledNodeCount == 0: | |
return None | |
return pbsdf | |
# test code | |
# exportMaterials(bpy.context.active_object) # exports material(s) for active obj | |
exportMaterials() # exports materials for entire scene |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment