Gorgious very helpfully pointed me towards the API documents I was struggling to find as well as an example script generating node trees in Blender. In essence my question boiled down to "where are the relevant API docs, I can't find them", and they provided exactly that in the comments of my question.
Nodes: https://docs.blender.org/api/current/bpy.types.Node.html
Node Sockets: https://docs.blender.org/api/current/bpy.types.Node.html
Node Types: https://docs.blender.org/api/current/bpy.types.ShaderNode.html
EDIT: I have completed my script and it works! It's not general-purpose so I am hesitant to share it, but here you are. The VMT files can be present anywhere either at the same level or in some subfolder relative to the .blend file. Additionally, you need to have used VTFEdit to batch convert all the texture files (vtf) to PNG's. If you prefer TGA, just edit my script and replace PNG with TGA. Also, the actual Shader node tree is visually a mess, because I didn't do any actual placement of the nodes and they all overlap, so it's very utilitarian.
Currently, I only went for the basic properties, being $basetexture, $bumpmap, and $translucent (which sets the material blend mode to Alpha Blend).
import bpy
import os
source_dir = os.path.dirname(bpy.data.filepath)
for r, d, f in os.walk(source_dir):
for file in f:
if 'vmt' in file:
mat = open(os.path.join(r, file), 'r')
material = {}
material['cancel'] = False
lines = [l.lstrip().rstrip().replace('"', '') for l in mat.readlines()
if 'basetexture' in l or 'bumpmap' in l or 'translucent' in l]
material['alpha'] = False
for l in lines:
if 'translucent' in l :
material['alpha'] = True
else:
img = l.split('/')[-1] + '.png'
found = False
for ro, do, fo in os.walk(source_dir):
for fi in fo:
if img.lower() == fi.lower():
img = os.path.join(ro, fi)
found = True
if 'basetexture' in l:
material['base'] = img
if 'bumpmap' in l:
material['bump'] = img
if found == False:
material['cancel'] = True
mat.close()
if material['cancel'] == False:
# Begin constructing node tree for this material
material_name = file.split('.vmt')[0]
new_mat = bpy.data.materials.get(material_name)
if not new_mat:
new_mat = bpy.data.materials.new(material_name)
if material['alpha'] == True:
new_mat.blend_method = 'BLEND'
new_mat.use_nodes = True
node_tree = new_mat.node_tree
nodes = node_tree.nodes
nodes.clear()
links = node_tree.links
links.clear()
master_node = nodes.new(type='ShaderNodeBsdfPrincipled')
if 'base' in material:
bt_node = nodes.new(type='ShaderNodeTexImage')
bt_node.image = bpy.data.images.load(material['base'])
links.new(master_node.inputs['Base Color'], bt_node.outputs['Color'])
links.new(master_node.inputs['Alpha'], bt_node.outputs['Alpha'])
if 'bump' in material:
bmi_node = nodes.new(type='ShaderNodeTexImage')
bmi_node.image = bpy.data.images.load(material['bump'])
bm_node = nodes.new(type='ShaderNodeBump')
links.new(bm_node.inputs['Height'], bt_node.outputs['Color'])
links.new(master_node.inputs['Normal'], bm_node.outputs['Normal'])
out_node = nodes.new(type='ShaderNodeOutputMaterial')
links.new(master_node.outputs['BSDF'], out_node.inputs[0])
print(dir(obj)). See Nodes, Sockets, and Node Types. You would also have to add images inside the blender memory which is related to another data manager (bpy.data.images). If you would like to throw an example of base file, I can write an answer with more extensive pointers – Gorgious Oct 23 '20 at 07:49"$basetexture" "Sandals_dif"in the VMT means in Blender I would create an image texture, load Sandals_dif.png, and then attach that to the base color in Principled BSDF. I'm already capable of generating code in python, I was just really struggling on finding WHAT to generate, which your example file is a goldmine of info for. Thank you!I will look into the images data manager as well.
– pridestalker Oct 23 '20 at 07:56