framework/cg/blender/texturing/shading.py
2023-12-01 11:34:37 +03:00

129 lines
5.4 KiB
Python

# coding: utf-8
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@yandex.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
'''
DESCRIPTION.
Set up materials.
'''
__version__ = '0.1'
import logging
import os
import random
import bpy
logger = logging.getLogger(__name__)
def assign_pbr_material(obj_names, textures_path):
''' Assign material with PBR textures pack. '''
textures = sorted(os.listdir(textures_path))
for obj_name in obj_names:
part_name = obj_name.rpartition('_')[0]
obj = bpy.data.objects[obj_name]
if len(obj.material_slots) > 0:
# should be only one material so clear all exist slots
obj.data.materials.clear()
if part_name in bpy.data.materials:
# if material is already in scene
obj.data.materials.append(bpy.data.materials[part_name])
continue
# create Principled BSDF based material
bmat = bpy.data.materials.new(name=f'M_{part_name}')
bmat.use_nodes = True
principled_node = bmat.node_tree.nodes["Principled BSDF"]
random_color = (
round(random.uniform(0.1, 0.9), 3),
round(random.uniform(0.1, 0.9), 3),
round(random.uniform(0.1, 0.9), 3),
1.0)
bmat.diffuse_color = random_color
principled_node.inputs['Base Color'].default_value = random_color
for texture in textures:
if not texture.startswith('T_' + part_name):
continue
if '_ao.' in texture:
image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
image_obj.colorspace_settings.name = 'Linear'
texture_ao = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
texture_ao.name = texture_ao.label = 'ambient_occlusion'
texture_ao.location = -1000, 500
texture_ao.image = bpy.data.images[image_obj.name]
mix_node = bmat.node_tree.nodes.new(type="ShaderNodeMix")
mix_node.location = -500, 500
mix_node.data_type = 'RGBA'
mix_node.blend_type = 'MULTIPLY'
mix_node.inputs['Factor'].default_value = 0.5
bmat.node_tree.links.new(texture_ao.outputs['Color'], mix_node.inputs[7])
bmat.node_tree.links.new(mix_node.outputs[2], principled_node.inputs['Base Color'])
if '_d.' in texture:
image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
image_obj.colorspace_settings.name = 'sRGB'
texture_d = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
texture_d.name = texture_d.label = 'diffuse'
texture_d.location = -1000, 0
texture_d.image = bpy.data.images[image_obj.name]
if texture_ao:
bmat.node_tree.links.new(texture_d.outputs['Color'], mix_node.inputs[6])
else:
bmat.node_tree.links.new(texture_d.outputs['Color'], principled_node.inputs['Base Color'])
if '_m.' in texture:
image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
image_obj.colorspace_settings.name = 'Linear'
texture_m = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
texture_m.name = texture_m.label = 'metallic'
texture_m.location = -1000, -500
texture_m.image = bpy.data.images[image_obj.name]
bmat.node_tree.links.new(texture_m.outputs['Color'], principled_node.inputs['Metallic'])
if '_r.' in texture:
image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
image_obj.colorspace_settings.name = 'Linear'
texture_r = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
texture_r.name = texture_r.label = 'roughness'
texture_r.location = -1000, -1000
texture_r.image = bpy.data.images[image_obj.name]
bmat.node_tree.links.new(texture_r.outputs['Color'], principled_node.inputs['Roughness'])
if '_n.' in texture:
image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
image_obj.colorspace_settings.name = 'Non-Color'
texture_n = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
texture_n.name = texture_n.label = 'normal'
texture_n.location = -1000, -1500
texture_n.image = bpy.data.images[image_obj.name]
normal_node = bmat.node_tree.nodes.new(type="ShaderNodeNormalMap")
normal_node.location = -500, -1500
bmat.node_tree.links.new(texture_n.outputs['Color'], normal_node.inputs['Color'])
bmat.node_tree.links.new(normal_node.outputs['Normal'], principled_node.inputs['Normal'])
obj.data.materials.append(bmat)
logger.info('Shading of %s objects is finished!', len(obj_names))
return True