WIP: MaterialX addon #104594

Closed
Bogdan Nagirniak wants to merge 34 commits from BogdanNagirniak/blender-addons:materialx-addon into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
26 changed files with 166 additions and 104 deletions
Showing only changes of commit 166cd20e89 - Show all commits

View File

@ -1,7 +0,0 @@
{
"project_id" : "Blender Addons",
"conduit_uri" : "https://developer.blender.org/",
"phabricator.uri" : "https://developer.blender.org/",
"git.default-relative-commit" : "origin/master",
"arc.land.update.default" : "rebase"
}

View File

@ -1,5 +1,4 @@
This repository is only used as a mirror of git.blender.org. Blender development happens on This repository is only used as a mirror. Blender development happens on projects.blender.org.
https://developer.blender.org.
To get started with contributing code, please see: To get started with contributing code, please see:
https://wiki.blender.org/wiki/Process/Contributing_Code https://wiki.blender.org/wiki/Process/Contributing_Code

3
.github/stale.yml vendored
View File

@ -15,8 +15,7 @@ staleLabel: stale
# Comment to post when closing a stale Issue or Pull Request. # Comment to post when closing a stale Issue or Pull Request.
closeComment: > closeComment: >
This issue has been automatically closed, because this repository is only This issue has been automatically closed, because this repository is only
used as a mirror of git.blender.org. Blender development happens on used as a mirror. Blender development happens on projects.blender.org.
developer.blender.org.
To get started contributing code, please read: To get started contributing code, please read:
https://wiki.blender.org/wiki/Process/Contributing_Code https://wiki.blender.org/wiki/Process/Contributing_Code

View File

