New Addon: Import Autodesk .max #105013
@ -5,8 +5,8 @@
|
||||
bl_info = {
|
||||
"name": "Add Camera Rigs",
|
||||
"author": "Wayne Dixon, Brian Raschko, Kris Wittig, Damien Picard, Flavio Perez",
|
||||
"version": (1, 5, 1),
|
||||
"blender": (3, 3, 0),
|
||||
"version": (1, 6, 0),
|
||||
"blender": (4, 0, 0),
|
||||
"location": "View3D > Add > Camera > Dolly or Crane Rig",
|
||||
"description": "Adds a Camera Rig with UI",
|
||||
"doc_url": "{BLENDER_MANUAL_URL}/addons/camera/camera_rigs.html",
|
||||
|
@ -36,26 +36,35 @@ def create_dolly_bones(rig):
|
||||
root = bones.new("Root")
|
||||
root.tail = (0.0, 1.0, 0.0)
|
||||
root.show_wire = True
|
||||
rig.data.collections.new(name="Controls")
|
||||
rig.data.collections['Controls'].assign(root)
|
||||
|
||||
ctrl_aim_child = bones.new("Aim_shape_rotation-MCH")
|
||||
ctrl_aim_child = bones.new("MCH-Aim_shape_rotation")
|
||||
ctrl_aim_child.head = (0.0, 10.0, 1.7)
|
||||
ctrl_aim_child.tail = (0.0, 11.0, 1.7)
|
||||
ctrl_aim_child.layers = tuple(i == 1 for i in range(32))
|
||||
# Create bone collection and assign bone
|
||||
rig.data.collections.new(name="MCH")
|
||||
rig.data.collections['MCH'].assign(ctrl_aim_child)
|
||||
rig.data.collections['MCH'].is_visible = False
|
||||
|
||||
ctrl_aim = bones.new("Aim")
|
||||
ctrl_aim.head = (0.0, 10.0, 1.7)
|
||||
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
||||
ctrl_aim.show_wire = True
|
||||
rig.data.collections['Controls'].assign(ctrl_aim)
|
||||
|
||||
ctrl = bones.new("Camera")
|
||||
ctrl.head = (0.0, 0.0, 1.7)
|
||||
ctrl.tail = (0.0, 1.0, 1.7)
|
||||
ctrl.show_wire = True
|
||||
rig.data.collections['Controls'].assign(ctrl)
|
||||
|
||||
ctrl_offset = bones.new("Camera_offset")
|
||||
ctrl_offset = bones.new("Camera_Offset")
|
||||
ctrl_offset.head = (0.0, 0.0, 1.7)
|
||||
ctrl_offset.tail = (0.0, 1.0, 1.7)
|
||||
ctrl_offset.show_wire = True
|
||||
rig.data.collections['Controls'].assign(ctrl_offset)
|
||||
|
||||
|
||||
# Setup hierarchy
|
||||
ctrl.parent = root
|
||||
@ -67,7 +76,7 @@ def create_dolly_bones(rig):
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pose_bones = rig.pose.bones
|
||||
# Lock the relevant scale channels of the Camera_offset bone
|
||||
pose_bones["Camera_offset"].lock_scale = (True,) * 3
|
||||
pose_bones["Camera_Offset"].lock_scale = (True,) * 3
|
||||
|
||||
|
||||
def create_crane_bones(rig):
|
||||
@ -78,42 +87,51 @@ def create_crane_bones(rig):
|
||||
root = bones.new("Root")
|
||||
root.tail = (0.0, 1.0, 0.0)
|
||||
root.show_wire = True
|
||||
rig.data.collections.new(name="Controls")
|
||||
rig.data.collections['Controls'].assign(root)
|
||||
|
||||
ctrl_aim_child = bones.new("Aim_shape_rotation-MCH")
|
||||
ctrl_aim_child = bones.new("MCH-Aim_shape_rotation")
|
||||
ctrl_aim_child.head = (0.0, 10.0, 1.7)
|
||||
ctrl_aim_child.tail = (0.0, 11.0, 1.7)
|
||||
ctrl_aim_child.layers = tuple(i == 1 for i in range(32))
|
||||
rig.data.collections.new(name="MCH")
|
||||
rig.data.collections['MCH'].assign(ctrl_aim_child)
|
||||
rig.data.collections['MCH'].is_visible = False
|
||||
|
||||
ctrl_aim = bones.new("Aim")
|
||||
ctrl_aim.head = (0.0, 10.0, 1.7)
|
||||
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
||||
ctrl_aim.show_wire = True
|
||||
rig.data.collections['Controls'].assign(ctrl_aim)
|
||||
|
||||
ctrl = bones.new("Camera")
|
||||
ctrl.head = (0.0, 1.0, 1.7)
|
||||
ctrl.tail = (0.0, 2.0, 1.7)
|
||||
rig.data.collections['Controls'].assign(ctrl)
|
||||
|
||||
ctrl_offset = bones.new("Camera_offset")
|
||||
ctrl_offset = bones.new("Camera_Offset")
|
||||
ctrl_offset.head = (0.0, 1.0, 1.7)
|
||||
ctrl_offset.tail = (0.0, 2.0, 1.7)
|
||||
rig.data.collections['Controls'].assign(ctrl_offset)
|
||||
|
||||
arm = bones.new("Crane_arm")
|
||||
arm = bones.new("Crane_Arm")
|
||||
arm.head = (0.0, 0.0, 1.7)
|
||||
arm.tail = (0.0, 1.0, 1.7)
|
||||
rig.data.collections['Controls'].assign(arm)
|
||||
|
||||
height = bones.new("Crane_height")
|
||||
height = bones.new("Crane_Height")
|
||||
height.head = (0.0, 0.0, 0.0)
|
||||
height.tail = (0.0, 0.0, 1.7)
|
||||
rig.data.collections['Controls'].assign(height)
|
||||
|
||||
# Setup hierarchy
|
||||
ctrl.parent = arm
|
||||
ctrl_offset.parent = ctrl
|
||||
ctrl.use_inherit_rotation = False
|
||||
ctrl.use_inherit_scale = False
|
||||
ctrl.inherit_scale = "NONE"
|
||||
ctrl.show_wire = True
|
||||
|
||||
arm.parent = height
|
||||
arm.use_inherit_scale = False
|
||||
arm.inherit_scale = "NONE"
|
||||
|
||||
height.parent = root
|
||||
ctrl_aim.parent = root
|
||||
@ -124,12 +142,12 @@ def create_crane_bones(rig):
|
||||
pose_bones = rig.pose.bones
|
||||
|
||||
# Lock the relevant loc, rot and scale
|
||||
pose_bones["Crane_arm"].lock_rotation = (False, True, False)
|
||||
pose_bones["Crane_arm"].lock_scale = (True, False, True)
|
||||
pose_bones["Crane_height"].lock_location = (True,) * 3
|
||||
pose_bones["Crane_height"].lock_rotation = (True,) * 3
|
||||
pose_bones["Crane_height"].lock_scale = (True, False, True)
|
||||
pose_bones["Camera_offset"].lock_scale = (True,) * 3
|
||||
pose_bones["Crane_Arm"].lock_rotation = (False, True, False)
|
||||
pose_bones["Crane_Arm"].lock_scale = (True, False, True)
|
||||
pose_bones["Crane_Height"].lock_location = (True,) * 3
|
||||
pose_bones["Crane_Height"].lock_rotation = (True,) * 3
|
||||
pose_bones["Crane_Height"].lock_scale = (True, False, True)
|
||||
pose_bones["Camera_Offset"].lock_scale = (True,) * 3
|
||||
|
||||
|
||||
def setup_3d_rig(rig, cam):
|
||||
@ -149,20 +167,20 @@ def setup_3d_rig(rig, cam):
|
||||
# Build the widgets
|
||||
root_widget = create_root_widget("Camera_Root")
|
||||
camera_widget = create_camera_widget("Camera")
|
||||
camera_offset_widget = create_camera_offset_widget("Camera_offset")
|
||||
camera_offset_widget = create_camera_offset_widget("Camera_Offset")
|
||||
aim_widget = create_aim_widget("Aim")
|
||||
|
||||
# Add the custom bone shapes
|
||||
pose_bones["Root"].custom_shape = root_widget
|
||||
pose_bones["Aim"].custom_shape = aim_widget
|
||||
pose_bones["Camera"].custom_shape = camera_widget
|
||||
pose_bones["Camera_offset"].custom_shape = camera_offset_widget
|
||||
pose_bones["Camera_Offset"].custom_shape = camera_offset_widget
|
||||
|
||||
# Set the "Override Transform" field to the mechanism position
|
||||
pose_bones["Aim"].custom_shape_transform = pose_bones["Aim_shape_rotation-MCH"]
|
||||
pose_bones["Aim"].custom_shape_transform = pose_bones["MCH-Aim_shape_rotation"]
|
||||
|
||||
# Add constraints to bones
|
||||
con = pose_bones['Aim_shape_rotation-MCH'].constraints.new('COPY_ROTATION')
|
||||
con = pose_bones['MCH-Aim_shape_rotation'].constraints.new('COPY_ROTATION')
|
||||
con.target = rig
|
||||
con.subtarget = "Camera"
|
||||
|
||||
@ -189,29 +207,38 @@ def create_2d_bones(context, rig, cam):
|
||||
root = bones.new("Root")
|
||||
root.tail = Vector((0.0, 0.0, 1.0))
|
||||
root.show_wire = True
|
||||
rig.data.collections.new(name="Controls")
|
||||
rig.data.collections['Controls'].assign(root)
|
||||
|
||||
ctrl = bones.new('Camera')
|
||||
ctrl.tail = Vector((0.0, 0.0, 1.0))
|
||||
ctrl.show_wire = True
|
||||
rig.data.collections['Controls'].assign(ctrl)
|
||||
|
||||
left_corner = bones.new("Left_corner")
|
||||
left_corner = bones.new("Left_Corner")
|
||||
left_corner.head = (-3, 10, -2)
|
||||
left_corner.tail = left_corner.head + Vector((0.0, 0.0, 1.0))
|
||||
left_corner.show_wire = True
|
||||
rig.data.collections['Controls'].assign(left_corner)
|
||||
|
||||
right_corner = bones.new("Right_corner")
|
||||
right_corner = bones.new("Right_Corner")
|
||||
right_corner.head = (3, 10, -2)
|
||||
right_corner.tail = right_corner.head + Vector((0.0, 0.0, 1.0))
|
||||
right_corner.show_wire = True
|
||||
rig.data.collections['Controls'].assign(right_corner)
|
||||
|
||||
corner_distance_x = (left_corner.head - right_corner.head).length
|
||||
corner_distance_y = -left_corner.head.z
|
||||
corner_distance_z = left_corner.head.y
|
||||
rig.data.collections['Controls'].assign(root)
|
||||
|
||||
center = bones.new("Center-MCH")
|
||||
center = bones.new("MCH-Center")
|
||||
center.head = ((right_corner.head + left_corner.head) / 2.0)
|
||||
center.tail = center.head + Vector((0.0, 0.0, 1.0))
|
||||
center.layers = tuple(i == 1 for i in range(32))
|
||||
center.show_wire = True
|
||||
rig.data.collections.new(name="MCH")
|
||||
rig.data.collections['MCH'].assign(center)
|
||||
rig.data.collections['MCH'].is_visible = False
|
||||
center.show_wire = True
|
||||
|
||||
# Setup hierarchy
|
||||
@ -227,7 +254,7 @@ def create_2d_bones(context, rig, cam):
|
||||
bone.rotation_mode = 'XYZ'
|
||||
|
||||
# Bone drivers
|
||||
center_drivers = pose_bones["Center-MCH"].driver_add("location")
|
||||
center_drivers = pose_bones["MCH-Center"].driver_add("location")
|
||||
|
||||
# Center X driver
|
||||
driver = center_drivers[0].driver
|
||||
@ -238,7 +265,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = corner
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_X'
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -255,7 +282,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = '%s_%s' % (corner, direction)
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_' + direction.upper()
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -275,31 +302,31 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = corner
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_Z'
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
# Bone constraints
|
||||
con = pose_bones["Camera"].constraints.new('DAMPED_TRACK')
|
||||
con.target = rig
|
||||
con.subtarget = "Center-MCH"
|
||||
con.subtarget = "MCH-Center"
|
||||
con.track_axis = 'TRACK_NEGATIVE_Z'
|
||||
|
||||
# Build the widgets
|
||||
left_widget = create_corner_widget("Left_corner", reverse=True)
|
||||
right_widget = create_corner_widget("Right_corner")
|
||||
left_widget = create_corner_widget("Left_Corner", reverse=True)
|
||||
right_widget = create_corner_widget("Right_Corner")
|
||||
parent_widget = create_circle_widget("Root", radius=0.5)
|
||||
camera_widget = create_circle_widget("Camera_2D", radius=0.3)
|
||||
|
||||
# Add the custom bone shapes
|
||||
pose_bones["Left_corner"].custom_shape = left_widget
|
||||
pose_bones["Right_corner"].custom_shape = right_widget
|
||||
pose_bones["Left_Corner"].custom_shape = left_widget
|
||||
pose_bones["Right_Corner"].custom_shape = right_widget
|
||||
pose_bones["Root"].custom_shape = parent_widget
|
||||
pose_bones["Camera"].custom_shape = camera_widget
|
||||
|
||||
# Lock the relevant loc, rot and scale
|
||||
pose_bones["Left_corner"].lock_rotation = (True,) * 3
|
||||
pose_bones["Right_corner"].lock_rotation = (True,) * 3
|
||||
pose_bones["Left_Corner"].lock_rotation = (True,) * 3
|
||||
pose_bones["Right_Corner"].lock_rotation = (True,) * 3
|
||||
pose_bones["Camera"].lock_rotation = (True,) * 3
|
||||
pose_bones["Camera"].lock_scale = (True,) * 3
|
||||
|
||||
@ -331,10 +358,10 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = 'frame_width'
|
||||
var.type = 'LOC_DIFF'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = "Left_corner"
|
||||
var.targets[0].bone_target = "Left_Corner"
|
||||
var.targets[0].transform_space = 'WORLD_SPACE'
|
||||
var.targets[1].id = rig
|
||||
var.targets[1].bone_target = "Right_corner"
|
||||
var.targets[1].bone_target = "Right_Corner"
|
||||
var.targets[1].transform_space = 'WORLD_SPACE'
|
||||
|
||||
for corner in ('left', 'right'):
|
||||
@ -342,7 +369,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = corner + '_z'
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_Z'
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -363,7 +390,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = corner + '_x'
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_X'
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -385,7 +412,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = '%s_%s' % (corner, direction)
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_' + direction.upper()
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -422,7 +449,7 @@ def create_2d_bones(context, rig, cam):
|
||||
var.name = '%s_%s' % (corner, direction)
|
||||
var.type = 'TRANSFORMS'
|
||||
var.targets[0].id = rig
|
||||
var.targets[0].bone_target = corner.capitalize() + '_corner'
|
||||
var.targets[0].bone_target = corner.capitalize() + '_Corner'
|
||||
var.targets[0].transform_type = 'LOC_' + direction.upper()
|
||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||
|
||||
@ -484,7 +511,7 @@ def build_camera_rig(context, mode):
|
||||
if mode == "2D":
|
||||
cam.parent_bone = "Camera"
|
||||
else:
|
||||
cam.parent_bone = "Camera_offset"
|
||||
cam.parent_bone = "Camera_Offset"
|
||||
|
||||
# Change display to BBone: it just looks nicer
|
||||
rig.data.display_type = 'BBONE'
|
||||
|
@ -63,7 +63,7 @@ class ExportUVLayout(bpy.types.Operator):
|
||||
items=(
|
||||
('SVG', "Scalable Vector Graphic (.svg)",
|
||||
"Export the UV layout to a vector SVG file"),
|
||||
('EPS', "Encapsulate PostScript (.eps)",
|
||||
('EPS', "Encapsulated PostScript (.eps)",
|
||||
"Export the UV layout to a vector EPS file"),
|
||||
('PNG', "PNG Image (.png)",
|
||||
"Export the UV layout to a bitmap image"),
|
||||
|
@ -1651,7 +1651,7 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
|
||||
gradient = next((lk.from_node.color_ramp.elements for lk in ntree if lk.from_node.type == 'VALTORGB' and lk.to_node.type in bgmixer), False)
|
||||
background_color_chunk.add_variable("color", _3ds_float_color(bg_color))
|
||||
background_chunk.add_subchunk(background_color_chunk)
|
||||
if bg_image:
|
||||
if bg_image and bg_image is not None:
|
||||
background_image = _3ds_chunk(BITMAP)
|
||||
background_flag = _3ds_chunk(USE_BITMAP)
|
||||
background_image.add_variable("image", _3ds_string(sane_name(bg_image.name)))
|
||||
@ -1938,11 +1938,10 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
|
||||
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||
obj_hierarchy_chunk.add_variable("hierarchy", _3ds_ushort(object_id[ob.name]))
|
||||
if ob.parent is None or (ob.parent.name not in object_id):
|
||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
||||
else: # Get the parent ID from the object_id dict
|
||||
if ob.parent is not None and (ob.parent.name in object_id):
|
||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(object_id[ob.parent.name]))
|
||||
obj_hierarchy_chunk.add_subchunk(obj_parent_chunk)
|
||||
obj_hierarchy_chunk.add_subchunk(obj_parent_chunk)
|
||||
object_chunk.add_subchunk(obj_hierarchy_chunk)
|
||||
|
||||
# Add light object and hierarchy chunks to object info
|
||||
@ -1976,11 +1975,10 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
|
||||
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||
obj_hierarchy_chunk.add_variable("hierarchy", _3ds_ushort(object_id[ob.name]))
|
||||
if ob.parent is None or (ob.parent.name not in object_id):
|
||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
||||
else: # Get the parent ID from the object_id dict
|
||||
if ob.parent is not None and (ob.parent.name in object_id):
|
||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(object_id[ob.parent.name]))
|
||||
obj_hierarchy_chunk.add_subchunk(obj_parent_chunk)
|
||||
obj_hierarchy_chunk.add_subchunk(obj_parent_chunk)
|
||||
object_chunk.add_subchunk(obj_hierarchy_chunk)
|
||||
|
||||
# Add light object and hierarchy chunks to object info
|
||||
|
@ -5,7 +5,7 @@
|
||||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (4, 0, 31),
|
||||
"version": (4, 0, 32),
|
||||
'blender': (4, 0, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
@ -326,14 +326,6 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
|
||||
default='EXPORT'
|
||||
)
|
||||
|
||||
export_original_specular: BoolProperty(
|
||||
name='Export original PBR Specular',
|
||||
description=(
|
||||
'Export original glTF PBR Specular, instead of Blender Principled Shader Specular'
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
|
||||
export_colors: BoolProperty(
|
||||
name='Vertex Colors',
|
||||
description='Export vertex colors with meshes',
|
||||
@ -680,6 +672,15 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
|
||||
default=True
|
||||
)
|
||||
|
||||
# Keep for back compatibility, but no more used
|
||||
export_original_specular: BoolProperty(
|
||||
name='Export original PBR Specular',
|
||||
description=(
|
||||
'Export original glTF PBR Specular, instead of Blender Principled Shader Specular'
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
|
||||
will_save_settings: BoolProperty(
|
||||
name='Remember Export Settings',
|
||||
description='Store glTF export settings in the Blender project',
|
||||
@ -801,8 +802,6 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
|
||||
export_settings['gltf_attributes'] = self.export_attributes
|
||||
export_settings['gltf_cameras'] = self.export_cameras
|
||||
|
||||
export_settings['gltf_original_specular'] = self.export_original_specular
|
||||
|
||||
export_settings['gltf_visible'] = self.use_visible
|
||||
export_settings['gltf_renderable'] = self.use_renderable
|
||||
|
||||
@ -1125,29 +1124,6 @@ class GLTF_PT_export_data_material(bpy.types.Panel):
|
||||
col.active = operator.export_image_format != "WEBP"
|
||||
col.prop(operator, "export_image_webp_fallback")
|
||||
|
||||
class GLTF_PT_export_data_original_pbr(bpy.types.Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'TOOL_PROPS'
|
||||
bl_label = "PBR Extensions"
|
||||
bl_parent_id = "GLTF_PT_export_data_material"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
sfile = context.space_data
|
||||
operator = sfile.active_operator
|
||||
return operator.bl_idname == "EXPORT_SCENE_OT_gltf"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
sfile = context.space_data
|
||||
operator = sfile.active_operator
|
||||
|
||||
layout.prop(operator, 'export_original_specular')
|
||||
|
||||
class GLTF_PT_export_data_lighting(bpy.types.Panel):
|
||||
bl_space_type = 'FILE_BROWSER'
|
||||
bl_region_type = 'TOOL_PROPS'
|
||||
@ -1864,7 +1840,6 @@ classes = (
|
||||
GLTF_PT_export_data_scene,
|
||||
GLTF_PT_export_data_mesh,
|
||||
GLTF_PT_export_data_material,
|
||||
GLTF_PT_export_data_original_pbr,
|
||||
GLTF_PT_export_data_shapekeys,
|
||||
GLTF_PT_export_data_sk_optimize,
|
||||
GLTF_PT_export_data_armature,
|
||||
|
@ -18,9 +18,5 @@ def create_settings_group(name):
|
||||
thicknessFactor.default_value = 0.0
|
||||
gltf_node_group.nodes.new('NodeGroupOutput')
|
||||
gltf_node_group_input = gltf_node_group.nodes.new('NodeGroupInput')
|
||||
specular = gltf_node_group.interface.new_socket("Specular", socket_type="NodeSocketFloat")
|
||||
specular.default_value = 1.0
|
||||
specularColor = gltf_node_group.interface.new_socket("Specular Color", socket_type="NodeSocketColor")
|
||||
specularColor.default_value = [1.0,1.0,1.0,1.0]
|
||||
gltf_node_group_input.location = -200, 0
|
||||
return gltf_node_group
|
||||
|
@ -119,7 +119,7 @@ def __fix_json(obj):
|
||||
|
||||
|
||||
def __should_include_json_value(key, value):
|
||||
allowed_empty_collections = ["KHR_materials_unlit"]
|
||||
allowed_empty_collections = ["KHR_materials_unlit", "KHR_materials_specular"]
|
||||
|
||||
if value is None:
|
||||
return False
|
||||
|
@ -71,10 +71,6 @@ def get_socket(blender_material: bpy.types.Material, name: str, volume=False):
|
||||
elif name == "Background":
|
||||
type = bpy.types.ShaderNodeBackground
|
||||
name = "Color"
|
||||
elif name == "sheenColor":
|
||||
return get_node_socket(blender_material, bpy.types.ShaderNodeBsdfSheen, "Color")
|
||||
elif name == "sheenRoughness":
|
||||
return get_node_socket(blender_material, bpy.types.ShaderNodeBsdfSheen, "Roughness")
|
||||
else:
|
||||
if volume is False:
|
||||
type = bpy.types.ShaderNodeBsdfPrincipled
|
||||
|
@ -11,34 +11,43 @@ from ...material import gltf2_blender_gather_texture_info
|
||||
def export_sheen(blender_material, export_settings):
|
||||
sheen_extension = {}
|
||||
|
||||
sheenColor_socket = gltf2_blender_get.get_socket(blender_material, "sheenColor")
|
||||
sheenRoughness_socket = gltf2_blender_get.get_socket(blender_material, "sheenRoughness")
|
||||
sheenTint_socket = gltf2_blender_get.get_socket(blender_material, "Sheen Tint")
|
||||
sheenRoughness_socket = gltf2_blender_get.get_socket(blender_material, "Sheen Roughness")
|
||||
sheen_socket = gltf2_blender_get.get_socket(blender_material, "Sheen Weight")
|
||||
|
||||
if sheenColor_socket is None or sheenRoughness_socket is None:
|
||||
if sheenTint_socket is None or sheenRoughness_socket is None or sheen_socket is None:
|
||||
return None, {}
|
||||
|
||||
if sheen_socket.is_linked is False and sheen_socket.default_value == 0.0:
|
||||
return None, {}
|
||||
|
||||
uvmap_infos = {}
|
||||
|
||||
sheenColor_non_linked = isinstance(sheenColor_socket, bpy.types.NodeSocket) and not sheenColor_socket.is_linked
|
||||
#TODOExt : What to do if sheen_socket is linked? or is not between 0 and 1?
|
||||
|
||||
sheenTint_non_linked = isinstance(sheenTint_socket, bpy.types.NodeSocket) and not sheenTint_socket.is_linked
|
||||
sheenRoughness_non_linked = isinstance(sheenRoughness_socket, bpy.types.NodeSocket) and not sheenRoughness_socket.is_linked
|
||||
|
||||
if sheenColor_non_linked is True:
|
||||
color = sheenColor_socket.default_value[:3]
|
||||
|
||||
use_actives_uvmaps = []
|
||||
|
||||
if sheenTint_non_linked is True:
|
||||
color = sheenTint_socket.default_value[:3]
|
||||
if color != (0.0, 0.0, 0.0):
|
||||
sheen_extension['sheenColorFactor'] = color
|
||||
else:
|
||||
# Factor
|
||||
fac = gltf2_blender_get.get_factor_from_socket(sheenColor_socket, kind='RGB')
|
||||
fac = gltf2_blender_get.get_factor_from_socket(sheenTint_socket, kind='RGB')
|
||||
if fac is None:
|
||||
fac = [1.0, 1.0, 1.0] # Default is 0.0/0.0/0.0, so we need to set it to 1 if no factor
|
||||
if fac is not None and fac != [0.0, 0.0, 0.0]:
|
||||
sheen_extension['sheenColorFactor'] = fac
|
||||
|
||||
# Texture
|
||||
if gltf2_blender_get.has_image_node_from_socket(sheenColor_socket):
|
||||
if gltf2_blender_get.has_image_node_from_socket(sheenTint_socket):
|
||||
original_sheenColor_texture, uvmap_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
sheenColor_socket,
|
||||
(sheenColor_socket,),
|
||||
sheenTint_socket,
|
||||
(sheenTint_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
|
@ -4,41 +4,43 @@
|
||||
|
||||
import bpy
|
||||
from .....io.com.gltf2_io_extensions import Extension
|
||||
from .....io.com.gltf2_io_constants import GLTF_IOR
|
||||
from ....exp import gltf2_blender_get
|
||||
from ....com.gltf2_blender_default import BLENDER_SPECULAR, BLENDER_SPECULAR_TINT
|
||||
from ...material.gltf2_blender_gather_texture_info import gather_texture_info
|
||||
from ...gltf2_blender_get import image_tex_is_valid_from_socket
|
||||
|
||||
def export_original_specular(blender_material, export_settings):
|
||||
def export_specular(blender_material, export_settings):
|
||||
specular_extension = {}
|
||||
|
||||
original_specular_socket = gltf2_blender_get.get_socket_old(blender_material, 'Specular')
|
||||
original_specularcolor_socket = gltf2_blender_get.get_socket_old(blender_material, 'Specular Color')
|
||||
specular_socket = gltf2_blender_get.get_socket(blender_material, 'Specular IOR Level')
|
||||
speculartint_socket = gltf2_blender_get.get_socket(blender_material, 'Specular Tint')
|
||||
|
||||
if original_specular_socket is None or original_specularcolor_socket is None:
|
||||
if specular_socket is None or speculartint_socket is None:
|
||||
return None, {}
|
||||
|
||||
uvmap_infos = {}
|
||||
|
||||
specular_non_linked = isinstance(original_specular_socket, bpy.types.NodeSocket) and not original_specular_socket.is_linked
|
||||
specularcolor_non_linked = isinstance(original_specularcolor_socket, bpy.types.NodeSocket) and not original_specularcolor_socket.is_linked
|
||||
specular_non_linked = isinstance(specular_socket, bpy.types.NodeSocket) and not specular_socket.is_linked
|
||||
specularcolor_non_linked = isinstance(speculartint_socket, bpy.types.NodeSocket) and not speculartint_socket.is_linked
|
||||
|
||||
if specular_non_linked is True:
|
||||
fac = original_specular_socket.default_value
|
||||
fac = specular_socket.default_value
|
||||
if fac != 1.0:
|
||||
specular_extension['specularFactor'] = fac
|
||||
if fac == 0.0:
|
||||
return None, {}
|
||||
else:
|
||||
# Factor
|
||||
fac = gltf2_blender_get.get_factor_from_socket(original_specular_socket, kind='VALUE')
|
||||
fac = gltf2_blender_get.get_factor_from_socket(specular_socket, kind='VALUE')
|
||||
if fac is not None and fac != 1.0:
|
||||
specular_extension['specularFactor'] = fac
|
||||
|
||||
if fac == 0.0:
|
||||
return None, {}
|
||||
|
||||
# Texture
|
||||
if gltf2_blender_get.has_image_node_from_socket(original_specular_socket):
|
||||
if gltf2_blender_get.has_image_node_from_socket(specular_socket):
|
||||
original_specular_texture, uvmap_info, _ = gather_texture_info(
|
||||
original_specular_socket,
|
||||
(original_specular_socket,),
|
||||
specular_socket,
|
||||
(specular_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
@ -46,20 +48,20 @@ def export_original_specular(blender_material, export_settings):
|
||||
uvmap_infos.update({'specularTexture': uvmap_info})
|
||||
|
||||
if specularcolor_non_linked is True:
|
||||
color = original_specularcolor_socket.default_value[:3]
|
||||
if color != [1.0, 1.0, 1.0]:
|
||||
color = speculartint_socket.default_value[:3]
|
||||
if color != (1.0, 1.0, 1.0):
|
||||
specular_extension['specularColorFactor'] = color
|
||||
else:
|
||||
# Factor
|
||||
fac = gltf2_blender_get.get_factor_from_socket(original_specularcolor_socket, kind='RGB')
|
||||
if fac is not None and fac != [1.0, 1.0, 1.0]:
|
||||
fac = gltf2_blender_get.get_factor_from_socket(speculartint_socket, kind='RGB')
|
||||
if fac is not None and fac != (1.0, 1.0, 1.0):
|
||||
specular_extension['specularColorFactor'] = fac
|
||||
|
||||
# Texture
|
||||
if gltf2_blender_get.has_image_node_from_socket(original_specularcolor_socket):
|
||||
if gltf2_blender_get.has_image_node_from_socket(speculartint_socket):
|
||||
original_specularcolor_texture, uvmap_info, _ = gather_texture_info(
|
||||
original_specularcolor_socket,
|
||||
(original_specularcolor_socket,),
|
||||
speculartint_socket,
|
||||
(speculartint_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
@ -67,103 +69,3 @@ def export_original_specular(blender_material, export_settings):
|
||||
uvmap_infos.update({'specularColorTexture': uvmap_info})
|
||||
|
||||
return Extension('KHR_materials_specular', specular_extension, False), uvmap_infos
|
||||
|
||||
def export_specular(blender_material, export_settings):
|
||||
|
||||
if export_settings['gltf_original_specular'] is True:
|
||||
return export_original_specular(blender_material, export_settings)
|
||||
|
||||
specular_extension = {}
|
||||
specular_ext_enabled = False
|
||||
|
||||
specular_socket = gltf2_blender_get.get_socket(blender_material, 'Specular IOR Level')
|
||||
specular_tint_socket = gltf2_blender_get.get_socket(blender_material, 'Specular Tint')
|
||||
base_color_socket = gltf2_blender_get.get_socket(blender_material, 'Base Color')
|
||||
transmission_socket = gltf2_blender_get.get_socket(blender_material, 'Transmission Weight')
|
||||
ior_socket = gltf2_blender_get.get_socket(blender_material, 'IOR')
|
||||
|
||||
if base_color_socket is None:
|
||||
return None, {}
|
||||
|
||||
specular_not_linked = not image_tex_is_valid_from_socket(specular_socket)
|
||||
specular_tint_not_linked = not image_tex_is_valid_from_socket(specular_tint_socket)
|
||||
base_color_not_linked = not image_tex_is_valid_from_socket(base_color_socket)
|
||||
transmission_not_linked = not image_tex_is_valid_from_socket(transmission_socket)
|
||||
ior_not_linked = not image_tex_is_valid_from_socket(ior_socket)
|
||||
|
||||
specular = specular_socket.default_value if specular_not_linked else None
|
||||
specular_tint = specular_tint_socket.default_value if specular_tint_not_linked else None
|
||||
if specular_tint is not None:
|
||||
specular_tint = (specular_tint[0] + specular_tint[1] + specular_tint[2]) / 3 # TODO tmp fix to avoid crash
|
||||
transmission = transmission_socket.default_value if transmission_not_linked else None
|
||||
ior = ior_socket.default_value if ior_not_linked else GLTF_IOR # textures not supported #TODOExt add warning?
|
||||
base_color = base_color_socket.default_value[0:3]
|
||||
|
||||
no_texture = (transmission_not_linked and specular_not_linked and specular_tint_not_linked and
|
||||
(specular_tint == 0.0 or (specular_tint != 0.0 and base_color_not_linked)))
|
||||
|
||||
if no_texture:
|
||||
uvmap_info = {}
|
||||
if specular != BLENDER_SPECULAR or specular_tint != BLENDER_SPECULAR_TINT:
|
||||
import numpy as np
|
||||
# See https://gist.github.com/proog128/d627c692a6bbe584d66789a5a6437a33
|
||||
specular_ext_enabled = True
|
||||
|
||||
def normalize(c):
|
||||
luminance = lambda c: 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
|
||||
assert(len(c) == 3)
|
||||
l = luminance(c)
|
||||
if l == 0:
|
||||
return np.array(c)
|
||||
return np.array([c[0] / l, c[1] / l, c[2] / l])
|
||||
|
||||
f0_from_ior = ((ior - 1)/(ior + 1))**2
|
||||
if f0_from_ior == 0:
|
||||
specular_color = [1.0, 1.0, 1.0]
|
||||
else:
|
||||
tint_strength = (1 - specular_tint) + normalize(base_color) * specular_tint
|
||||
specular_color = (1 - transmission) * (1 / f0_from_ior) * 0.08 * specular * tint_strength + transmission * tint_strength
|
||||
specular_color = list(specular_color)
|
||||
specular_extension['specularColorFactor'] = specular_color
|
||||
else:
|
||||
if specular_not_linked and specular == BLENDER_SPECULAR and specular_tint_not_linked and specular_tint == BLENDER_SPECULAR_TINT:
|
||||
return None, {}
|
||||
|
||||
# Trying to identify cases where exporting a texture will not be needed
|
||||
if specular_not_linked and transmission_not_linked and \
|
||||
specular == 0.0 and transmission == 0.0:
|
||||
|
||||
specular_extension['specularColorFactor'] = [0.0, 0.0, 0.0]
|
||||
return specular_extension, {}
|
||||
|
||||
|
||||
# There will be a texture, with a complex calculation (no direct channel mapping)
|
||||
sockets = (specular_socket, specular_tint_socket, base_color_socket, transmission_socket, ior_socket)
|
||||
# Set primary socket having a texture
|
||||
primary_socket = specular_socket
|
||||
if specular_not_linked:
|
||||
primary_socket = specular_tint_socket
|
||||
if specular_tint_not_linked:
|
||||
primary_socket = base_color_socket
|
||||
if base_color_not_linked:
|
||||
primary_socket = transmission_socket
|
||||
|
||||
specularColorTexture, uvmap_info, specularColorFactor = gather_texture_info(
|
||||
primary_socket,
|
||||
sockets,
|
||||
(),
|
||||
export_settings,
|
||||
filter_type='ANY')
|
||||
if specularColorTexture is None:
|
||||
return None, {}
|
||||
|
||||
specular_ext_enabled = True
|
||||
specular_extension['specularColorTexture'] = specularColorTexture
|
||||
|
||||
|
||||
if specularColorFactor is not None:
|
||||
specular_extension['specularColorFactor'] = specularColorFactor
|
||||
|
||||
|
||||
specular_extension = Extension('KHR_materials_specular', specular_extension, False) if specular_ext_enabled else None
|
||||
return specular_extension, {'specularColorTexture': uvmap_info}
|
||||
|
@ -147,7 +147,6 @@ class ExportImage:
|
||||
|
||||
# Unhappy path = we need to create the image self.fills describes or self.stores describes
|
||||
if self.numpy_calc is None:
|
||||
print(">2")
|
||||
return self.__encode_unhappy(export_settings), None
|
||||
else:
|
||||
pixels, width, height, factor = self.numpy_calc(self.stored)
|
||||
|
@ -1,97 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2018-2022 The glTF-Blender-IO authors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
from .gltf2_blender_image import TmpImageGuard, make_temp_image_copy, StoreImage
|
||||
|
||||
def specular_calculation(stored):
|
||||
|
||||
# See https://gist.github.com/proog128/d627c692a6bbe584d66789a5a6437a33
|
||||
|
||||
# Find all Blender images used
|
||||
images = []
|
||||
for fill in stored.values():
|
||||
if isinstance(fill, StoreImage):
|
||||
if fill.image not in images:
|
||||
images.append(fill.image)
|
||||
|
||||
if not images:
|
||||
# No ImageFills; use a 1x1 white pixel
|
||||
pixels = np.array([1.0, 1.0, 1.0, 1.0], np.float32)
|
||||
return pixels, 1, 1
|
||||
|
||||
width = max(image.size[0] for image in images)
|
||||
height = max(image.size[1] for image in images)
|
||||
|
||||
buffers = {}
|
||||
|
||||
for identifier, image in [(ident, store.image) for (ident, store) in stored.items() if isinstance(store, StoreImage)]:
|
||||
tmp_buf = np.empty(width * height * 4, np.float32)
|
||||
|
||||
if image.size[0] == width and image.size[1] == height:
|
||||
image.pixels.foreach_get(tmp_buf)
|
||||
else:
|
||||
# Image is the wrong size; make a temp copy and scale it.
|
||||
with TmpImageGuard() as guard:
|
||||
make_temp_image_copy(guard, src_image=image)
|
||||
tmp_image = guard.image
|
||||
tmp_image.scale(width, height)
|
||||
tmp_image.pixels.foreach_get(tmp_buf)
|
||||
|
||||
buffers[identifier] = np.reshape(tmp_buf, [width, height, 4])
|
||||
|
||||
# keep only needed channels
|
||||
## scalar
|
||||
for i in ['specular', 'transmission']:
|
||||
if i in buffers.keys():
|
||||
buffers[i] = buffers[i][:,:,stored[i + "_channel"].data]
|
||||
else:
|
||||
buffers[i] = np.full((width, height, 1), stored[i].data)
|
||||
|
||||
# Vector 3
|
||||
for i in ['base_color', 'specular_tint']:
|
||||
if i in buffers.keys():
|
||||
if i + "_channel" not in stored.keys():
|
||||
buffers[i] = buffers[i][:,:,:3]
|
||||
else:
|
||||
# keep only needed channel
|
||||
for c in range(3):
|
||||
if c != stored[i+"_channel"].data:
|
||||
buffers[i][:, :, c] = 0.0
|
||||
buffers[i] = buffers[i][:,:,:3]
|
||||
else:
|
||||
buffers[i] = np.full((width, height, 3), stored[i].data[0:3])
|
||||
|
||||
# TODO tmp Merge last dimension to avoid crash
|
||||
buffers['specular_tint'] = np.average(buffers['specular_tint'], axis=2)
|
||||
|
||||
ior = stored['ior'].data
|
||||
|
||||
# calculation
|
||||
stack3 = lambda v: np.dstack([v]*3)
|
||||
|
||||
def normalize(c):
|
||||
luminance = lambda c: 0.3 * c[:,:,0] + 0.6 * c[:,:,1] + 0.1 * c[:,:,2]
|
||||
l = luminance(c)
|
||||
# TODOExt Manage all 0
|
||||
return c / stack3(l)
|
||||
|
||||
|
||||
f0_from_ior = ((ior - 1)/(ior + 1))**2
|
||||
tint_strength = (1 - stack3(buffers['specular_tint'])) + normalize(buffers['base_color']) * stack3(buffers['specular_tint'])
|
||||
out_buf = (1 - stack3(buffers['transmission'])) * (1 / f0_from_ior) * 0.08 * stack3(buffers['specular']) * tint_strength + stack3(buffers['transmission']) * tint_strength
|
||||
|
||||
# Manage values > 1.0 -> Need to apply factor
|
||||
factor = None
|
||||
factors = [np.amax(out_buf[:, :, i]) for i in range(3)]
|
||||
|
||||
if any([f > 1.0 for f in factors]):
|
||||
factor = [1.0 if f < 1.0 else f for f in factors]
|
||||
out_buf /= factor
|
||||
|
||||
out_buf = np.dstack((out_buf, np.ones((width, height)))) # Set alpha (glTF specular) to 1
|
||||
out_buf = np.reshape(out_buf, (width * height * 4))
|
||||
|
||||
return np.float32(out_buf), width, height, [float(f) for f in factor] if factor else None
|
@ -194,10 +194,8 @@ def __get_image_data(sockets, default_sockets, export_settings) -> ExportImage:
|
||||
results = [get_tex_from_socket(socket) for socket in sockets]
|
||||
|
||||
# Check if we need a simple mapping or more complex calculation
|
||||
if any([socket.name == "Specular IOR Level" and socket.node.type == "BSDF_PRINCIPLED" for socket in sockets]):
|
||||
return __get_image_data_specular(sockets, results, export_settings)
|
||||
else:
|
||||
return __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||
# There is currently no complex calculation for any textures
|
||||
return __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||
|
||||
def __get_image_data_mapping(sockets, default_sockets, results, export_settings) -> ExportImage:
|
||||
"""
|
||||
@ -240,7 +238,7 @@ def __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||
# some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes)
|
||||
if socket.name == 'Metallic':
|
||||
dst_chan = Channel.B
|
||||
elif socket.name == 'Roughness' and socket.node.type == "BSDF_PRINCIPLED":
|
||||
elif socket.name == 'Roughness':
|
||||
dst_chan = Channel.G
|
||||
elif socket.name == 'Occlusion':
|
||||
dst_chan = Channel.R
|
||||
@ -252,9 +250,9 @@ def __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||
dst_chan = Channel.G
|
||||
elif socket.name == 'Thickness': # For KHR_materials_volume
|
||||
dst_chan = Channel.G
|
||||
elif socket.name == "Specular": # For original KHR_material_specular
|
||||
elif socket.name == "Specular IOR Level": # For KHR_material_specular
|
||||
dst_chan = Channel.A
|
||||
elif socket.name == "Roughness" and socket.node.type == "BSDF_SHEEN": # For KHR_materials_sheen
|
||||
elif socket.name == "Sheen Roughness": # For KHR_materials_sheen
|
||||
dst_chan = Channel.A
|
||||
|
||||
if dst_chan is not None:
|
||||
@ -288,54 +286,6 @@ def __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||
return composed_image
|
||||
|
||||
|
||||
def __get_image_data_specular(sockets, results, export_settings) -> ExportImage:
|
||||
"""
|
||||
calculating Specular Texture, settings needed data
|
||||
"""
|
||||
from .extensions.gltf2_blender_texture_specular import specular_calculation
|
||||
composed_image = ExportImage()
|
||||
composed_image.set_calc(specular_calculation)
|
||||
|
||||
composed_image.store_data("ior", sockets[4].default_value, type="Data")
|
||||
|
||||
results = [get_tex_from_socket(socket) for socket in sockets[:-1]] #Do not retrieve IOR --> No texture allowed
|
||||
|
||||
mapping = {
|
||||
0: "specular",
|
||||
1: "specular_tint",
|
||||
2: "base_color",
|
||||
3: "transmission"
|
||||
}
|
||||
|
||||
for idx, result in enumerate(results):
|
||||
if get_tex_from_socket(sockets[idx]):
|
||||
|
||||
composed_image.store_data(mapping[idx], result.shader_node.image, type="Image")
|
||||
|
||||
# rudimentarily try follow the node tree to find the correct image data.
|
||||
src_chan = None if idx == 2 else Channel.R
|
||||
for elem in result.path:
|
||||
if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateColor):
|
||||
src_chan = {
|
||||
'Red': Channel.R,
|
||||
'Green': Channel.G,
|
||||
'Blue': Channel.B,
|
||||
}[elem.from_socket.name]
|
||||
if elem.from_socket.name == 'Alpha':
|
||||
src_chan = Channel.A
|
||||
# For base_color, keep all channels, as this is a Vec, not scalar
|
||||
if idx != 2:
|
||||
composed_image.store_data(mapping[idx] + "_channel", src_chan, type="Data")
|
||||
else:
|
||||
if src_chan is not None:
|
||||
composed_image.store_data(mapping[idx] + "_channel", src_chan, type="Data")
|
||||
|
||||
else:
|
||||
composed_image.store_data(mapping[idx], sockets[idx].default_value, type="Data")
|
||||
|
||||
return composed_image
|
||||
|
||||
|
||||
def __is_blender_image_a_jpeg(image: bpy.types.Image) -> bool:
|
||||
if image.source != 'FILE':
|
||||
return False
|
||||
|
@ -23,15 +23,14 @@ def pbr_specular_glossiness(mh):
|
||||
mh.node_tree.links.new(add_node.inputs[0], glossy_node.outputs[0])
|
||||
mh.node_tree.links.new(add_node.inputs[1], diffuse_node.outputs[0])
|
||||
|
||||
emission_socket, alpha_socket, _, _ = make_output_nodes(
|
||||
emission_socket, alpha_socket, _ = make_output_nodes(
|
||||
mh,
|
||||
location=(370, 250),
|
||||
additional_location=None, #No additional location needed for SpecGloss
|
||||
shader_socket=add_node.outputs[0],
|
||||
make_emission_socket=mh.needs_emissive(),
|
||||
make_alpha_socket=not mh.is_opaque(),
|
||||
make_volume_socket=None, # No possible to have KHR_materials_volume with specular/glossiness
|
||||
make_sheen_socket=None # No possible to have KHR_materials_volume with specular/glossiness
|
||||
make_volume_socket=None # No possible to have KHR_materials_volume with specular/glossiness
|
||||
)
|
||||
|
||||
if emission_socket:
|
||||
|
@ -6,13 +6,14 @@ from ...io.com.gltf2_io import TextureInfo
|
||||
from .gltf2_blender_texture import texture
|
||||
|
||||
def sheen( mh,
|
||||
location_sheenColor,
|
||||
location_sheenTint,
|
||||
location_sheenRoughness,
|
||||
sheenColor_socket,
|
||||
sheen_socket,
|
||||
sheenTint_socket,
|
||||
sheenRoughness_socket
|
||||
):
|
||||
|
||||
x_sheenColor, y_sheenColor = location_sheenColor
|
||||
x_sheenTint, y_sheenTint = location_sheenTint
|
||||
x_sheenRoughness, y_sheenRoughness = location_sheenRoughness
|
||||
|
||||
try:
|
||||
@ -20,7 +21,8 @@ def sheen( mh,
|
||||
except Exception:
|
||||
return
|
||||
|
||||
sheenColorFactor = ext.get('sheenColorFactor', [0.0, 0.0, 0.0])
|
||||
sheen_socket.default_value = 1.0
|
||||
sheenTintFactor = ext.get('sheenColorFactor', [0.0, 0.0, 0.0])
|
||||
tex_info_color = ext.get('sheenColorTexture')
|
||||
if tex_info_color is not None:
|
||||
tex_info_color = TextureInfo.from_dict(tex_info_color)
|
||||
@ -31,31 +33,31 @@ def sheen( mh,
|
||||
tex_info_roughness = TextureInfo.from_dict(tex_info_roughness)
|
||||
|
||||
if tex_info_color is None:
|
||||
sheenColorFactor.extend([1.0])
|
||||
sheenColor_socket.default_value = sheenColorFactor
|
||||
sheenTintFactor.extend([1.0])
|
||||
sheenTint_socket.default_value = sheenTintFactor
|
||||
else:
|
||||
# Mix sheenColor factor
|
||||
sheenColorFactor = sheenColorFactor + [1.0]
|
||||
if sheenColorFactor != [1.0, 1.0, 1.0, 1.0]:
|
||||
# Mix sheenTint factor
|
||||
sheenTintFactor = sheenTintFactor + [1.0]
|
||||
if sheenTintFactor != [1.0, 1.0, 1.0, 1.0]:
|
||||
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
||||
node.label = 'sheenColor Factor'
|
||||
node.label = 'sheenTint Factor'
|
||||
node.data_type = 'RGBA'
|
||||
node.location = x_sheenColor - 140, y_sheenColor
|
||||
node.location = x_sheenTint - 140, y_sheenTint
|
||||
node.blend_type = 'MULTIPLY'
|
||||
# Outputs
|
||||
mh.node_tree.links.new(sheenColor_socket, node.outputs[2])
|
||||
mh.node_tree.links.new(sheenTint_socket, node.outputs[2])
|
||||
# Inputs
|
||||
node.inputs['Factor'].default_value = 1.0
|
||||
sheenColor_socket = node.inputs[6]
|
||||
node.inputs[7].default_value = sheenColorFactor
|
||||
x_sheenColor -= 200
|
||||
sheenTint_socket = node.inputs[6]
|
||||
node.inputs[7].default_value = sheenTintFactor
|
||||
x_sheenTint -= 200
|
||||
|
||||
texture(
|
||||
mh,
|
||||
tex_info=tex_info_color,
|
||||
label='SHEEN COLOR',
|
||||
location=(x_sheenColor, y_sheenColor),
|
||||
color_socket=sheenColor_socket
|
||||
location=(x_sheenTint, y_sheenTint),
|
||||
color_socket=sheenTint_socket
|
||||
)
|
||||
|
||||
if tex_info_roughness is None:
|
||||
|
@ -12,13 +12,7 @@ from ..exp.material.extensions.gltf2_blender_image import TmpImageGuard, make_te
|
||||
def specular(mh, location_specular,
|
||||
location_specular_tint,
|
||||
specular_socket,
|
||||
specular_tint_socket,
|
||||
original_specular_socket,
|
||||
original_specularcolor_socket,
|
||||
location_original_specular,
|
||||
location_original_specularcolor):
|
||||
x_specular, y_specular = location_specular
|
||||
x_tint, y_tint = location_specular_tint
|
||||
specular_tint_socket):
|
||||
|
||||
if specular_socket is None:
|
||||
return
|
||||
@ -30,316 +24,22 @@ def specular(mh, location_specular,
|
||||
except Exception:
|
||||
return
|
||||
|
||||
import numpy as np
|
||||
|
||||
# Retrieve image names
|
||||
try:
|
||||
tex_info = mh.pymat.pbr_metallic_roughness.base_color_texture
|
||||
pytexture = mh.gltf.data.textures[tex_info.index]
|
||||
if mh.gltf.import_settings['import_webp_texture'] is True \
|
||||
and pytexture.extensions is not None \
|
||||
and "EXT_texture_webp" in pytexture.extensions:
|
||||
pyimg = mh.gltf.data.images[pytexture.extensions["EXT_texture_webp"]["source"]]
|
||||
base_color_image_name = pyimg.blender_image_name
|
||||
else:
|
||||
pyimg = mh.gltf.data.images[pytexture.source]
|
||||
base_color_image_name = pyimg.blender_image_name
|
||||
except:
|
||||
base_color_image_name = None
|
||||
|
||||
# First check if we need a texture or not -> retrieve all info needed
|
||||
specular_factor = ext.get('specularFactor', 1.0)
|
||||
tex_specular_info = ext.get('specularTexture')
|
||||
if tex_specular_info is not None:
|
||||
tex_specular_info = TextureInfo.from_dict(tex_specular_info)
|
||||
|
||||
specular_color_factor = np.array(ext.get('specularColorFactor', [1.0, 1.0, 1.0])[:3])
|
||||
tex_specular_color_info = ext.get('specularColorTexture')
|
||||
if tex_specular_color_info is not None:
|
||||
tex_specular_color_info = TextureInfo.from_dict(tex_specular_color_info)
|
||||
specular_tint_factor = ext.get('specularColorFactor', [1.0, 1.0, 1.0])[:3]
|
||||
tex_specular_tint_info = ext.get('specularColorTexture')
|
||||
if tex_specular_tint_info is not None:
|
||||
tex_specular_tint_info = TextureInfo.from_dict(tex_specular_tint_info)
|
||||
|
||||
base_color_not_linked = base_color_image_name is None
|
||||
base_color = np.array(mh.pymat.pbr_metallic_roughness.base_color_factor or [1, 1, 1])
|
||||
tex_base_color = mh.pymat.pbr_metallic_roughness.base_color_texture
|
||||
base_color = base_color[:3]
|
||||
|
||||
try:
|
||||
ext_transmission = mh.pymat.extensions['KHR_materials_transmission']
|
||||
transmission_factor = ext_transmission.get('transmissionFactor', 0)
|
||||
tex_transmission_info = ext_transmission.get('transmissionTexture')
|
||||
if tex_transmission_info is not None:
|
||||
tex_transmission_info = TextureInfo.from_dict(tex_transmission_info)
|
||||
pytexture = mh.gltf.data.textures[tex_transmission_info.index]
|
||||
if mh.gltf.import_settings['import_webp_texture'] is True \
|
||||
and pytexture.extensions is not None \
|
||||
and "EXT_texture_webp" in pytexture.extensions:
|
||||
pyimg = mh.gltf.data.images[pytexture.extensions["EXT_texture_webp"]["source"]]
|
||||
transmission_image_name = pyimg.blender_image_name
|
||||
else:
|
||||
pyimg = mh.gltf.data.images[pytexture.source]
|
||||
transmission_image_name = pyimg.blender_image_name
|
||||
else:
|
||||
transmission_image_name = None
|
||||
except Exception:
|
||||
transmission_factor = 0
|
||||
tex_transmission_info = None
|
||||
transmission_image_name = None
|
||||
|
||||
transmission_not_linked = transmission_image_name is None
|
||||
|
||||
try:
|
||||
ext_ior = mh.pymat.extensions['KHR_materials_ior']
|
||||
ior = ext_ior.get('ior', GLTF_IOR)
|
||||
except:
|
||||
ior = GLTF_IOR
|
||||
|
||||
use_texture = tex_specular_info is not None or tex_specular_color_info is not None \
|
||||
or transmission_not_linked is False or base_color_not_linked is False
|
||||
|
||||
|
||||
# Before creating converted textures,
|
||||
# Also plug non converted data into glTF PBR Non Converted Extensions node
|
||||
original_specular( mh,
|
||||
specular_factor,
|
||||
tex_specular_info,
|
||||
specular_color_factor,
|
||||
tex_specular_color_info,
|
||||
original_specular_socket,
|
||||
original_specularcolor_socket,
|
||||
location_original_specular,
|
||||
location_original_specularcolor
|
||||
)
|
||||
|
||||
|
||||
if not use_texture:
|
||||
|
||||
def luminance(c):
|
||||
return 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
|
||||
|
||||
def normalize(c):
|
||||
assert(len(c) == 3)
|
||||
l = luminance(c)
|
||||
if l == 0:
|
||||
return c
|
||||
return np.array([c[0] / l, c[1] / l, c[2] / l])
|
||||
|
||||
f0_from_ior = ((ior - 1)/(ior + 1))**2
|
||||
lum_specular_color = luminance(specular_color_factor)
|
||||
if transmission_factor != 1.0:
|
||||
blender_specular = ((lum_specular_color - transmission_factor) / (1 - transmission_factor)) * (1 / 0.08) * f0_from_ior
|
||||
else:
|
||||
# Avoid division by 0
|
||||
blender_specular = 1.0
|
||||
if not all([i == 0 for i in normalize(base_color) - 1]):
|
||||
blender_specular_tint = luminance((normalize(specular_color_factor) - 1) / (normalize(base_color) - 1))
|
||||
if blender_specular_tint < 0 or blender_specular_tint > 1:
|
||||
# TODOExt Warning clamping
|
||||
blender_specular_tint = np.maximum(np.minimum(blender_specular_tint, 1), 0)
|
||||
else:
|
||||
blender_specular_tint = 1.0
|
||||
|
||||
specular_socket.default_value = blender_specular
|
||||
specular_tint_socket.default_value = [blender_specular_tint]*3 + [1.0] #TODO tmp fix to avoid crash
|
||||
# Note: blender_specular can be greater 1. The Blender documentation permits this.
|
||||
|
||||
return
|
||||
else:
|
||||
# Need to create a texture
|
||||
# First, retrieve and create all images needed
|
||||
|
||||
# Base Color is already created
|
||||
# Transmission is already created
|
||||
# specularTexture is just created by original specular function
|
||||
specular_image_name = None
|
||||
try:
|
||||
pytexture = mh.gltf.data.textures[tex_specular_info.index]
|
||||
if mh.gltf.import_settings['import_webp_texture'] is True \
|
||||
and pytexture.extensions is not None \
|
||||
and "EXT_texture_webp" in pytexture.extensions:
|
||||
pyimg = mh.gltf.data.images[pytexture.extensions["EXT_texture_webp"]["source"]]
|
||||
specular_image_name = pyimg.blender_image_name
|
||||
else:
|
||||
pyimg = mh.gltf.data.images[pytexture.source]
|
||||
specular_image_name = pyimg.blender_image_name
|
||||
except:
|
||||
specular_image_name = None
|
||||
|
||||
|
||||
# specularColorTexture is just created by original specular function
|
||||
specularcolor_image_name = None
|
||||
try:
|
||||
pytexture = mh.gltf.data.textures[tex_specular_color_info.index]
|
||||
if mh.gltf.import_settings['import_webp_texture'] is True \
|
||||
and pytexture.extensions is not None \
|
||||
and "EXT_texture_webp" in pytexture.extensions:
|
||||
pyimg = mh.gltf.data.images[pytexture.extensions["EXT_texture_webp"]["source"]]
|
||||
specularcolor_image_name = pyimg.blender_image_name
|
||||
else:
|
||||
pyimg = mh.gltf.data.images[pytexture.source]
|
||||
specularcolor_image_name = pyimg.blender_image_name
|
||||
except:
|
||||
specularcolor_image_name = None
|
||||
|
||||
stack3 = lambda v: np.dstack([v]*3)
|
||||
|
||||
texts = {
|
||||
base_color_image_name : 'basecolor',
|
||||
transmission_image_name : 'transmission',
|
||||
specularcolor_image_name : 'speccolor',
|
||||
specular_image_name: 'spec'
|
||||
}
|
||||
print("--")
|
||||
print(base_color_image_name)
|
||||
print(transmission_image_name)
|
||||
print(specularcolor_image_name)
|
||||
print(specular_image_name)
|
||||
images = [(name, bpy.data.images[name]) for name in [base_color_image_name, transmission_image_name, specularcolor_image_name, specular_image_name] if name is not None]
|
||||
|
||||
width = max(image[1].size[0] for image in images)
|
||||
height = max(image[1].size[1] for image in images)
|
||||
|
||||
buffers = {}
|
||||
for name, image in images:
|
||||
tmp_buf = np.empty(width * height * 4, np.float32)
|
||||
|
||||
if image.size[0] == width and image.size[1] == height:
|
||||
image.pixels.foreach_get(tmp_buf)
|
||||
else:
|
||||
# Image is the wrong size; make a temp copy and scale it.
|
||||
with TmpImageGuard() as guard:
|
||||
make_temp_image_copy(guard, src_image=image)
|
||||
tmp_image = guard.image
|
||||
tmp_image.scale(width, height)
|
||||
tmp_image.pixels.foreach_get(tmp_buf)
|
||||
|
||||
buffers[texts[name]] = np.reshape(tmp_buf, [width, height, 4])
|
||||
buffers[texts[name]] = buffers[texts[name]][:,:,:3]
|
||||
|
||||
# Manage factors
|
||||
if name == transmission_image_name:
|
||||
buffers[texts[name]] = stack3(buffers[texts[name]][:,:,0]) # Transmission : keep only R channel
|
||||
|
||||
buffers[texts[name]] *= stack3(transmission_factor)
|
||||
|
||||
elif name == base_color_image_name:
|
||||
buffers[texts[name]] *= base_color
|
||||
|
||||
elif name == specularcolor_image_name:
|
||||
buffers[texts[name]] *= specular_color_factor
|
||||
|
||||
# Create buffer if there is no image
|
||||
if 'basecolor' not in buffers.keys():
|
||||
buffers['basecolor'] = np.full((width, height, 3), base_color)
|
||||
if 'transmission' not in buffers.keys():
|
||||
buffers['transmission'] = np.full((width, height, 3), transmission_factor)
|
||||
if 'speccolor' not in buffers.keys():
|
||||
buffers['speccolor'] = np.full((width, height, 3), specular_color_factor)
|
||||
|
||||
# Calculation
|
||||
|
||||
luminance = lambda c: 0.3 * c[:,:,0] + 0.6 * c[:,:,1] + 0.1 * c[:,:,2]
|
||||
def normalize(c):
|
||||
l = luminance(c)
|
||||
if np.all(l == 0.0):
|
||||
return np.array(c)
|
||||
return c / stack3(l)
|
||||
|
||||
f0_from_ior = ((ior - 1)/(ior + 1))**2
|
||||
lum_specular_color = stack3(luminance(buffers['speccolor']))
|
||||
if transmission_factor != 1.0:
|
||||
blender_specular = ((lum_specular_color - buffers['transmission']) / (1 - buffers['transmission'])) * (1 / 0.08) * f0_from_ior
|
||||
else:
|
||||
# Avoid division by 0
|
||||
blender_specular = np.full((width, height, 3), 1.0)
|
||||
if not np.all(normalize(buffers['basecolor']) - 1 == 0.0):
|
||||
blender_specular_tint = luminance((normalize(buffers['speccolor']) - 1) / (normalize(buffers['basecolor']) - 1))
|
||||
np.nan_to_num(blender_specular_tint, copy=False)
|
||||
blender_specular_tint = np.clip(blender_specular_tint, 0.0, 1.0)
|
||||
blender_specular_tint = stack3(blender_specular_tint)
|
||||
else:
|
||||
blender_specular_tint = stack3(np.ones((width, height)))
|
||||
|
||||
blender_specular = np.dstack((blender_specular, np.ones((width, height)))) # Set alpha to 1
|
||||
blender_specular_tint = np.dstack((blender_specular_tint, np.ones((width, height)))) # Set alpha to 1
|
||||
|
||||
# Check if we really need to create a texture
|
||||
blender_specular_tex_not_needed = np.all(np.isclose(blender_specular, blender_specular[0][0]))
|
||||
blender_specular_tint_tex_not_needed = np.all(np.isclose(blender_specular_tint, blender_specular_tint[0][0]))
|
||||
|
||||
if blender_specular_tex_not_needed == True:
|
||||
lum = lambda c: 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
|
||||
specular_socket.default_value = lum(blender_specular[0][0][:3])
|
||||
else:
|
||||
blender_specular = np.reshape(blender_specular, width * height * 4)
|
||||
# Create images in Blender, width and height are dummy values, then set packed file data
|
||||
blender_image_spec = bpy.data.images.new('Specular', width, height)
|
||||
blender_image_spec.pixels.foreach_set(np.float32(blender_specular))
|
||||
blender_image_spec.pack()
|
||||
|
||||
# Create Textures in Blender
|
||||
tex_info = tex_specular_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_specular_color_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_transmission_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_base_color
|
||||
|
||||
texture(
|
||||
mh,
|
||||
tex_info=tex_info,
|
||||
label='SPECULAR',
|
||||
location=(x_specular, y_specular),
|
||||
is_data=True,
|
||||
color_socket=specular_socket,
|
||||
forced_image=blender_image_spec
|
||||
)
|
||||
|
||||
if blender_specular_tint_tex_not_needed == True:
|
||||
lum = lambda c: 0.3 * c[0] + 0.6 * c[1] + 0.1 * c[2]
|
||||
specular_tint_socket.default_value = [lum(blender_specular_tint[0][0])]*3 + [1.0] #TODO tmp fix to avoid crash
|
||||
else:
|
||||
blender_specular_tint = np.reshape(blender_specular_tint, width * height * 4)
|
||||
# Create images in Blender, width and height are dummy values, then set packed file data
|
||||
blender_image_tint = bpy.data.images.new('Specular Tint', width, height)
|
||||
blender_image_tint.pixels.foreach_set(np.float32(blender_specular_tint))
|
||||
blender_image_tint.pack()
|
||||
|
||||
# Create Textures in Blender
|
||||
tex_info = tex_specular_color_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_specular_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_transmission_info
|
||||
if tex_info is None:
|
||||
tex_info = tex_base_color
|
||||
|
||||
texture(
|
||||
mh,
|
||||
tex_info=tex_info,
|
||||
label='SPECULAR TINT',
|
||||
location=(x_tint, y_tint),
|
||||
is_data=True,
|
||||
color_socket=specular_tint_socket,
|
||||
forced_image=blender_image_tint
|
||||
)
|
||||
|
||||
def original_specular( mh,
|
||||
specular_factor,
|
||||
tex_specular_info,
|
||||
specular_color_factor,
|
||||
tex_specular_color_info,
|
||||
original_specular_socket,
|
||||
original_specularcolor_socket,
|
||||
location_original_specular,
|
||||
location_original_specularcolor
|
||||
):
|
||||
|
||||
x_specular, y_specular = location_original_specular
|
||||
x_specularcolor, y_specularcolor = location_original_specularcolor
|
||||
x_specular, y_specular = location_specular
|
||||
x_specularcolor, y_specularcolor = location_specular_tint
|
||||
|
||||
if tex_specular_info is None:
|
||||
original_specular_socket.default_value = specular_factor
|
||||
specular_socket.default_value = specular_factor
|
||||
else:
|
||||
# Mix specular factor
|
||||
if specular_factor != 1.0:
|
||||
@ -348,9 +48,9 @@ def original_specular( mh,
|
||||
node.location = x_specular - 140, y_specular
|
||||
node.operation = 'MULTIPLY'
|
||||
# Outputs
|
||||
mh.node_tree.links.new(original_specular_socket, node.outputs[0])
|
||||
mh.node_tree.links.new(specular_socket, node.outputs[0])
|
||||
# Inputs
|
||||
original_specular_socket = node.inputs[0]
|
||||
specular_socket = node.inputs[0]
|
||||
node.inputs[1].default_value = specular_factor
|
||||
x_specular -= 200
|
||||
|
||||
@ -361,16 +61,16 @@ def original_specular( mh,
|
||||
location=(x_specular, y_specular),
|
||||
is_data=True,
|
||||
color_socket=None,
|
||||
alpha_socket=original_specular_socket
|
||||
alpha_socket=specular_socket
|
||||
)
|
||||
|
||||
if tex_specular_color_info is None:
|
||||
specular_color_factor = list(specular_color_factor)
|
||||
specular_color_factor.extend([1.0])
|
||||
original_specularcolor_socket.default_value = specular_color_factor
|
||||
if tex_specular_tint_info is None:
|
||||
specular_tint_factor = list(specular_tint_factor)
|
||||
specular_tint_factor.extend([1.0])
|
||||
specular_tint_socket.default_value = specular_tint_factor
|
||||
else:
|
||||
specular_color_factor = list(specular_color_factor) + [1.0]
|
||||
if specular_color_factor != [1.0, 1.0, 1.0, 1.0]:
|
||||
specular_tint_factor = list(specular_tint_factor) + [1.0]
|
||||
if specular_tint_factor != [1.0, 1.0, 1.0, 1.0]:
|
||||
# Mix specularColorFactor
|
||||
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
||||
node.label = 'SpecularColor Factor'
|
||||
@ -378,17 +78,17 @@ def original_specular( mh,
|
||||
node.location = x_specularcolor - 140, y_specularcolor
|
||||
node.blend_type = 'MULTIPLY'
|
||||
# Outputs
|
||||
mh.node_tree.links.new(original_specularcolor_socket, node.outputs[2])
|
||||
mh.node_tree.links.new(specular_tint_socket, node.outputs[2])
|
||||
# Inputs
|
||||
node.inputs['Factor'].default_value = 1.0
|
||||
original_specularcolor_socket = node.inputs[6]
|
||||
node.inputs[7].default_value = specular_color_factor
|
||||
specular_tint_socket = node.inputs[6]
|
||||
node.inputs[7].default_value = specular_tint_factor
|
||||
x_specularcolor -= 200
|
||||
|
||||
texture(
|
||||
mh,
|
||||
tex_info=tex_specular_color_info,
|
||||
tex_info=tex_specular_tint_info,
|
||||
label='SPECULAR COLOR',
|
||||
location=(x_specularcolor, y_specularcolor),
|
||||
color_socket=original_specularcolor_socket,
|
||||
color_socket=specular_tint_socket,
|
||||
)
|
||||
|
@ -25,15 +25,14 @@ def unlit(mh):
|
||||
mh.node_tree.links.new(mix_node.inputs[1], transparent_node.outputs[0])
|
||||
mh.node_tree.links.new(mix_node.inputs[2], emission_node.outputs[0])
|
||||
|
||||
_emission_socket, alpha_socket, _, _ = make_output_nodes(
|
||||
_emission_socket, alpha_socket, _ = make_output_nodes(
|
||||
mh,
|
||||
location=(420, 280) if mh.is_opaque() else (150, 130),
|
||||
additional_location=None, #No additional location needed for Unlit
|
||||
shader_socket=mix_node.outputs[0],
|
||||
make_emission_socket=False,
|
||||
make_alpha_socket=not mh.is_opaque(),
|
||||
make_volume_socket=None, # Not possible to have KHR_materials_volume with unlit
|
||||
make_sheen_socket=None #Not possible to have KHR_materials_sheen with unlit
|
||||
make_volume_socket=None # Not possible to have KHR_materials_volume with unlit
|
||||
)
|
||||
|
||||
base_color(
|
||||
|
@ -50,7 +50,10 @@ def pbr_metallic_roughness(mh: MaterialHelper):
|
||||
# This value may be overridden later if IOR extension is set on file
|
||||
pbr_node.inputs['IOR'].default_value = GLTF_IOR
|
||||
|
||||
if mh.pymat.occlusion_texture is not None or (mh.pymat.extensions and 'KHR_materials_specular' in mh.pymat.extensions):
|
||||
pbr_node.inputs['Specular IOR Level'].default_value = 0.0 # Will be overridden by KHR_materials_specular if set
|
||||
pbr_node.inputs['Specular Tint'].default_value = [0.0]*3 + [1.0] # Will be overridden by KHR_materials_specular if set
|
||||
|
||||
if mh.pymat.occlusion_texture is not None:
|
||||
if mh.settings_node is None:
|
||||
mh.settings_node = make_settings_node(mh)
|
||||
mh.settings_node.location = additional_location
|
||||
@ -69,28 +72,19 @@ def pbr_metallic_roughness(mh: MaterialHelper):
|
||||
mh.settings_node = make_settings_node(mh)
|
||||
mh.settings_node.location = additional_location
|
||||
mh.settings_node.width = 180
|
||||
volume_location = additional_location
|
||||
additional_location = additional_location[0], additional_location[1] - 150
|
||||
|
||||
need_sheen_node = False
|
||||
if mh.pymat.extensions and 'KHR_materials_sheen' in mh.pymat.extensions:
|
||||
need_sheen_node = True
|
||||
|
||||
_, _, volume_socket, sheen_node = make_output_nodes(
|
||||
_, _, volume_socket = make_output_nodes(
|
||||
mh,
|
||||
location=(250, 260),
|
||||
additional_location=additional_location,
|
||||
shader_socket=pbr_node.outputs[0],
|
||||
make_emission_socket=False, # is managed by Principled shader node
|
||||
make_alpha_socket=False, # is managed by Principled shader node
|
||||
make_volume_socket=need_volume_node,
|
||||
make_sheen_socket=need_sheen_node
|
||||
make_volume_socket=need_volume_node
|
||||
)
|
||||
|
||||
|
||||
if mh.pymat.extensions and 'KHR_materials_sheen':
|
||||
pass #TOTOEXT
|
||||
|
||||
locs = calc_locations(mh)
|
||||
|
||||
emission(
|
||||
@ -164,21 +158,17 @@ def pbr_metallic_roughness(mh: MaterialHelper):
|
||||
location_specular=locs['specularTexture'],
|
||||
location_specular_tint=locs['specularColorTexture'],
|
||||
specular_socket=pbr_node.inputs['Specular IOR Level'],
|
||||
specular_tint_socket=pbr_node.inputs['Specular Tint'],
|
||||
original_specular_socket=mh.settings_node.inputs[2] if mh.settings_node else None,
|
||||
original_specularcolor_socket=mh.settings_node.inputs[3] if mh.settings_node else None,
|
||||
location_original_specular=locs['original_specularTexture'],
|
||||
location_original_specularcolor=locs['original_specularColorTexture']
|
||||
specular_tint_socket=pbr_node.inputs['Specular Tint']
|
||||
)
|
||||
|
||||
if need_sheen_node:
|
||||
sheen(
|
||||
mh,
|
||||
location_sheenColor=locs['sheenColorTexture'],
|
||||
location_sheenRoughness=locs['sheenRoughnessTexture'],
|
||||
sheenColor_socket=sheen_node.inputs[0],
|
||||
sheenRoughness_socket=sheen_node.inputs[1]
|
||||
)
|
||||
sheen(
|
||||
mh,
|
||||
location_sheenTint=locs['sheenColorTexture'],
|
||||
location_sheenRoughness=locs['sheenRoughnessTexture'],
|
||||
sheen_socket=pbr_node.inputs['Sheen Weight'],
|
||||
sheenTint_socket=pbr_node.inputs['Sheen Tint'],
|
||||
sheenRoughness_socket=pbr_node.inputs['Sheen Roughness']
|
||||
)
|
||||
|
||||
ior(
|
||||
mh,
|
||||
@ -219,12 +209,6 @@ def calc_locations(mh):
|
||||
except:
|
||||
sheen_ext = {}
|
||||
|
||||
locs['sheenColorTexture'] = (x, y)
|
||||
if 'sheenColorTexture' in sheen_ext:
|
||||
y -= height
|
||||
locs['sheenRoughnessTexture'] = (x, y)
|
||||
if 'sheenRoughnessTexture' in sheen_ext:
|
||||
y -= height
|
||||
locs['base_color'] = (x, y)
|
||||
if mh.pymat.pbr_metallic_roughness.base_color_texture is not None or mh.vertex_color:
|
||||
y -= height
|
||||
@ -243,6 +227,12 @@ def calc_locations(mh):
|
||||
locs['specularColorTexture'] = (x, y)
|
||||
if 'specularColorTexture' in specular_ext:
|
||||
y -= height
|
||||
locs['sheenRoughnessTexture'] = (x, y)
|
||||
if 'sheenRoughnessTexture' in sheen_ext:
|
||||
y -= height
|
||||
locs['sheenColorTexture'] = (x, y)
|
||||
if 'sheenColorTexture' in sheen_ext:
|
||||
y -= height
|
||||
locs['clearcoat'] = (x, y)
|
||||
if 'clearcoatTexture' in clearcoat_ext:
|
||||
y -= height
|
||||
@ -261,19 +251,6 @@ def calc_locations(mh):
|
||||
locs['volume_thickness'] = (x, y)
|
||||
if 'thicknessTexture' in volume_ext:
|
||||
y -= height
|
||||
locs['original_specularTexture'] = (x, y)
|
||||
if 'specularTexture' in specular_ext:
|
||||
y -= height
|
||||
locs['original_specularColorTexture'] = (x, y)
|
||||
if 'specularColorTexture' in specular_ext:
|
||||
y -= height
|
||||
locs['original_sheenColorTexture'] = (x, y)
|
||||
if 'sheenColorTexture' in sheen_ext:
|
||||
y -= height
|
||||
locs['original_sheenRoughnessTexture'] = (x, y)
|
||||
if 'sheenRoughnessTexture' in sheen_ext:
|
||||
y -= height
|
||||
|
||||
|
||||
# Center things
|
||||
total_height = -y
|
||||
@ -306,6 +283,11 @@ def emission(mh: MaterialHelper, location, color_socket, strength_socket):
|
||||
return
|
||||
|
||||
if mh.pymat.emissive_texture is None:
|
||||
if emissive_factor == [0, 0, 0]:
|
||||
# Keep as close as possible to the default Blender value when there is no emission
|
||||
color_socket.default_value = [1,1,1,1]
|
||||
strength_socket.default_value = 0
|
||||
return
|
||||
color_socket.default_value = emissive_factor + [1]
|
||||
strength_socket.default_value = strength
|
||||
return
|
||||
@ -624,12 +606,11 @@ def make_output_nodes(
|
||||
shader_socket,
|
||||
make_emission_socket,
|
||||
make_alpha_socket,
|
||||
make_volume_socket,
|
||||
make_sheen_socket,
|
||||
make_volume_socket
|
||||
):
|
||||
"""
|
||||
Creates the Material Output node and connects shader_socket to it.
|
||||
If requested, it can also create places to hookup the emission/alpha.sheen
|
||||
If requested, it can also create places to hookup the emission/alpha
|
||||
in between shader_socket and the Output node too.
|
||||
|
||||
:return: a pair containing the sockets you should put emission and alpha
|
||||
@ -637,7 +618,6 @@ def make_output_nodes(
|
||||
"""
|
||||
x, y = location
|
||||
emission_socket = None
|
||||
sheen_node = None
|
||||
alpha_socket = None
|
||||
|
||||
# Create an Emission node and add it to the shader.
|
||||
@ -666,31 +646,6 @@ def make_output_nodes(
|
||||
x += 380
|
||||
y += 125
|
||||
|
||||
# Create an Sheen node add add it to the shader
|
||||
# Note that you can not have Emission & Sheen at the same time
|
||||
if make_sheen_socket:
|
||||
# Sheen
|
||||
node = mh.node_tree.nodes.new("ShaderNodeBsdfSheen")
|
||||
node.location = x + 50, y + 250
|
||||
# Node
|
||||
sheen_node = node
|
||||
# Outputs
|
||||
sheen_output = node.outputs[0]
|
||||
|
||||
# Add
|
||||
node = mh.node_tree.nodes.new('ShaderNodeAddShader')
|
||||
node.location = x + 250, y + 160
|
||||
# Inputs
|
||||
mh.node_tree.links.new(node.inputs[0], sheen_output)
|
||||
mh.node_tree.links.new(node.inputs[1], shader_socket)
|
||||
# Outputs
|
||||
shader_socket = node.outputs[0]
|
||||
|
||||
|
||||
x += 380
|
||||
y += 125
|
||||
|
||||
|
||||
# Mix with a Transparent BSDF. Mixing factor is the alpha value.
|
||||
if make_alpha_socket:
|
||||
# Transparent BSDF
|
||||
@ -730,7 +685,7 @@ def make_output_nodes(
|
||||
volume_socket = node.outputs[0]
|
||||
|
||||
|
||||
return emission_socket, alpha_socket, volume_socket, sheen_node
|
||||
return emission_socket, alpha_socket, volume_socket
|
||||
|
||||
|
||||
def make_settings_node(mh):
|
||||
|
@ -539,7 +539,7 @@ class NWPreviewNode(Operator, NWBase):
|
||||
|
||||
if not viewer_socket:
|
||||
# create viewer socket
|
||||
viewer_socket = node.node_tree.interface.new_socket(viewer_socket_name, in_out={'OUTPUT'}, socket_type=socket_type)
|
||||
viewer_socket = node.node_tree.interface.new_socket(viewer_socket_name, in_out='OUTPUT', socket_type=socket_type)
|
||||
viewer_socket.NWViewerSocket = True
|
||||
return viewer_socket
|
||||
|
||||
|
@ -164,7 +164,7 @@ def create_path(scene):
|
||||
|
||||
|
||||
class SVGExporterLinesetPanel(bpy.types.Panel):
|
||||
"""Creates a Panel in the Render Layers context of the properties editor"""
|
||||
"""Creates a panel in the View Layer context of the properties editor"""
|
||||
bl_idname = "RENDER_PT_SVGExporterLinesetPanel"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_label = "Freestyle Line Style SVG Export"
|
||||
|
@ -46,7 +46,7 @@ PROMOTED_FEATURE_SETS = [
|
||||
"name": "Cessen's Rigify Extensions",
|
||||
"author": "Nathan Vegdahl",
|
||||
"description": "Collection of original legacy Rigify rigs minimally ported to the modern Rigify",
|
||||
"warning": "This feature set is maintaned at the bare minimal level",
|
||||
"warning": "This feature set is maintained at the bare minimal level",
|
||||
"link": "https://github.com/cessen/cessen_rigify_ext",
|
||||
}
|
||||
]
|
||||
|
@ -163,7 +163,7 @@ def i18n_updatetranslation_blender_repo_callback(lng, settings):
|
||||
|
||||
|
||||
class UI_OT_i18n_updatetranslation_blender_repo(Operator):
|
||||
"""Update i18n data (po files) in Blneder source code repository"""
|
||||
"""Update i18n data (po files) in Blender source code repository"""
|
||||
bl_idname = "ui.i18n_updatetranslation_blender_repo"
|
||||
bl_label = "Update I18n Blender Repo"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user