New Addon: Import Autodesk .max #105013
@ -5,8 +5,8 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Add Camera Rigs",
|
"name": "Add Camera Rigs",
|
||||||
"author": "Wayne Dixon, Brian Raschko, Kris Wittig, Damien Picard, Flavio Perez",
|
"author": "Wayne Dixon, Brian Raschko, Kris Wittig, Damien Picard, Flavio Perez",
|
||||||
"version": (1, 5, 1),
|
"version": (1, 6, 0),
|
||||||
"blender": (3, 3, 0),
|
"blender": (4, 0, 0),
|
||||||
"location": "View3D > Add > Camera > Dolly or Crane Rig",
|
"location": "View3D > Add > Camera > Dolly or Crane Rig",
|
||||||
"description": "Adds a Camera Rig with UI",
|
"description": "Adds a Camera Rig with UI",
|
||||||
"doc_url": "{BLENDER_MANUAL_URL}/addons/camera/camera_rigs.html",
|
"doc_url": "{BLENDER_MANUAL_URL}/addons/camera/camera_rigs.html",
|
||||||
|
@ -36,26 +36,35 @@ def create_dolly_bones(rig):
|
|||||||
root = bones.new("Root")
|
root = bones.new("Root")
|
||||||
root.tail = (0.0, 1.0, 0.0)
|
root.tail = (0.0, 1.0, 0.0)
|
||||||
root.show_wire = True
|
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.head = (0.0, 10.0, 1.7)
|
||||||
ctrl_aim_child.tail = (0.0, 11.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 = bones.new("Aim")
|
||||||
ctrl_aim.head = (0.0, 10.0, 1.7)
|
ctrl_aim.head = (0.0, 10.0, 1.7)
|
||||||
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
||||||
ctrl_aim.show_wire = True
|
ctrl_aim.show_wire = True
|
||||||
|
rig.data.collections['Controls'].assign(ctrl_aim)
|
||||||
|
|
||||||
ctrl = bones.new("Camera")
|
ctrl = bones.new("Camera")
|
||||||
ctrl.head = (0.0, 0.0, 1.7)
|
ctrl.head = (0.0, 0.0, 1.7)
|
||||||
ctrl.tail = (0.0, 1.0, 1.7)
|
ctrl.tail = (0.0, 1.0, 1.7)
|
||||||
ctrl.show_wire = True
|
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.head = (0.0, 0.0, 1.7)
|
||||||
ctrl_offset.tail = (0.0, 1.0, 1.7)
|
ctrl_offset.tail = (0.0, 1.0, 1.7)
|
||||||
ctrl_offset.show_wire = True
|
ctrl_offset.show_wire = True
|
||||||
|
rig.data.collections['Controls'].assign(ctrl_offset)
|
||||||
|
|
||||||
|
|
||||||
# Setup hierarchy
|
# Setup hierarchy
|
||||||
ctrl.parent = root
|
ctrl.parent = root
|
||||||
@ -67,7 +76,7 @@ def create_dolly_bones(rig):
|
|||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
pose_bones = rig.pose.bones
|
pose_bones = rig.pose.bones
|
||||||
# Lock the relevant scale channels of the Camera_offset bone
|
# 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):
|
def create_crane_bones(rig):
|
||||||
@ -78,42 +87,51 @@ def create_crane_bones(rig):
|
|||||||
root = bones.new("Root")
|
root = bones.new("Root")
|
||||||
root.tail = (0.0, 1.0, 0.0)
|
root.tail = (0.0, 1.0, 0.0)
|
||||||
root.show_wire = True
|
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.head = (0.0, 10.0, 1.7)
|
||||||
ctrl_aim_child.tail = (0.0, 11.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 = bones.new("Aim")
|
||||||
ctrl_aim.head = (0.0, 10.0, 1.7)
|
ctrl_aim.head = (0.0, 10.0, 1.7)
|
||||||
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
ctrl_aim.tail = (0.0, 11.0, 1.7)
|
||||||
ctrl_aim.show_wire = True
|
ctrl_aim.show_wire = True
|
||||||
|
rig.data.collections['Controls'].assign(ctrl_aim)
|
||||||
|
|
||||||
ctrl = bones.new("Camera")
|
ctrl = bones.new("Camera")
|
||||||
ctrl.head = (0.0, 1.0, 1.7)
|
ctrl.head = (0.0, 1.0, 1.7)
|
||||||
ctrl.tail = (0.0, 2.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.head = (0.0, 1.0, 1.7)
|
||||||
ctrl_offset.tail = (0.0, 2.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.head = (0.0, 0.0, 1.7)
|
||||||
arm.tail = (0.0, 1.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.head = (0.0, 0.0, 0.0)
|
||||||
height.tail = (0.0, 0.0, 1.7)
|
height.tail = (0.0, 0.0, 1.7)
|
||||||
|
rig.data.collections['Controls'].assign(height)
|
||||||
|
|
||||||
# Setup hierarchy
|
# Setup hierarchy
|
||||||
ctrl.parent = arm
|
ctrl.parent = arm
|
||||||
ctrl_offset.parent = ctrl
|
ctrl_offset.parent = ctrl
|
||||||
ctrl.use_inherit_rotation = False
|
ctrl.use_inherit_rotation = False
|
||||||
ctrl.use_inherit_scale = False
|
ctrl.inherit_scale = "NONE"
|
||||||
ctrl.show_wire = True
|
ctrl.show_wire = True
|
||||||
|
|
||||||
arm.parent = height
|
arm.parent = height
|
||||||
arm.use_inherit_scale = False
|
arm.inherit_scale = "NONE"
|
||||||
|
|
||||||
height.parent = root
|
height.parent = root
|
||||||
ctrl_aim.parent = root
|
ctrl_aim.parent = root
|
||||||
@ -124,12 +142,12 @@ def create_crane_bones(rig):
|
|||||||
pose_bones = rig.pose.bones
|
pose_bones = rig.pose.bones
|
||||||
|
|
||||||
# Lock the relevant loc, rot and scale
|
# Lock the relevant loc, rot and scale
|
||||||
pose_bones["Crane_arm"].lock_rotation = (False, True, False)
|
pose_bones["Crane_Arm"].lock_rotation = (False, True, False)
|
||||||
pose_bones["Crane_arm"].lock_scale = (True, False, True)
|
pose_bones["Crane_Arm"].lock_scale = (True, False, True)
|
||||||
pose_bones["Crane_height"].lock_location = (True,) * 3
|
pose_bones["Crane_Height"].lock_location = (True,) * 3
|
||||||
pose_bones["Crane_height"].lock_rotation = (True,) * 3
|
pose_bones["Crane_Height"].lock_rotation = (True,) * 3
|
||||||
pose_bones["Crane_height"].lock_scale = (True, False, True)
|
pose_bones["Crane_Height"].lock_scale = (True, False, True)
|
||||||
pose_bones["Camera_offset"].lock_scale = (True,) * 3
|
pose_bones["Camera_Offset"].lock_scale = (True,) * 3
|
||||||
|
|
||||||
|
|
||||||
def setup_3d_rig(rig, cam):
|
def setup_3d_rig(rig, cam):
|
||||||
@ -149,20 +167,20 @@ def setup_3d_rig(rig, cam):
|
|||||||
# Build the widgets
|
# Build the widgets
|
||||||
root_widget = create_root_widget("Camera_Root")
|
root_widget = create_root_widget("Camera_Root")
|
||||||
camera_widget = create_camera_widget("Camera")
|
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")
|
aim_widget = create_aim_widget("Aim")
|
||||||
|
|
||||||
# Add the custom bone shapes
|
# Add the custom bone shapes
|
||||||
pose_bones["Root"].custom_shape = root_widget
|
pose_bones["Root"].custom_shape = root_widget
|
||||||
pose_bones["Aim"].custom_shape = aim_widget
|
pose_bones["Aim"].custom_shape = aim_widget
|
||||||
pose_bones["Camera"].custom_shape = camera_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
|
# 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
|
# 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.target = rig
|
||||||
con.subtarget = "Camera"
|
con.subtarget = "Camera"
|
||||||
|
|
||||||
@ -189,29 +207,38 @@ def create_2d_bones(context, rig, cam):
|
|||||||
root = bones.new("Root")
|
root = bones.new("Root")
|
||||||
root.tail = Vector((0.0, 0.0, 1.0))
|
root.tail = Vector((0.0, 0.0, 1.0))
|
||||||
root.show_wire = True
|
root.show_wire = True
|
||||||
|
rig.data.collections.new(name="Controls")
|
||||||
|
rig.data.collections['Controls'].assign(root)
|
||||||
|
|
||||||
ctrl = bones.new('Camera')
|
ctrl = bones.new('Camera')
|
||||||
ctrl.tail = Vector((0.0, 0.0, 1.0))
|
ctrl.tail = Vector((0.0, 0.0, 1.0))
|
||||||
ctrl.show_wire = True
|
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.head = (-3, 10, -2)
|
||||||
left_corner.tail = left_corner.head + Vector((0.0, 0.0, 1.0))
|
left_corner.tail = left_corner.head + Vector((0.0, 0.0, 1.0))
|
||||||
left_corner.show_wire = True
|
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.head = (3, 10, -2)
|
||||||
right_corner.tail = right_corner.head + Vector((0.0, 0.0, 1.0))
|
right_corner.tail = right_corner.head + Vector((0.0, 0.0, 1.0))
|
||||||
right_corner.show_wire = True
|
right_corner.show_wire = True
|
||||||
|
rig.data.collections['Controls'].assign(right_corner)
|
||||||
|
|
||||||
corner_distance_x = (left_corner.head - right_corner.head).length
|
corner_distance_x = (left_corner.head - right_corner.head).length
|
||||||
corner_distance_y = -left_corner.head.z
|
corner_distance_y = -left_corner.head.z
|
||||||
corner_distance_z = left_corner.head.y
|
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.head = ((right_corner.head + left_corner.head) / 2.0)
|
||||||
center.tail = center.head + Vector((0.0, 0.0, 1.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
|
center.show_wire = True
|
||||||
|
|
||||||
# Setup hierarchy
|
# Setup hierarchy
|
||||||
@ -227,7 +254,7 @@ def create_2d_bones(context, rig, cam):
|
|||||||
bone.rotation_mode = 'XYZ'
|
bone.rotation_mode = 'XYZ'
|
||||||
|
|
||||||
# Bone drivers
|
# Bone drivers
|
||||||
center_drivers = pose_bones["Center-MCH"].driver_add("location")
|
center_drivers = pose_bones["MCH-Center"].driver_add("location")
|
||||||
|
|
||||||
# Center X driver
|
# Center X driver
|
||||||
driver = center_drivers[0].driver
|
driver = center_drivers[0].driver
|
||||||
@ -238,7 +265,7 @@ def create_2d_bones(context, rig, cam):
|
|||||||
var.name = corner
|
var.name = corner
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_X'
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
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.name = '%s_%s' % (corner, direction)
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_' + direction.upper()
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||||
|
|
||||||
@ -275,31 +302,31 @@ def create_2d_bones(context, rig, cam):
|
|||||||
var.name = corner
|
var.name = corner
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_Z'
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||||
|
|
||||||
# Bone constraints
|
# Bone constraints
|
||||||
con = pose_bones["Camera"].constraints.new('DAMPED_TRACK')
|
con = pose_bones["Camera"].constraints.new('DAMPED_TRACK')
|
||||||
con.target = rig
|
con.target = rig
|
||||||
con.subtarget = "Center-MCH"
|
con.subtarget = "MCH-Center"
|
||||||
con.track_axis = 'TRACK_NEGATIVE_Z'
|
con.track_axis = 'TRACK_NEGATIVE_Z'
|
||||||
|
|
||||||
# Build the widgets
|
# Build the widgets
|
||||||
left_widget = create_corner_widget("Left_corner", reverse=True)
|
left_widget = create_corner_widget("Left_Corner", reverse=True)
|
||||||
right_widget = create_corner_widget("Right_corner")
|
right_widget = create_corner_widget("Right_Corner")
|
||||||
parent_widget = create_circle_widget("Root", radius=0.5)
|
parent_widget = create_circle_widget("Root", radius=0.5)
|
||||||
camera_widget = create_circle_widget("Camera_2D", radius=0.3)
|
camera_widget = create_circle_widget("Camera_2D", radius=0.3)
|
||||||
|
|
||||||
# Add the custom bone shapes
|
# Add the custom bone shapes
|
||||||
pose_bones["Left_corner"].custom_shape = left_widget
|
pose_bones["Left_Corner"].custom_shape = left_widget
|
||||||
pose_bones["Right_corner"].custom_shape = right_widget
|
pose_bones["Right_Corner"].custom_shape = right_widget
|
||||||
pose_bones["Root"].custom_shape = parent_widget
|
pose_bones["Root"].custom_shape = parent_widget
|
||||||
pose_bones["Camera"].custom_shape = camera_widget
|
pose_bones["Camera"].custom_shape = camera_widget
|
||||||
|
|
||||||
# Lock the relevant loc, rot and scale
|
# Lock the relevant loc, rot and scale
|
||||||
pose_bones["Left_corner"].lock_rotation = (True,) * 3
|
pose_bones["Left_Corner"].lock_rotation = (True,) * 3
|
||||||
pose_bones["Right_corner"].lock_rotation = (True,) * 3
|
pose_bones["Right_Corner"].lock_rotation = (True,) * 3
|
||||||
pose_bones["Camera"].lock_rotation = (True,) * 3
|
pose_bones["Camera"].lock_rotation = (True,) * 3
|
||||||
pose_bones["Camera"].lock_scale = (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.name = 'frame_width'
|
||||||
var.type = 'LOC_DIFF'
|
var.type = 'LOC_DIFF'
|
||||||
var.targets[0].id = rig
|
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[0].transform_space = 'WORLD_SPACE'
|
||||||
var.targets[1].id = rig
|
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'
|
var.targets[1].transform_space = 'WORLD_SPACE'
|
||||||
|
|
||||||
for corner in ('left', 'right'):
|
for corner in ('left', 'right'):
|
||||||
@ -342,7 +369,7 @@ def create_2d_bones(context, rig, cam):
|
|||||||
var.name = corner + '_z'
|
var.name = corner + '_z'
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_Z'
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||||
|
|
||||||
@ -363,7 +390,7 @@ def create_2d_bones(context, rig, cam):
|
|||||||
var.name = corner + '_x'
|
var.name = corner + '_x'
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_X'
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
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.name = '%s_%s' % (corner, direction)
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_' + direction.upper()
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
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.name = '%s_%s' % (corner, direction)
|
||||||
var.type = 'TRANSFORMS'
|
var.type = 'TRANSFORMS'
|
||||||
var.targets[0].id = rig
|
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_type = 'LOC_' + direction.upper()
|
||||||
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
var.targets[0].transform_space = 'TRANSFORM_SPACE'
|
||||||
|
|
||||||
@ -484,7 +511,7 @@ def build_camera_rig(context, mode):
|
|||||||
if mode == "2D":
|
if mode == "2D":
|
||||||
cam.parent_bone = "Camera"
|
cam.parent_bone = "Camera"
|
||||||
else:
|
else:
|
||||||
cam.parent_bone = "Camera_offset"
|
cam.parent_bone = "Camera_Offset"
|
||||||
|
|
||||||
# Change display to BBone: it just looks nicer
|
# Change display to BBone: it just looks nicer
|
||||||
rig.data.display_type = 'BBONE'
|
rig.data.display_type = 'BBONE'
|
||||||
|
@ -63,7 +63,7 @@ class ExportUVLayout(bpy.types.Operator):
|
|||||||
items=(
|
items=(
|
||||||
('SVG', "Scalable Vector Graphic (.svg)",
|
('SVG', "Scalable Vector Graphic (.svg)",
|
||||||
"Export the UV layout to a vector SVG file"),
|
"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"),
|
"Export the UV layout to a vector EPS file"),
|
||||||
('PNG', "PNG Image (.png)",
|
('PNG', "PNG Image (.png)",
|
||||||
"Export the UV layout to a bitmap image"),
|
"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)
|
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_color_chunk.add_variable("color", _3ds_float_color(bg_color))
|
||||||
background_chunk.add_subchunk(background_color_chunk)
|
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_image = _3ds_chunk(BITMAP)
|
||||||
background_flag = _3ds_chunk(USE_BITMAP)
|
background_flag = _3ds_chunk(USE_BITMAP)
|
||||||
background_image.add_variable("image", _3ds_string(sane_name(bg_image.name)))
|
background_image.add_variable("image", _3ds_string(sane_name(bg_image.name)))
|
||||||
@ -1938,9 +1938,8 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
|
|||||||
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
||||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||||
obj_hierarchy_chunk.add_variable("hierarchy", _3ds_ushort(object_id[ob.name]))
|
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):
|
if ob.parent is not None and (ob.parent.name in object_id):
|
||||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||||
else: # Get the parent ID from the object_id dict
|
|
||||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(object_id[ob.parent.name]))
|
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)
|
object_chunk.add_subchunk(obj_hierarchy_chunk)
|
||||||
@ -1976,9 +1975,8 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
|
|||||||
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
obj_hierarchy_chunk = _3ds_chunk(OBJECT_HIERARCHY)
|
||||||
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||||
obj_hierarchy_chunk.add_variable("hierarchy", _3ds_ushort(object_id[ob.name]))
|
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):
|
if ob.parent is not None and (ob.parent.name in object_id):
|
||||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
obj_parent_chunk = _3ds_chunk(OBJECT_PARENT)
|
||||||
else: # Get the parent ID from the object_id dict
|
|
||||||
obj_parent_chunk.add_variable("parent", _3ds_ushort(object_id[ob.parent.name]))
|
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)
|
object_chunk.add_subchunk(obj_hierarchy_chunk)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
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": (4, 0, 31),
|
"version": (4, 0, 32),
|
||||||
'blender': (4, 0, 0),
|
'blender': (4, 0, 0),
|
||||||
'location': 'File > Import-Export',
|
'location': 'File > Import-Export',
|
||||||
'description': 'Import-Export as glTF 2.0',
|
'description': 'Import-Export as glTF 2.0',
|
||||||
@ -326,14 +326,6 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
|
|||||||
default='EXPORT'
|
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(
|
export_colors: BoolProperty(
|
||||||
name='Vertex Colors',
|
name='Vertex Colors',
|
||||||
description='Export vertex colors with meshes',
|
description='Export vertex colors with meshes',
|
||||||
@ -680,6 +672,15 @@ class ExportGLTF2_Base(ConvertGLTF2_Base):
|
|||||||
default=True
|
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(
|
will_save_settings: BoolProperty(
|
||||||
name='Remember Export Settings',
|
name='Remember Export Settings',
|
||||||
description='Store glTF export settings in the Blender project',
|
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_attributes'] = self.export_attributes
|
||||||
export_settings['gltf_cameras'] = self.export_cameras
|
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_visible'] = self.use_visible
|
||||||
export_settings['gltf_renderable'] = self.use_renderable
|
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.active = operator.export_image_format != "WEBP"
|
||||||
col.prop(operator, "export_image_webp_fallback")
|
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):
|
class GLTF_PT_export_data_lighting(bpy.types.Panel):
|
||||||
bl_space_type = 'FILE_BROWSER'
|
bl_space_type = 'FILE_BROWSER'
|
||||||
bl_region_type = 'TOOL_PROPS'
|
bl_region_type = 'TOOL_PROPS'
|
||||||
@ -1864,7 +1840,6 @@ classes = (
|
|||||||
GLTF_PT_export_data_scene,
|
GLTF_PT_export_data_scene,
|
||||||
GLTF_PT_export_data_mesh,
|
GLTF_PT_export_data_mesh,
|
||||||
GLTF_PT_export_data_material,
|
GLTF_PT_export_data_material,
|
||||||
GLTF_PT_export_data_original_pbr,
|
|
||||||
GLTF_PT_export_data_shapekeys,
|
GLTF_PT_export_data_shapekeys,
|
||||||
GLTF_PT_export_data_sk_optimize,
|
GLTF_PT_export_data_sk_optimize,
|
||||||
GLTF_PT_export_data_armature,
|
GLTF_PT_export_data_armature,
|
||||||
|
@ -18,9 +18,5 @@ def create_settings_group(name):
|
|||||||
thicknessFactor.default_value = 0.0
|
thicknessFactor.default_value = 0.0
|
||||||
gltf_node_group.nodes.new('NodeGroupOutput')
|
gltf_node_group.nodes.new('NodeGroupOutput')
|
||||||
gltf_node_group_input = gltf_node_group.nodes.new('NodeGroupInput')
|
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
|
gltf_node_group_input.location = -200, 0
|
||||||
return gltf_node_group
|
return gltf_node_group
|
||||||
|
@ -119,7 +119,7 @@ def __fix_json(obj):
|
|||||||
|
|
||||||
|
|
||||||
def __should_include_json_value(key, value):
|
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:
|
if value is None:
|
||||||
return False
|
return False
|
||||||
|
@ -71,10 +71,6 @@ def get_socket(blender_material: bpy.types.Material, name: str, volume=False):
|
|||||||
elif name == "Background":
|
elif name == "Background":
|
||||||
type = bpy.types.ShaderNodeBackground
|
type = bpy.types.ShaderNodeBackground
|
||||||
name = "Color"
|
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:
|
else:
|
||||||
if volume is False:
|
if volume is False:
|
||||||
type = bpy.types.ShaderNodeBsdfPrincipled
|
type = bpy.types.ShaderNodeBsdfPrincipled
|
||||||
|
@ -11,34 +11,43 @@ from ...material import gltf2_blender_gather_texture_info
|
|||||||
def export_sheen(blender_material, export_settings):
|
def export_sheen(blender_material, export_settings):
|
||||||
sheen_extension = {}
|
sheen_extension = {}
|
||||||
|
|
||||||
sheenColor_socket = gltf2_blender_get.get_socket(blender_material, "sheenColor")
|
sheenTint_socket = gltf2_blender_get.get_socket(blender_material, "Sheen Tint")
|
||||||
sheenRoughness_socket = gltf2_blender_get.get_socket(blender_material, "sheenRoughness")
|
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, {}
|
return None, {}
|
||||||
|
|
||||||
uvmap_infos = {}
|
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
|
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):
|
if color != (0.0, 0.0, 0.0):
|
||||||
sheen_extension['sheenColorFactor'] = color
|
sheen_extension['sheenColorFactor'] = color
|
||||||
else:
|
else:
|
||||||
# Factor
|
# 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:
|
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
|
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]:
|
if fac is not None and fac != [0.0, 0.0, 0.0]:
|
||||||
sheen_extension['sheenColorFactor'] = fac
|
sheen_extension['sheenColorFactor'] = fac
|
||||||
|
|
||||||
# Texture
|
# 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(
|
original_sheenColor_texture, uvmap_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||||
sheenColor_socket,
|
sheenTint_socket,
|
||||||
(sheenColor_socket,),
|
(sheenTint_socket,),
|
||||||
(),
|
(),
|
||||||
export_settings,
|
export_settings,
|
||||||
)
|
)
|
||||||
|
@ -4,41 +4,43 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from .....io.com.gltf2_io_extensions import Extension
|
from .....io.com.gltf2_io_extensions import Extension
|
||||||
from .....io.com.gltf2_io_constants import GLTF_IOR
|
|
||||||
from ....exp import gltf2_blender_get
|
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 ...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 = {}
|
specular_extension = {}
|
||||||
|
|
||||||
original_specular_socket = gltf2_blender_get.get_socket_old(blender_material, 'Specular')
|
specular_socket = gltf2_blender_get.get_socket(blender_material, 'Specular IOR Level')
|
||||||
original_specularcolor_socket = gltf2_blender_get.get_socket_old(blender_material, 'Specular Color')
|
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, {}
|
return None, {}
|
||||||
|
|
||||||
uvmap_infos = {}
|
uvmap_infos = {}
|
||||||
|
|
||||||
specular_non_linked = isinstance(original_specular_socket, bpy.types.NodeSocket) and not original_specular_socket.is_linked
|
specular_non_linked = isinstance(specular_socket, bpy.types.NodeSocket) and not specular_socket.is_linked
|
||||||
specularcolor_non_linked = isinstance(original_specularcolor_socket, bpy.types.NodeSocket) and not original_specularcolor_socket.is_linked
|
specularcolor_non_linked = isinstance(speculartint_socket, bpy.types.NodeSocket) and not speculartint_socket.is_linked
|
||||||
|
|
||||||
if specular_non_linked is True:
|
if specular_non_linked is True:
|
||||||
fac = original_specular_socket.default_value
|
fac = specular_socket.default_value
|
||||||
if fac != 1.0:
|
if fac != 1.0:
|
||||||
specular_extension['specularFactor'] = fac
|
specular_extension['specularFactor'] = fac
|
||||||
|
if fac == 0.0:
|
||||||
|
return None, {}
|
||||||
else:
|
else:
|
||||||
# Factor
|
# 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:
|
if fac is not None and fac != 1.0:
|
||||||
specular_extension['specularFactor'] = fac
|
specular_extension['specularFactor'] = fac
|
||||||
|
|
||||||
|
if fac == 0.0:
|
||||||
|
return None, {}
|
||||||
|
|
||||||
# Texture
|
# 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_texture, uvmap_info, _ = gather_texture_info(
|
||||||
original_specular_socket,
|
specular_socket,
|
||||||
(original_specular_socket,),
|
(specular_socket,),
|
||||||
(),
|
(),
|
||||||
export_settings,
|
export_settings,
|
||||||
)
|
)
|
||||||
@ -46,20 +48,20 @@ def export_original_specular(blender_material, export_settings):
|
|||||||
uvmap_infos.update({'specularTexture': uvmap_info})
|
uvmap_infos.update({'specularTexture': uvmap_info})
|
||||||
|
|
||||||
if specularcolor_non_linked is True:
|
if specularcolor_non_linked is True:
|
||||||
color = original_specularcolor_socket.default_value[:3]
|
color = speculartint_socket.default_value[:3]
|
||||||
if color != [1.0, 1.0, 1.0]:
|
if color != (1.0, 1.0, 1.0):
|
||||||
specular_extension['specularColorFactor'] = color
|
specular_extension['specularColorFactor'] = color
|
||||||
else:
|
else:
|
||||||
# Factor
|
# Factor
|
||||||
fac = gltf2_blender_get.get_factor_from_socket(original_specularcolor_socket, kind='RGB')
|
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]:
|
if fac is not None and fac != (1.0, 1.0, 1.0):
|
||||||
specular_extension['specularColorFactor'] = fac
|
specular_extension['specularColorFactor'] = fac
|
||||||
|
|
||||||
# Texture
|
# 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_texture, uvmap_info, _ = gather_texture_info(
|
||||||
original_specularcolor_socket,
|
speculartint_socket,
|
||||||
(original_specularcolor_socket,),
|
(speculartint_socket,),
|
||||||
(),
|
(),
|
||||||
export_settings,
|
export_settings,
|
||||||
)
|
)
|
||||||
@ -67,103 +69,3 @@ def export_original_specular(blender_material, export_settings):
|
|||||||
uvmap_infos.update({'specularColorTexture': uvmap_info})
|
uvmap_infos.update({'specularColorTexture': uvmap_info})
|
||||||
|
|
||||||
return Extension('KHR_materials_specular', specular_extension, False), uvmap_infos
|
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
|
# Unhappy path = we need to create the image self.fills describes or self.stores describes
|
||||||
if self.numpy_calc is None:
|
if self.numpy_calc is None:
|
||||||
print(">2")
|
|
||||||
return self.__encode_unhappy(export_settings), None
|
return self.__encode_unhappy(export_settings), None
|
||||||
else:
|
else:
|
||||||
pixels, width, height, factor = self.numpy_calc(self.stored)
|
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,9 +194,7 @@ def __get_image_data(sockets, default_sockets, export_settings) -> ExportImage:
|
|||||||
results = [get_tex_from_socket(socket) for socket in sockets]
|
results = [get_tex_from_socket(socket) for socket in sockets]
|
||||||
|
|
||||||
# Check if we need a simple mapping or more complex calculation
|
# 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]):
|
# There is currently no complex calculation for any textures
|
||||||
return __get_image_data_specular(sockets, results, export_settings)
|
|
||||||
else:
|
|
||||||
return __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
return __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
||||||
|
|
||||||
def __get_image_data_mapping(sockets, default_sockets, results, export_settings) -> ExportImage:
|
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)
|
# some sockets need channel rewriting (gltf pbr defines fixed channels for some attributes)
|
||||||
if socket.name == 'Metallic':
|
if socket.name == 'Metallic':
|
||||||
dst_chan = Channel.B
|
dst_chan = Channel.B
|
||||||
elif socket.name == 'Roughness' and socket.node.type == "BSDF_PRINCIPLED":
|
elif socket.name == 'Roughness':
|
||||||
dst_chan = Channel.G
|
dst_chan = Channel.G
|
||||||
elif socket.name == 'Occlusion':
|
elif socket.name == 'Occlusion':
|
||||||
dst_chan = Channel.R
|
dst_chan = Channel.R
|
||||||
@ -252,9 +250,9 @@ def __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
|||||||
dst_chan = Channel.G
|
dst_chan = Channel.G
|
||||||
elif socket.name == 'Thickness': # For KHR_materials_volume
|
elif socket.name == 'Thickness': # For KHR_materials_volume
|
||||||
dst_chan = Channel.G
|
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
|
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
|
dst_chan = Channel.A
|
||||||
|
|
||||||
if dst_chan is not None:
|
if dst_chan is not None:
|
||||||
@ -288,54 +286,6 @@ def __get_image_data_mapping(sockets, default_sockets, results, export_settings)
|
|||||||
return composed_image
|
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:
|
def __is_blender_image_a_jpeg(image: bpy.types.Image) -> bool:
|
||||||
if image.source != 'FILE':
|
if image.source != 'FILE':
|
||||||
return False
|
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[0], glossy_node.outputs[0])
|
||||||
mh.node_tree.links.new(add_node.inputs[1], diffuse_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,
|
mh,
|
||||||
location=(370, 250),
|
location=(370, 250),
|
||||||
additional_location=None, #No additional location needed for SpecGloss
|
additional_location=None, #No additional location needed for SpecGloss
|
||||||
shader_socket=add_node.outputs[0],
|
shader_socket=add_node.outputs[0],
|
||||||
make_emission_socket=mh.needs_emissive(),
|
make_emission_socket=mh.needs_emissive(),
|
||||||
make_alpha_socket=not mh.is_opaque(),
|
make_alpha_socket=not mh.is_opaque(),
|
||||||
make_volume_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
|
||||||
make_sheen_socket=None # No possible to have KHR_materials_volume with specular/glossiness
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if emission_socket:
|
if emission_socket:
|
||||||
|
@ -6,13 +6,14 @@ from ...io.com.gltf2_io import TextureInfo
|
|||||||
from .gltf2_blender_texture import texture
|
from .gltf2_blender_texture import texture
|
||||||
|
|
||||||
def sheen( mh,
|
def sheen( mh,
|
||||||
location_sheenColor,
|
location_sheenTint,
|
||||||
location_sheenRoughness,
|
location_sheenRoughness,
|
||||||
sheenColor_socket,
|
sheen_socket,
|
||||||
|
sheenTint_socket,
|
||||||
sheenRoughness_socket
|
sheenRoughness_socket
|
||||||
):
|
):
|
||||||
|
|
||||||
x_sheenColor, y_sheenColor = location_sheenColor
|
x_sheenTint, y_sheenTint = location_sheenTint
|
||||||
x_sheenRoughness, y_sheenRoughness = location_sheenRoughness
|
x_sheenRoughness, y_sheenRoughness = location_sheenRoughness
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -20,7 +21,8 @@ def sheen( mh,
|
|||||||
except Exception:
|
except Exception:
|
||||||
return
|
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')
|
tex_info_color = ext.get('sheenColorTexture')
|
||||||
if tex_info_color is not None:
|
if tex_info_color is not None:
|
||||||
tex_info_color = TextureInfo.from_dict(tex_info_color)
|
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)
|
tex_info_roughness = TextureInfo.from_dict(tex_info_roughness)
|
||||||
|
|
||||||
if tex_info_color is None:
|
if tex_info_color is None:
|
||||||
sheenColorFactor.extend([1.0])
|
sheenTintFactor.extend([1.0])
|
||||||
sheenColor_socket.default_value = sheenColorFactor
|
sheenTint_socket.default_value = sheenTintFactor
|
||||||
else:
|
else:
|
||||||
# Mix sheenColor factor
|
# Mix sheenTint factor
|
||||||
sheenColorFactor = sheenColorFactor + [1.0]
|
sheenTintFactor = sheenTintFactor + [1.0]
|
||||||
if sheenColorFactor != [1.0, 1.0, 1.0, 1.0]:
|
if sheenTintFactor != [1.0, 1.0, 1.0, 1.0]:
|
||||||
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
||||||
node.label = 'sheenColor Factor'
|
node.label = 'sheenTint Factor'
|
||||||
node.data_type = 'RGBA'
|
node.data_type = 'RGBA'
|
||||||
node.location = x_sheenColor - 140, y_sheenColor
|
node.location = x_sheenTint - 140, y_sheenTint
|
||||||
node.blend_type = 'MULTIPLY'
|
node.blend_type = 'MULTIPLY'
|
||||||
# Outputs
|
# Outputs
|
||||||
mh.node_tree.links.new(sheenColor_socket, node.outputs[2])
|
mh.node_tree.links.new(sheenTint_socket, node.outputs[2])
|
||||||
# Inputs
|
# Inputs
|
||||||
node.inputs['Factor'].default_value = 1.0
|
node.inputs['Factor'].default_value = 1.0
|
||||||
sheenColor_socket = node.inputs[6]
|
sheenTint_socket = node.inputs[6]
|
||||||
node.inputs[7].default_value = sheenColorFactor
|
node.inputs[7].default_value = sheenTintFactor
|
||||||
x_sheenColor -= 200
|
x_sheenTint -= 200
|
||||||
|
|
||||||
texture(
|
texture(
|
||||||
mh,
|
mh,
|
||||||
tex_info=tex_info_color,
|
tex_info=tex_info_color,
|
||||||
label='SHEEN COLOR',
|
label='SHEEN COLOR',
|
||||||
location=(x_sheenColor, y_sheenColor),
|
location=(x_sheenTint, y_sheenTint),
|
||||||
color_socket=sheenColor_socket
|
color_socket=sheenTint_socket
|
||||||
)
|
)
|
||||||
|
|
||||||
if tex_info_roughness is None:
|
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,
|
def specular(mh, location_specular,
|
||||||
location_specular_tint,
|
location_specular_tint,
|
||||||
specular_socket,
|
specular_socket,
|
||||||
specular_tint_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
|
|
||||||
|
|
||||||
if specular_socket is None:
|
if specular_socket is None:
|
||||||
return
|
return
|
||||||
@ -30,316 +24,22 @@ def specular(mh, location_specular,
|
|||||||
except Exception:
|
except Exception:
|
||||||
return
|
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
|
# First check if we need a texture or not -> retrieve all info needed
|
||||||
specular_factor = ext.get('specularFactor', 1.0)
|
specular_factor = ext.get('specularFactor', 1.0)
|
||||||
tex_specular_info = ext.get('specularTexture')
|
tex_specular_info = ext.get('specularTexture')
|
||||||
if tex_specular_info is not None:
|
if tex_specular_info is not None:
|
||||||
tex_specular_info = TextureInfo.from_dict(tex_specular_info)
|
tex_specular_info = TextureInfo.from_dict(tex_specular_info)
|
||||||
|
|
||||||
specular_color_factor = np.array(ext.get('specularColorFactor', [1.0, 1.0, 1.0])[:3])
|
specular_tint_factor = ext.get('specularColorFactor', [1.0, 1.0, 1.0])[:3]
|
||||||
tex_specular_color_info = ext.get('specularColorTexture')
|
tex_specular_tint_info = ext.get('specularColorTexture')
|
||||||
if tex_specular_color_info is not None:
|
if tex_specular_tint_info is not None:
|
||||||
tex_specular_color_info = TextureInfo.from_dict(tex_specular_color_info)
|
tex_specular_tint_info = TextureInfo.from_dict(tex_specular_tint_info)
|
||||||
|
|
||||||
base_color_not_linked = base_color_image_name is None
|
x_specular, y_specular = location_specular
|
||||||
base_color = np.array(mh.pymat.pbr_metallic_roughness.base_color_factor or [1, 1, 1])
|
x_specularcolor, y_specularcolor = location_specular_tint
|
||||||
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
|
|
||||||
|
|
||||||
if tex_specular_info is None:
|
if tex_specular_info is None:
|
||||||
original_specular_socket.default_value = specular_factor
|
specular_socket.default_value = specular_factor
|
||||||
else:
|
else:
|
||||||
# Mix specular factor
|
# Mix specular factor
|
||||||
if specular_factor != 1.0:
|
if specular_factor != 1.0:
|
||||||
@ -348,9 +48,9 @@ def original_specular( mh,
|
|||||||
node.location = x_specular - 140, y_specular
|
node.location = x_specular - 140, y_specular
|
||||||
node.operation = 'MULTIPLY'
|
node.operation = 'MULTIPLY'
|
||||||
# Outputs
|
# Outputs
|
||||||
mh.node_tree.links.new(original_specular_socket, node.outputs[0])
|
mh.node_tree.links.new(specular_socket, node.outputs[0])
|
||||||
# Inputs
|
# Inputs
|
||||||
original_specular_socket = node.inputs[0]
|
specular_socket = node.inputs[0]
|
||||||
node.inputs[1].default_value = specular_factor
|
node.inputs[1].default_value = specular_factor
|
||||||
x_specular -= 200
|
x_specular -= 200
|
||||||
|
|
||||||
@ -361,16 +61,16 @@ def original_specular( mh,
|
|||||||
location=(x_specular, y_specular),
|
location=(x_specular, y_specular),
|
||||||
is_data=True,
|
is_data=True,
|
||||||
color_socket=None,
|
color_socket=None,
|
||||||
alpha_socket=original_specular_socket
|
alpha_socket=specular_socket
|
||||||
)
|
)
|
||||||
|
|
||||||
if tex_specular_color_info is None:
|
if tex_specular_tint_info is None:
|
||||||
specular_color_factor = list(specular_color_factor)
|
specular_tint_factor = list(specular_tint_factor)
|
||||||
specular_color_factor.extend([1.0])
|
specular_tint_factor.extend([1.0])
|
||||||
original_specularcolor_socket.default_value = specular_color_factor
|
specular_tint_socket.default_value = specular_tint_factor
|
||||||
else:
|
else:
|
||||||
specular_color_factor = list(specular_color_factor) + [1.0]
|
specular_tint_factor = list(specular_tint_factor) + [1.0]
|
||||||
if specular_color_factor != [1.0, 1.0, 1.0, 1.0]:
|
if specular_tint_factor != [1.0, 1.0, 1.0, 1.0]:
|
||||||
# Mix specularColorFactor
|
# Mix specularColorFactor
|
||||||
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
node = mh.node_tree.nodes.new('ShaderNodeMix')
|
||||||
node.label = 'SpecularColor Factor'
|
node.label = 'SpecularColor Factor'
|
||||||
@ -378,17 +78,17 @@ def original_specular( mh,
|
|||||||
node.location = x_specularcolor - 140, y_specularcolor
|
node.location = x_specularcolor - 140, y_specularcolor
|
||||||
node.blend_type = 'MULTIPLY'
|
node.blend_type = 'MULTIPLY'
|
||||||
# Outputs
|
# Outputs
|
||||||
mh.node_tree.links.new(original_specularcolor_socket, node.outputs[2])
|
mh.node_tree.links.new(specular_tint_socket, node.outputs[2])
|
||||||
# Inputs
|
# Inputs
|
||||||
node.inputs['Factor'].default_value = 1.0
|
node.inputs['Factor'].default_value = 1.0
|
||||||
original_specularcolor_socket = node.inputs[6]
|
specular_tint_socket = node.inputs[6]
|
||||||
node.inputs[7].default_value = specular_color_factor
|
node.inputs[7].default_value = specular_tint_factor
|
||||||
x_specularcolor -= 200
|
x_specularcolor -= 200
|
||||||
|
|
||||||
texture(
|
texture(
|
||||||
mh,
|
mh,
|
||||||
tex_info=tex_specular_color_info,
|
tex_info=tex_specular_tint_info,
|
||||||
label='SPECULAR COLOR',
|
label='SPECULAR COLOR',
|
||||||
location=(x_specularcolor, y_specularcolor),
|
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[1], transparent_node.outputs[0])
|
||||||
mh.node_tree.links.new(mix_node.inputs[2], emission_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,
|
mh,
|
||||||
location=(420, 280) if mh.is_opaque() else (150, 130),
|
location=(420, 280) if mh.is_opaque() else (150, 130),
|
||||||
additional_location=None, #No additional location needed for Unlit
|
additional_location=None, #No additional location needed for Unlit
|
||||||
shader_socket=mix_node.outputs[0],
|
shader_socket=mix_node.outputs[0],
|
||||||
make_emission_socket=False,
|
make_emission_socket=False,
|
||||||
make_alpha_socket=not mh.is_opaque(),
|
make_alpha_socket=not mh.is_opaque(),
|
||||||
make_volume_socket=None, # Not possible to have KHR_materials_volume with unlit
|
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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
base_color(
|
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
|
# This value may be overridden later if IOR extension is set on file
|
||||||
pbr_node.inputs['IOR'].default_value = GLTF_IOR
|
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:
|
if mh.settings_node is None:
|
||||||
mh.settings_node = make_settings_node(mh)
|
mh.settings_node = make_settings_node(mh)
|
||||||
mh.settings_node.location = additional_location
|
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 = make_settings_node(mh)
|
||||||
mh.settings_node.location = additional_location
|
mh.settings_node.location = additional_location
|
||||||
mh.settings_node.width = 180
|
mh.settings_node.width = 180
|
||||||
volume_location = additional_location
|
|
||||||
additional_location = additional_location[0], additional_location[1] - 150
|
additional_location = additional_location[0], additional_location[1] - 150
|
||||||
|
|
||||||
need_sheen_node = False
|
_, _, volume_socket = make_output_nodes(
|
||||||
if mh.pymat.extensions and 'KHR_materials_sheen' in mh.pymat.extensions:
|
|
||||||
need_sheen_node = True
|
|
||||||
|
|
||||||
_, _, volume_socket, sheen_node = make_output_nodes(
|
|
||||||
mh,
|
mh,
|
||||||
location=(250, 260),
|
location=(250, 260),
|
||||||
additional_location=additional_location,
|
additional_location=additional_location,
|
||||||
shader_socket=pbr_node.outputs[0],
|
shader_socket=pbr_node.outputs[0],
|
||||||
make_emission_socket=False, # is managed by Principled shader node
|
make_emission_socket=False, # is managed by Principled shader node
|
||||||
make_alpha_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_volume_socket=need_volume_node
|
||||||
make_sheen_socket=need_sheen_node
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if mh.pymat.extensions and 'KHR_materials_sheen':
|
|
||||||
pass #TOTOEXT
|
|
||||||
|
|
||||||
locs = calc_locations(mh)
|
locs = calc_locations(mh)
|
||||||
|
|
||||||
emission(
|
emission(
|
||||||
@ -164,20 +158,16 @@ def pbr_metallic_roughness(mh: MaterialHelper):
|
|||||||
location_specular=locs['specularTexture'],
|
location_specular=locs['specularTexture'],
|
||||||
location_specular_tint=locs['specularColorTexture'],
|
location_specular_tint=locs['specularColorTexture'],
|
||||||
specular_socket=pbr_node.inputs['Specular IOR Level'],
|
specular_socket=pbr_node.inputs['Specular IOR Level'],
|
||||||
specular_tint_socket=pbr_node.inputs['Specular Tint'],
|
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']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if need_sheen_node:
|
|
||||||
sheen(
|
sheen(
|
||||||
mh,
|
mh,
|
||||||
location_sheenColor=locs['sheenColorTexture'],
|
location_sheenTint=locs['sheenColorTexture'],
|
||||||
location_sheenRoughness=locs['sheenRoughnessTexture'],
|
location_sheenRoughness=locs['sheenRoughnessTexture'],
|
||||||
sheenColor_socket=sheen_node.inputs[0],
|
sheen_socket=pbr_node.inputs['Sheen Weight'],
|
||||||
sheenRoughness_socket=sheen_node.inputs[1]
|
sheenTint_socket=pbr_node.inputs['Sheen Tint'],
|
||||||
|
sheenRoughness_socket=pbr_node.inputs['Sheen Roughness']
|
||||||
)
|
)
|
||||||
|
|
||||||
ior(
|
ior(
|
||||||
@ -219,12 +209,6 @@ def calc_locations(mh):
|
|||||||
except:
|
except:
|
||||||
sheen_ext = {}
|
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)
|
locs['base_color'] = (x, y)
|
||||||
if mh.pymat.pbr_metallic_roughness.base_color_texture is not None or mh.vertex_color:
|
if mh.pymat.pbr_metallic_roughness.base_color_texture is not None or mh.vertex_color:
|
||||||
y -= height
|
y -= height
|
||||||
@ -243,6 +227,12 @@ def calc_locations(mh):
|
|||||||
locs['specularColorTexture'] = (x, y)
|
locs['specularColorTexture'] = (x, y)
|
||||||
if 'specularColorTexture' in specular_ext:
|
if 'specularColorTexture' in specular_ext:
|
||||||
y -= height
|
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)
|
locs['clearcoat'] = (x, y)
|
||||||
if 'clearcoatTexture' in clearcoat_ext:
|
if 'clearcoatTexture' in clearcoat_ext:
|
||||||
y -= height
|
y -= height
|
||||||
@ -261,19 +251,6 @@ def calc_locations(mh):
|
|||||||
locs['volume_thickness'] = (x, y)
|
locs['volume_thickness'] = (x, y)
|
||||||
if 'thicknessTexture' in volume_ext:
|
if 'thicknessTexture' in volume_ext:
|
||||||
y -= height
|
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
|
# Center things
|
||||||
total_height = -y
|
total_height = -y
|
||||||
@ -306,6 +283,11 @@ def emission(mh: MaterialHelper, location, color_socket, strength_socket):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if mh.pymat.emissive_texture is None:
|
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]
|
color_socket.default_value = emissive_factor + [1]
|
||||||
strength_socket.default_value = strength
|
strength_socket.default_value = strength
|
||||||
return
|
return
|
||||||
@ -624,12 +606,11 @@ def make_output_nodes(
|
|||||||
shader_socket,
|
shader_socket,
|
||||||
make_emission_socket,
|
make_emission_socket,
|
||||||
make_alpha_socket,
|
make_alpha_socket,
|
||||||
make_volume_socket,
|
make_volume_socket
|
||||||
make_sheen_socket,
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates the Material Output node and connects shader_socket to it.
|
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.
|
in between shader_socket and the Output node too.
|
||||||
|
|
||||||
:return: a pair containing the sockets you should put emission and alpha
|
:return: a pair containing the sockets you should put emission and alpha
|
||||||
@ -637,7 +618,6 @@ def make_output_nodes(
|
|||||||
"""
|
"""
|
||||||
x, y = location
|
x, y = location
|
||||||
emission_socket = None
|
emission_socket = None
|
||||||
sheen_node = None
|
|
||||||
alpha_socket = None
|
alpha_socket = None
|
||||||
|
|
||||||
# Create an Emission node and add it to the shader.
|
# Create an Emission node and add it to the shader.
|
||||||
@ -666,31 +646,6 @@ def make_output_nodes(
|
|||||||
x += 380
|
x += 380
|
||||||
y += 125
|
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.
|
# Mix with a Transparent BSDF. Mixing factor is the alpha value.
|
||||||
if make_alpha_socket:
|
if make_alpha_socket:
|
||||||
# Transparent BSDF
|
# Transparent BSDF
|
||||||
@ -730,7 +685,7 @@ def make_output_nodes(
|
|||||||
volume_socket = node.outputs[0]
|
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):
|
def make_settings_node(mh):
|
||||||
|
@ -539,7 +539,7 @@ class NWPreviewNode(Operator, NWBase):
|
|||||||
|
|
||||||
if not viewer_socket:
|
if not viewer_socket:
|
||||||
# create 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
|
viewer_socket.NWViewerSocket = True
|
||||||
return viewer_socket
|
return viewer_socket
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ def create_path(scene):
|
|||||||
|
|
||||||
|
|
||||||
class SVGExporterLinesetPanel(bpy.types.Panel):
|
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_idname = "RENDER_PT_SVGExporterLinesetPanel"
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'PROPERTIES'
|
||||||
bl_label = "Freestyle Line Style SVG Export"
|
bl_label = "Freestyle Line Style SVG Export"
|
||||||
|
@ -46,7 +46,7 @@ PROMOTED_FEATURE_SETS = [
|
|||||||
"name": "Cessen's Rigify Extensions",
|
"name": "Cessen's Rigify Extensions",
|
||||||
"author": "Nathan Vegdahl",
|
"author": "Nathan Vegdahl",
|
||||||
"description": "Collection of original legacy Rigify rigs minimally ported to the modern Rigify",
|
"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",
|
"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):
|
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_idname = "ui.i18n_updatetranslation_blender_repo"
|
||||||
bl_label = "Update I18n Blender Repo"
|
bl_label = "Update I18n Blender Repo"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user