@ -2,8 +2,8 @@
bl_info = { bl_info = {
"name": "Import Palettes", "name": "Import Palettes",
"author": "Antonio Vazquez", "author": "Antonio Vazquez, Kevin C. Burke (@blastframe)",
"version": (1, 0, 0), "version": (1, 0, 1),
"blender": (2, 81, 6), "blender": (2, 81, 6),
"location": "File > Import", "location": "File > Import",
"description": "Import Palettes", "description": "Import Palettes",

View File

@ -99,16 +99,9 @@ def parse(filename):
return [c for c in parse_chunk(data)] return [c for c in parse_chunk(data)]
def load(context, filepath): def create_color(data):
output = parse(filepath)
(path, filename) = os.path.split(filepath)
pal = None
for elm in output:
valid = False valid = False
data = elm['data']
color = [0, 0, 0] color = [0, 0, 0]
val = data['values'] val = data['values']
@ -128,12 +121,31 @@ def load(context, filepath):
color[1] = (1.0 - val[1]) * (1.0 - val[3]) color[1] = (1.0 - val[1]) * (1.0 - val[3])
color[2] = (1.0 - val[2]) * (1.0 - val[3]) color[2] = (1.0 - val[2]) * (1.0 - val[3])
# Create palette color
if valid: if valid:
return color
def load(context, filepath):
output = parse(filepath)
(path, filename) = os.path.split(filepath)
pal = None
for elm in output:
colors = []
if "data" in elm:
colors.append(create_color(elm['data']))
if "swatches" in elm:
for swatch in elm['swatches']:
colors.append(create_color(swatch["data"]))
# Create Palette # Create Palette
if pal is None: if pal is None:
pal = bpy.data.palettes.new(name=filename) pal = bpy.data.palettes.new(name=filename)
for color in colors:
# Create Color # Create Color
col = pal.colors.new() col = pal.colors.new()
col.color[0] = color[0] col.color[0] = color[0]

View File

@ -43,7 +43,7 @@ bl_info = {
"name": "Atomic Blender PDB/XYZ", "name": "Atomic Blender PDB/XYZ",
"description": "Importing atoms listed in PDB or XYZ files as balls into Blender", "description": "Importing atoms listed in PDB or XYZ files as balls into Blender",
"author": "Clemens Barth", "author": "Clemens Barth",
"version": (1, 8), "version": (1, 8, 1),
"blender": (2, 80, 0), "blender": (2, 80, 0),
"location": "File -> Import -> PDB (.pdb) and File -> Import -> XYZ (.xyz)", "location": "File -> Import -> PDB (.pdb) and File -> Import -> XYZ (.xyz)",
"warning": "", "warning": "",

View File

@ -755,7 +755,8 @@ def draw_sticks_dupliverts(all_atoms,
if use_sticks_color == False: if use_sticks_color == False:
stick_material = bpy.data.materials.new(ELEMENTS[-1].name) stick_material = bpy.data.materials.new(ELEMENTS[-1].name)
stick_material.use_nodes = True stick_material.use_nodes = True
mat_P_BSDF = stick_material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in stick_material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color
# Sort the sticks and put them into a new list such that ... # Sort the sticks and put them into a new list such that ...
@ -1048,7 +1049,8 @@ def draw_sticks_skin(all_atoms,
stick_material = bpy.data.materials.new(ELEMENTS[-1].name) stick_material = bpy.data.materials.new(ELEMENTS[-1].name)
stick_material.use_nodes = True stick_material.use_nodes = True
mat_P_BSDF = stick_material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in stick_material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color
new_stick_mesh.active_material = stick_material new_stick_mesh.active_material = stick_material
@ -1105,7 +1107,8 @@ def draw_sticks_normal(all_atoms,
stick_material = bpy.data.materials.new(ELEMENTS[-1].name) stick_material = bpy.data.materials.new(ELEMENTS[-1].name)
stick_material.use_nodes = True stick_material.use_nodes = True
mat_P_BSDF = stick_material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in stick_material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color mat_P_BSDF.inputs['Base Color'].default_value = ELEMENTS[-1].color
up_axis = Vector([0.0, 0.0, 1.0]) up_axis = Vector([0.0, 0.0, 1.0])
@ -1332,7 +1335,8 @@ def import_pdb(Ball_type,
material = bpy.data.materials.new(atom_type[1]) material = bpy.data.materials.new(atom_type[1])
material.diffuse_color = atom_type[2] material.diffuse_color = atom_type[2]
material.use_nodes = True material.use_nodes = True
mat_P_BSDF = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = atom_type[2] mat_P_BSDF.inputs['Base Color'].default_value = atom_type[2]
material.name = atom_type[0] material.name = atom_type[0]
atom_material_list.append(material) atom_material_list.append(material)
@ -1350,7 +1354,8 @@ def import_pdb(Ball_type,
if atom.name == "Vacancy": if atom.name == "Vacancy":
# For cycles and eevee. # For cycles and eevee.
material.use_nodes = True material.use_nodes = True
mat_P_BSDF = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Metallic'].default_value = 0.1 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
mat_P_BSDF.inputs['Specular'].default_value = 0.15 mat_P_BSDF.inputs['Specular'].default_value = 0.15
mat_P_BSDF.inputs['Roughness'].default_value = 0.05 mat_P_BSDF.inputs['Roughness'].default_value = 0.05

View File

@ -493,7 +493,8 @@ def modify_objects(action_type,
else: else:
new_material = draw_obj_material('1', atom.active_material) new_material = draw_obj_material('1', atom.active_material)
# Assign now the correct color. # Assign now the correct color.
mat_P_BSDF = new_material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in new_material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = element.color mat_P_BSDF.inputs['Base Color'].default_value = element.color
new_material.name = element.name + "_normal" new_material.name = element.name + "_normal"
@ -580,7 +581,8 @@ def separate_atoms(scn):
# Prepare a new material # Prepare a new material
def draw_obj_material(material_type, material): def draw_obj_material(material_type, material):
mat_P_BSDF_default = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF_default = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
default_color = mat_P_BSDF_default.inputs['Base Color'].default_value default_color = mat_P_BSDF_default.inputs['Base Color'].default_value
if material_type == '0': # Unchanged if material_type == '0': # Unchanged
@ -591,7 +593,8 @@ def draw_obj_material(material_type, material):
# user's work in Blender ... . # user's work in Blender ... .
material_new = bpy.data.materials.new(material.name + "_normal") material_new = bpy.data.materials.new(material.name + "_normal")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = default_color mat_P_BSDF.inputs['Base Color'].default_value = default_color
mat_P_BSDF.inputs['Metallic'].default_value = 0.0 mat_P_BSDF.inputs['Metallic'].default_value = 0.0
mat_P_BSDF.inputs['Specular'].default_value = 0.5 mat_P_BSDF.inputs['Specular'].default_value = 0.5
@ -607,7 +610,8 @@ def draw_obj_material(material_type, material):
if material_type == '2': # Transparent if material_type == '2': # Transparent
material_new = bpy.data.materials.new(material.name + "_transparent") material_new = bpy.data.materials.new(material.name + "_transparent")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = default_color mat_P_BSDF.inputs['Base Color'].default_value = default_color
mat_P_BSDF.inputs['Metallic'].default_value = 0.0 mat_P_BSDF.inputs['Metallic'].default_value = 0.0
mat_P_BSDF.inputs['Specular'].default_value = 0.15 mat_P_BSDF.inputs['Specular'].default_value = 0.15
@ -624,7 +628,8 @@ def draw_obj_material(material_type, material):
if material_type == '3': # Reflecting if material_type == '3': # Reflecting
material_new = bpy.data.materials.new(material.name + "_reflecting") material_new = bpy.data.materials.new(material.name + "_reflecting")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = default_color mat_P_BSDF.inputs['Base Color'].default_value = default_color
mat_P_BSDF.inputs['Metallic'].default_value = 0.7 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
mat_P_BSDF.inputs['Specular'].default_value = 0.15 mat_P_BSDF.inputs['Specular'].default_value = 0.15
@ -640,7 +645,8 @@ def draw_obj_material(material_type, material):
if material_type == '4': # Transparent + reflecting if material_type == '4': # Transparent + reflecting
material_new = bpy.data.materials.new(material.name + "_trans+refl") material_new = bpy.data.materials.new(material.name + "_trans+refl")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = default_color mat_P_BSDF.inputs['Base Color'].default_value = default_color
mat_P_BSDF.inputs['Metallic'].default_value = 0.5 mat_P_BSDF.inputs['Metallic'].default_value = 0.5
mat_P_BSDF.inputs['Specular'].default_value = 0.15 mat_P_BSDF.inputs['Specular'].default_value = 0.15
@ -933,7 +939,8 @@ def draw_obj_special(atom_shape, atom):
# Get the color of the selected atom. # Get the color of the selected atom.
material = atom.active_material material = atom.active_material
mat_P_BSDF_default = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF_default = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
default_color = mat_P_BSDF_default.inputs['Base Color'].default_value default_color = mat_P_BSDF_default.inputs['Base Color'].default_value
# Create first a cube # Create first a cube
@ -952,7 +959,8 @@ def draw_obj_special(atom_shape, atom):
# New material for this cube # New material for this cube
material_new = bpy.data.materials.new(atom.name + "_F2+_vac") material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = default_color mat_P_BSDF.inputs['Base Color'].default_value = default_color
mat_P_BSDF.inputs['Metallic'].default_value = 0.7 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
mat_P_BSDF.inputs['Specular'].default_value = 0.0 mat_P_BSDF.inputs['Specular'].default_value = 0.0
@ -1008,7 +1016,8 @@ def draw_obj_special(atom_shape, atom):
# New material for this cube # New material for this cube
material_new = bpy.data.materials.new(atom.name + "_F2+_vac") material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0] mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
mat_P_BSDF.inputs['Metallic'].default_value = 0.7 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
mat_P_BSDF.inputs['Specular'].default_value = 0.0 mat_P_BSDF.inputs['Specular'].default_value = 0.0
@ -1038,7 +1047,8 @@ def draw_obj_special(atom_shape, atom):
# New material for the electron # New material for the electron
material_electron = bpy.data.materials.new(atom.name + "_F+-center") material_electron = bpy.data.materials.new(atom.name + "_F+-center")
material_electron.use_nodes = True material_electron.use_nodes = True
mat_P_BSDF = material_electron.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_electron.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0] mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
mat_P_BSDF.inputs['Metallic'].default_value = 0.8 mat_P_BSDF.inputs['Metallic'].default_value = 0.8
mat_P_BSDF.inputs['Specular'].default_value = 0.0 mat_P_BSDF.inputs['Specular'].default_value = 0.0
@ -1097,7 +1107,8 @@ def draw_obj_special(atom_shape, atom):
# New material for this cube # New material for this cube
material_new = bpy.data.materials.new(atom.name + "_F2+_vac") material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
material_new.use_nodes = True material_new.use_nodes = True
mat_P_BSDF = material_new.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_new.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = [0.8, 0.0, 0.0, 1.0] mat_P_BSDF.inputs['Base Color'].default_value = [0.8, 0.0, 0.0, 1.0]
mat_P_BSDF.inputs['Metallic'].default_value = 0.7 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
mat_P_BSDF.inputs['Specular'].default_value = 0.0 mat_P_BSDF.inputs['Specular'].default_value = 0.0
@ -1136,7 +1147,8 @@ def draw_obj_special(atom_shape, atom):
# Create a new material for the two electrons. # Create a new material for the two electrons.
material_electron = bpy.data.materials.new(atom.name + "_F0-center") material_electron = bpy.data.materials.new(atom.name + "_F0-center")
material_electron.use_nodes = True material_electron.use_nodes = True
mat_P_BSDF = material_electron.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material_electron.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0] mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
mat_P_BSDF.inputs['Metallic'].default_value = 0.8 mat_P_BSDF.inputs['Metallic'].default_value = 0.8
mat_P_BSDF.inputs['Specular'].default_value = 0.0 mat_P_BSDF.inputs['Specular'].default_value = 0.0
@ -1263,7 +1275,8 @@ def custom_datafile_change_atom_props():
if FLAG: if FLAG:
obj.scale = (e.radii[0],) * 3 obj.scale = (e.radii[0],) * 3
mat = obj.active_material mat = obj.active_material
mat_P_BSDF = mat.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in mat.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = e.color mat_P_BSDF.inputs['Base Color'].default_value = e.color
mat_P_BSDF.subsurface_method = e.mat_P_BSDF.Subsurface_method mat_P_BSDF.subsurface_method = e.mat_P_BSDF.Subsurface_method

View File

@ -472,7 +472,8 @@ def import_xyz(Ball_type,
material = bpy.data.materials.new(atom.name) material = bpy.data.materials.new(atom.name)
material.diffuse_color = atom.color material.diffuse_color = atom.color
material.use_nodes = True material.use_nodes = True
mat_P_BSDF = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Base Color'].default_value = atom.color mat_P_BSDF.inputs['Base Color'].default_value = atom.color
material.name = atom.name material.name = atom.name
atom_material_list.append(material) atom_material_list.append(material)
@ -491,7 +492,8 @@ def import_xyz(Ball_type,
if atom.name == "Vacancy": if atom.name == "Vacancy":
# For cycles and eevee. # For cycles and eevee.
material.use_nodes = True material.use_nodes = True
mat_P_BSDF = material.node_tree.nodes['Principled BSDF'] mat_P_BSDF = next(n for n in material.node_tree.nodes
if n.type == "BSDF_PRINCIPLED")
mat_P_BSDF.inputs['Metallic'].default_value = 0.1 mat_P_BSDF.inputs['Metallic'].default_value = 0.1
mat_P_BSDF.inputs['Specular'].default_value = 0.15 mat_P_BSDF.inputs['Specular'].default_value = 0.15
mat_P_BSDF.inputs['Roughness'].default_value = 0.05 mat_P_BSDF.inputs['Roughness'].default_value = 0.05

View File

@ -3,7 +3,7 @@
bl_info = { bl_info = {
"name": "FBX format", "name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier",
"version": (4, 37, 4), "version": (4, 37, 5),
"blender": (3, 4, 0), "blender": (3, 4, 0),
"location": "File > Import-Export", "location": "File > Import-Export",
"description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions", "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions",
@ -80,7 +80,7 @@ class ImportFBX(bpy.types.Operator, ImportHelper):
name="Apply Transform", name="Apply Transform",
description="Bake space transform into object data, avoids getting unwanted rotations to objects when " description="Bake space transform into object data, avoids getting unwanted rotations to objects when "
"target space is not aligned with Blender's space " "target space is not aligned with Blender's space "
"(WARNING! experimental option, use at own risks, known broken with armatures/animations)", "(WARNING! experimental option, use at own risk, known to be broken with armatures/animations)",
default=False, default=False,
) )
@ -434,7 +434,7 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
name="Apply Transform", name="Apply Transform",
description="Bake space transform into object data, avoids getting unwanted rotations to objects when " description="Bake space transform into object data, avoids getting unwanted rotations to objects when "
"target space is not aligned with Blender's space " "target space is not aligned with Blender's space "
"(WARNING! experimental option, use at own risks, known broken with armatures/animations)", "(WARNING! experimental option, use at own risk, known to be broken with armatures/animations)",
default=False, default=False,
) )
@ -549,8 +549,8 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
('LIMBNODE', "LimbNode", "'LimbNode' FBX node, a regular joint between two bones..."), ('LIMBNODE', "LimbNode", "'LimbNode' FBX node, a regular joint between two bones..."),
), ),
description="FBX type of node (object) used to represent Blender's armatures " description="FBX type of node (object) used to represent Blender's armatures "
"(use Null one unless you experience issues with other app, other choices may no import back " "(use the Null type unless you experience issues with the other app, "
"perfectly in Blender...)", "as other choices may not import back perfectly into Blender...)",
default='NULL', default='NULL',
) )
bake_anim: BoolProperty( bake_anim: BoolProperty(

View File

@ -3154,7 +3154,7 @@ def load(operator, context, filepath="",
# Intensity actually, not color... # Intensity actually, not color...
ma_wrap.metallic_texture.image = image ma_wrap.metallic_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.metallic_texture) texture_mapping_set(fbx_lnk, ma_wrap.metallic_texture)
elif lnk_type in {b'TransparentColor', b'TransparentFactor'}: elif lnk_type in {b'TransparentColor', b'TransparencyFactor'}:
ma_wrap.alpha_texture.image = image ma_wrap.alpha_texture.image = image
texture_mapping_set(fbx_lnk, ma_wrap.alpha_texture) texture_mapping_set(fbx_lnk, ma_wrap.alpha_texture)
if use_alpha_decals: if use_alpha_decals:

View File

@ -4,8 +4,8 @@
bl_info = { bl_info = {
'name': 'glTF 2.0 format', 'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors', 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (3, 5, 21), "version": (3, 6, 0),
'blender': (3, 4, 0), 'blender': (3, 5, 0),
'location': 'File > Import-Export', 'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0', 'description': 'Import-Export as glTF 2.0',
'warning': '', 'warning': '',
@ -97,6 +97,11 @@ def on_export_format_changed(self, context):
self.export_format, self.export_format,
) )
# Also change the filter
sfile.params.filter_glob = '*.glb' if self.export_format == 'GLB' else '*.gltf'
# Force update of file list, has update the filter does not update the real file list
bpy.ops.file.refresh()
class ConvertGLTF2_Base: class ConvertGLTF2_Base:
"""Base class containing options that should be exposed during both import and export.""" """Base class containing options that should be exposed during both import and export."""
@ -146,7 +151,7 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
'Output format and embedding options. Binary is most efficient, ' 'Output format and embedding options. Binary is most efficient, '
'but JSON (embedded or separate) may be easier to edit later' 'but JSON (embedded or separate) may be easier to edit later'
), ),
default='GLB', default='GLB', #Warning => If you change the default, need to change the default filter too
update=on_export_format_changed, update=on_export_format_changed,
) )
@ -441,7 +446,7 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
export_optimize_animation_size: BoolProperty( export_optimize_animation_size: BoolProperty(
name='Optimize Animation Size', name='Optimize Animation Size',
description=( description=(
"Reduce exported file-size by removing duplicate keyframes" "Reduce exported file size by removing duplicate keyframes "
"(can cause problems with stepped animation)" "(can cause problems with stepped animation)"
), ),
default=False default=False
@ -1158,7 +1163,7 @@ class ExportGLTF2(bpy.types.Operator, ExportGLTF2_Base, ExportHelper):
filename_ext = '' filename_ext = ''
filter_glob: StringProperty(default='*.glb;*.gltf', options={'HIDDEN'}) filter_glob: StringProperty(default='*.glb', options={'HIDDEN'})
def menu_func_export(self, context): def menu_func_export(self, context):

View File

@ -6,6 +6,7 @@ from mathutils import Vector
from . import gltf2_blender_export_keys from . import gltf2_blender_export_keys
from ...io.com.gltf2_io_debug import print_console from ...io.com.gltf2_io_debug import print_console
from ...io.com.gltf2_io_constants import NORMALS_ROUNDING_DIGIT
from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins from io_scene_gltf2.blender.exp import gltf2_blender_gather_skins
from io_scene_gltf2.io.com import gltf2_io_constants from io_scene_gltf2.io.com import gltf2_io_constants
from io_scene_gltf2.blender.com import gltf2_blender_conversion from io_scene_gltf2.blender.com import gltf2_blender_conversion
@ -699,10 +700,13 @@ class PrimitiveCreator:
self.normals = self.normals.reshape(len(self.blender_mesh.loops), 3) self.normals = self.normals.reshape(len(self.blender_mesh.loops), 3)
self.normals = np.round(self.normals, NORMALS_ROUNDING_DIGIT)
self.morph_normals = [] self.morph_normals = []
for key_block in key_blocks: for key_block in key_blocks:
ns = np.array(key_block.normals_split_get(), dtype=np.float32) ns = np.array(key_block.normals_split_get(), dtype=np.float32)
ns = ns.reshape(len(self.blender_mesh.loops), 3) ns = ns.reshape(len(self.blender_mesh.loops), 3)
ns = np.round(ns, NORMALS_ROUNDING_DIGIT)
self.morph_normals.append(ns) self.morph_normals.append(ns)
# Transform for skinning # Transform for skinning

View File

@ -86,10 +86,16 @@ def __gather_wrap(blender_shader_node, export_settings):
elif blender_shader_node.extension == 'CLIP': elif blender_shader_node.extension == 'CLIP':
# Not possible in glTF, but ClampToEdge is closest # Not possible in glTF, but ClampToEdge is closest
wrap_s = TextureWrap.ClampToEdge wrap_s = TextureWrap.ClampToEdge
elif blender_shader_node.extension == 'MIRROR':
wrap_s = TextureWrap.MirroredRepeat
else: else:
wrap_s = TextureWrap.Repeat wrap_s = TextureWrap.Repeat
wrap_t = wrap_s wrap_t = wrap_s
# Starting Blender 3.5, MIRROR is now an extension of image node
# So this manual uv wrapping trick is no more usefull for MIRROR x MIRROR
# But still works for old files
# Still needed for heterogen heterogeneous sampler, like MIRROR x REPEAT, for example
# Take manual wrapping into account # Take manual wrapping into account
result = detect_manual_uv_wrapping(blender_shader_node) result = detect_manual_uv_wrapping(blender_shader_node)
if result: if result:

View File

@ -169,7 +169,7 @@ def __gather_texture_transform_and_tex_coord(primary_socket, export_settings):
node_tree = node.id_data node_tree = node.id_data
for mesh in bpy.data.meshes: for mesh in bpy.data.meshes:
for material in mesh.materials: for material in mesh.materials:
if material.node_tree == node_tree: if material and material.node_tree == node_tree:
i = mesh.uv_layers.find(node.uv_map) i = mesh.uv_layers.find(node.uv_map)
if i >= 0: if i >= 0:
texcoord_idx = i texcoord_idx = i

View File

@ -171,8 +171,8 @@ class VExportTree:
# If object is parented to bone, and Rest pose is used, we need to keep the world matrix # If object is parented to bone, and Rest pose is used, we need to keep the world matrix
# Of the rest pose, not the current world matrix # Of the rest pose, not the current world matrix
if parent_uuid and self.nodes[parent_uuid].blender_type == VExportNode.BONE and self.export_settings['gltf_current_frame'] is False: if parent_uuid and self.nodes[parent_uuid].blender_type == VExportNode.BONE and self.export_settings['gltf_current_frame'] is False:
blender_bone = self.nodes[parent_uuid].blender_bone _blender_bone = self.nodes[parent_uuid].blender_bone
node.matrix_world = (blender_bone.matrix @ blender_bone.bone.matrix_local.inverted_safe()).inverted_safe() @ node.matrix_world node.matrix_world = (_blender_bone.matrix @ _blender_bone.bone.matrix_local.inverted_safe()).inverted_safe() @ node.matrix_world
if node.blender_type == VExportNode.CAMERA and self.export_settings[gltf2_blender_export_keys.CAMERAS]: if node.blender_type == VExportNode.CAMERA and self.export_settings[gltf2_blender_export_keys.CAMERAS]:
if self.export_settings[gltf2_blender_export_keys.YUP]: if self.export_settings[gltf2_blender_export_keys.YUP]:

View File

@ -309,7 +309,11 @@ class GlTF2Exporter:
return image return image
# extensions # extensions
if isinstance(node, gltf2_io_extensions.Extension): # I don't know why, but after reloading script, this condition failed
# So using name comparison, instead of isinstance
# if isinstance(node, gltf2_io_extensions.Extension):
if isinstance(node, gltf2_io_extensions.Extension) \
or (node and hasattr(type(node), "extension")):
extension = self.__traverse(node.extension) extension = self.__traverse(node.extension)
self.__append_unique_and_get_index(self.__gltf.extensions_used, node.name) self.__append_unique_and_get_index(self.__gltf.extensions_used, node.name)
if node.required: if node.required:

View File

@ -69,11 +69,13 @@ def texture(
wrap_s = TextureWrap.Repeat wrap_s = TextureWrap.Repeat
if wrap_t is None: if wrap_t is None:
wrap_t = TextureWrap.Repeat wrap_t = TextureWrap.Repeat
# If wrapping is REPEATxREPEAT or CLAMPxCLAMP, just set tex_img.extension # If wrapping is the same in both directions, just set tex_img.extension
if (wrap_s, wrap_t) == (TextureWrap.Repeat, TextureWrap.Repeat): if wrap_s == wrap_t == TextureWrap.Repeat:
tex_img.extension = 'REPEAT' tex_img.extension = 'REPEAT'
elif (wrap_s, wrap_t) == (TextureWrap.ClampToEdge, TextureWrap.ClampToEdge): elif wrap_s == wrap_t == TextureWrap.ClampToEdge:
tex_img.extension = 'EXTEND' tex_img.extension = 'EXTEND'
elif wrap_s == wrap_t == TextureWrap.MirroredRepeat:
tex_img.extension = 'MIRROR'
else: else:
# Otherwise separate the UV components and use math nodes to compute # Otherwise separate the UV components and use math nodes to compute
# the wrapped UV coordinates # the wrapped UV coordinates

View File

@ -150,3 +150,6 @@ GLTF_DATA_TYPE_MAT3 = "MAT3"
GLTF_DATA_TYPE_MAT4 = "MAT4" GLTF_DATA_TYPE_MAT4 = "MAT4"
GLTF_IOR = 1.5 GLTF_IOR = 1.5
# Rounding digit used for normal rounding
NORMALS_ROUNDING_DIGIT = 4

View File

@ -6,6 +6,8 @@ from typing import List, Dict, Any
class Extension: class Extension:
"""Container for extensions. Allows to specify requiredness""" """Container for extensions. Allows to specify requiredness"""
extension = True # class method used to check Extension class at traversal (after reloading script, isinstance is not working)
def __init__(self, name: str, extension: Dict[str, Any], required: bool = True): def __init__(self, name: str, extension: Dict[str, Any], required: bool = True):
self.name = name self.name = name
self.extension = extension self.extension = extension

View File

@ -449,7 +449,8 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
# assign image # assign image
if compat.check_version(2, 80, 0) >= 0: if compat.check_version(2, 80, 0) >= 0:
node_tree = obj.active_material.node_tree node_tree = obj.active_material.node_tree
output_node = node_tree.nodes["Material Output"] output_node = next(n for n in node_tree.nodes
if n.type == "OUTPUT_MATERIAL")
nodes = common.find_texture_nodes_from_material( nodes = common.find_texture_nodes_from_material(
obj.active_material) obj.active_material)

View File

@ -447,7 +447,8 @@ class MUV_OT_UVInspection_PaintUVIsland(bpy.types.Operator):
"MagicUV_PaintUVMaterial_{}".format(i)) "MagicUV_PaintUVMaterial_{}".format(i))
if compat.check_version(2, 80, 0) >= 0: if compat.check_version(2, 80, 0) >= 0:
target_mtrl.use_nodes = True target_mtrl.use_nodes = True
output_node = target_mtrl.node_tree.nodes["Material Output"] output_node = next(n for n in target_mtrl.node_tree.nodes
if n.type == "OUTPUT_MATERIAL")
nodes_to_remove = [n for n in target_mtrl.node_tree.nodes nodes_to_remove = [n for n in target_mtrl.node_tree.nodes
if n != output_node] if n != output_node]
for n in nodes_to_remove: for n in nodes_to_remove:

View File

@ -2,7 +2,7 @@
bl_info = { bl_info = {
"name": "Rigify", "name": "Rigify",
"version": (0, 6, 6), "version": (0, 6, 7),
"author": "Nathan Vegdahl, Lucio Rossi, Ivan Cappiello, Alexander Gavrilov", # noqa "author": "Nathan Vegdahl, Lucio Rossi, Ivan Cappiello, Alexander Gavrilov", # noqa
"blender": (3, 0, 0), "blender": (3, 0, 0),
"description": "Automatic rigging from building-block components", "description": "Automatic rigging from building-block components",

View File

@ -720,17 +720,17 @@ class MESH_MT_CopyFaceSettings(Menu):
layout = self.layout layout = self.layout
op = layout.operator(mesh.copy_face_settings, text="Copy Material") op = layout.operator("mesh.copy_face_settings", text="Copy Material")
op['layer'] = '' op['layer'] = ''
op['mode'] = 'MAT' op['mode'] = 'MAT'
if mesh.uv_layers.active: if mesh.uv_layers.active:
op = layout.operator(mesh.copy_face_settings, text="Copy Active UV Coords") op = layout.operator("mesh.copy_face_settings", text="Copy Active UV Coords")
op['layer'] = '' op['layer'] = ''
op['mode'] = 'UV' op['mode'] = 'UV'
if mesh.vertex_colors.active: if mesh.vertex_colors.active:
op = layout.operator(mesh.copy_face_settings, text="Copy Active Vertex Colors") op = layout.operator("mesh.copy_face_settings", text="Copy Active Vertex Colors")
op['layer'] = '' op['layer'] = ''
op['mode'] = 'VCOL' op['mode'] = 'VCOL'
@ -783,7 +783,7 @@ def _buildmenu(self, mesh, mode, icon):
layers = mesh.uv_layers layers = mesh.uv_layers
for layer in layers: for layer in layers:
if not layer.active: if not layer.active:
op = layout.operator(mesh.copy_face_settings, op = layout.operator("mesh.copy_face_settings",
text=layer.name, icon=icon) text=layer.name, icon=icon)
op['layer'] = layer.name op['layer'] = layer.name
op['mode'] = mode op['mode'] = mode

View File

@ -16,7 +16,7 @@
bl_info = { bl_info = {
"name": "Sun Position", "name": "Sun Position",
"author": "Michael Martin", "author": "Michael Martin",
"version": (3, 2, 0), "version": (3, 2, 2),
"blender": (3, 0, 0), "blender": (3, 0, 0),
"location": "World > Sun Position", "location": "World > Sun Position",
"description": "Show sun position with objects and/or sky texture", "description": "Show sun position with objects and/or sky texture",

View File

@ -11,14 +11,23 @@ if bpy.app.background: # ignore north line in background mode
def north_update(self, context): def north_update(self, context):
pass pass
else: else:
vertex_shader = ''' shader_interface = gpu.types.GPUStageInterfaceInfo("my_interface")
uniform mat4 u_ViewProjectionMatrix; shader_interface.flat('VEC2', "v_StartPos")
shader_interface.smooth('VEC4', "v_VertPos")
in vec3 position; shader_info = gpu.types.GPUShaderCreateInfo()
shader_info.push_constant('MAT4', "u_ViewProjectionMatrix")
flat out vec2 v_StartPos; shader_info.push_constant('VEC4', "u_Color")
out vec4 v_VertPos; shader_info.push_constant('VEC2', "u_Resolution")
shader_info.vertex_in(0, 'VEC3', "position")
shader_info.vertex_out(shader_interface)
shader_info.vertex_source(
# uniform mat4 u_ViewProjectionMatrix;
# in vec3 position;
# flat out vec2 v_StartPos;
# out vec4 v_VertPos;
'''
void main() void main()
{ {
vec4 pos = u_ViewProjectionMatrix * vec4(position, 1.0f); vec4 pos = u_ViewProjectionMatrix * vec4(position, 1.0f);
@ -27,16 +36,16 @@ else:
v_VertPos = pos; v_VertPos = pos;
} }
''' '''
)
fragment_shader = ''' shader_info.fragment_out(0, 'VEC4', "FragColor")
uniform vec4 u_Color; shader_info.fragment_source(
# uniform vec4 u_Color;
flat in vec2 v_StartPos; # uniform vec2 u_Resolution;
in vec4 v_VertPos; # flat in vec2 v_StartPos;
out vec4 FragColor; # in vec4 v_VertPos;
# out vec4 FragColor;
uniform vec2 u_Resolution; '''
void main() void main()
{ {
vec4 vertPos_2d = v_VertPos / v_VertPos.w; vec4 vertPos_2d = v_VertPos / v_VertPos.w;
@ -48,8 +57,11 @@ else:
FragColor = u_Color; FragColor = u_Color;
} }
''' '''
)
shader = gpu.types.GPUShader(vertex_shader, fragment_shader) shader = gpu.shader.create_from_info(shader_info)
del shader_info
del shader_interface
def draw_north_callback(): def draw_north_callback():
""" """
@ -77,7 +89,6 @@ else:
batch.draw(shader) batch.draw(shader)
gpu.state.line_width_set(width) gpu.state.line_width_set(width)
_north_handle = None _north_handle = None
def north_update(self, context): def north_update(self, context):