mirror of
https://github.com/ApfelTeeSaft/lightspeed64.git
synced 2026-08-26 19:33:24 +00:00
Improved nodes preview: F3DEX3 and OoT lighting (#382)
* Draft of shader changes * Almost draft of new version * Seems to be working * Fixed gamma on lighting * Fixed fog issues * blacked * Manually added in changes for color wrapping * Fixes OoT light directions and an OoT light previewing error * Fixed more issues and applied review suggestions * 4.2 support Add CLIP output group node, no longer uses CLIP blend mode because it was deprecated * Changed variable name * Addressing comments * Fixed upgrade props --------- Co-authored-by: Lila <[email protected]>
This commit is contained in:
+17
-7
@@ -22,7 +22,12 @@ from .fast64_internal.oot import OOT_Properties, oot_register, oot_unregister
|
||||
from .fast64_internal.oot.props_panel_main import OOT_ObjectProperties
|
||||
from .fast64_internal.utility_anim import utility_anim_register, utility_anim_unregister, ArmatureApplyWithMeshOperator
|
||||
|
||||
from .fast64_internal.f3d.f3d_material import mat_register, mat_unregister, check_or_ask_color_management
|
||||
from .fast64_internal.f3d.f3d_material import (
|
||||
F3D_MAT_CUR_VERSION,
|
||||
mat_register,
|
||||
mat_unregister,
|
||||
check_or_ask_color_management,
|
||||
)
|
||||
from .fast64_internal.f3d.f3d_render_engine import render_engine_register, render_engine_unregister
|
||||
from .fast64_internal.f3d.f3d_writer import f3d_writer_register, f3d_writer_unregister
|
||||
from .fast64_internal.f3d.f3d_parser import f3d_parser_register, f3d_parser_unregister
|
||||
@@ -31,7 +36,7 @@ from .fast64_internal.f3d.op_largetexture import op_largetexture_register, op_la
|
||||
|
||||
from .fast64_internal.f3d_material_converter import (
|
||||
MatUpdateConvert,
|
||||
upgradeF3DVersionAll,
|
||||
upgrade_f3d_version_all_meshes,
|
||||
bsdf_conv_register,
|
||||
bsdf_conv_unregister,
|
||||
bsdf_conv_panel_regsiter,
|
||||
@@ -264,10 +269,7 @@ class UpgradeF3DMaterialsDialog(bpy.types.Operator):
|
||||
if context.mode != "OBJECT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
upgradeF3DVersionAll(
|
||||
[obj for obj in bpy.data.objects if obj.type == "MESH"],
|
||||
MatUpdateConvert.version,
|
||||
)
|
||||
upgrade_f3d_version_all_meshes()
|
||||
self.done = True
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -320,10 +322,18 @@ def upgrade_changed_props():
|
||||
scene.gameEditorMode = "Homebrew"
|
||||
del scene["decomp_compatible"]
|
||||
|
||||
settings = scene.fast64.renderSettings
|
||||
light0Color = settings.pop("lightColor", None)
|
||||
if light0Color is not None:
|
||||
settings.light0Color = light0Color
|
||||
light0Direction = settings.pop("lightDirection", None)
|
||||
if light0Direction is not None:
|
||||
settings.light0Direction = light0Direction
|
||||
|
||||
|
||||
def upgrade_scene_props_node():
|
||||
"""update f3d materials with SceneProperties node"""
|
||||
has_old_f3d_mats = any(mat.is_f3d and mat.mat_ver < MatUpdateConvert.version for mat in bpy.data.materials)
|
||||
has_old_f3d_mats = any(mat.is_f3d and mat.mat_ver < F3D_MAT_CUR_VERSION for mat in bpy.data.materials)
|
||||
if has_old_f3d_mats:
|
||||
bpy.ops.dialog.upgrade_f3d_materials("INVOKE_DEFAULT")
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ from .f3d_material_helpers import F3DMaterial_UpdateLock, node_tree_copy
|
||||
from bpy.app.handlers import persistent
|
||||
from typing import Generator, Optional, Tuple, Any, Dict, Union
|
||||
|
||||
F3D_MAT_CUR_VERSION = 6 # Increment this when changing the nodes
|
||||
|
||||
F3DMaterialHash = Any # giant tuple
|
||||
|
||||
logging.basicConfig(format="%(asctime)s: %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p")
|
||||
@@ -114,14 +116,14 @@ drawLayerOOTtoSM64 = {
|
||||
}
|
||||
|
||||
drawLayerSM64Alpha = {
|
||||
"0": "OPAQUE",
|
||||
"1": "OPAQUE",
|
||||
"2": "OPAQUE",
|
||||
"3": "OPAQUE",
|
||||
"0": "OPA",
|
||||
"1": "OPA",
|
||||
"2": "OPA",
|
||||
"3": "OPA",
|
||||
"4": "CLIP",
|
||||
"5": "BLEND",
|
||||
"6": "BLEND",
|
||||
"7": "BLEND",
|
||||
"5": "XLU",
|
||||
"6": "XLU",
|
||||
"7": "XLU",
|
||||
}
|
||||
|
||||
enumF3DMenu = [
|
||||
@@ -270,7 +272,7 @@ def is_blender_doing_fog(settings: "RDPSettings", default_for_no_rendermode: boo
|
||||
)
|
||||
|
||||
|
||||
def get_blend_method(material: bpy.types.Material) -> str:
|
||||
def get_output_method(material: bpy.types.Material) -> str:
|
||||
settings = material.f3d_mat.rdp_settings
|
||||
if not settings.set_rendermode:
|
||||
return drawLayerSM64Alpha[material.f3d_mat.draw_layer.sm64]
|
||||
@@ -279,14 +281,17 @@ def get_blend_method(material: bpy.types.Material) -> str:
|
||||
if settings.force_bl and is_blender_equation_equal(
|
||||
settings, -1, "G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_MEM", "G_BL_1MA"
|
||||
):
|
||||
return "BLEND"
|
||||
return "OPAQUE"
|
||||
return "XLU"
|
||||
return "OPA"
|
||||
|
||||
|
||||
def update_blend_method(material: Material, context):
|
||||
material.blend_method = get_blend_method(material)
|
||||
if material.blend_method == "CLIP":
|
||||
material.alpha_threshold = 0.125
|
||||
if bpy.app.version >= (4, 2, 0):
|
||||
material.surface_render_method = "BLENDED"
|
||||
elif get_output_method(material) == "OPA":
|
||||
material.blend_method = "OPAQUE"
|
||||
else:
|
||||
material.blend_method = "BLEND"
|
||||
|
||||
|
||||
class DrawLayerProperty(PropertyGroup):
|
||||
@@ -1571,8 +1576,6 @@ def update_fog_nodes(material: Material, context: Context):
|
||||
f3dMat: "F3DMaterialProperty" = material.f3d_mat
|
||||
shade_alpha_is_fog = material.f3d_mat.rdp_settings.g_fog
|
||||
|
||||
nodes["Shade Color"].inputs["Fog"].default_value = int(shade_alpha_is_fog)
|
||||
|
||||
fogBlender: ShaderNodeGroup = nodes["FogBlender"]
|
||||
# if NOT setting rendermode, it is more likely that the user is setting
|
||||
# rendermodes in code, so to be safe we'll enable fog. Plus we are checking
|
||||
@@ -1599,7 +1602,7 @@ def update_fog_nodes(material: Material, context: Context):
|
||||
remove_first_link_if_exists(material, nodes["CalcFog"].inputs["FogNear"].links)
|
||||
remove_first_link_if_exists(material, nodes["CalcFog"].inputs["FogFar"].links)
|
||||
|
||||
fogBlender.inputs["Fog Color"].default_value = f3dMat.fog_color
|
||||
fogBlender.inputs["Fog Color"].default_value = s_rgb_alpha_1_tuple(f3dMat.fog_color)
|
||||
nodes["CalcFog"].inputs["FogNear"].default_value = f3dMat.fog_position[0]
|
||||
nodes["CalcFog"].inputs["FogFar"].default_value = f3dMat.fog_position[1]
|
||||
|
||||
@@ -1649,20 +1652,28 @@ def update_combiner_connections(material: Material, context: Context, combiner:
|
||||
|
||||
def set_output_node_groups(material: Material):
|
||||
nodes = material.node_tree.nodes
|
||||
f3dMat: "F3DMaterialProperty" = material.f3d_mat
|
||||
is_two_cycle = f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE"
|
||||
|
||||
output_node = nodes["OUTPUT"]
|
||||
if is_two_cycle:
|
||||
if material.blend_method == "OPAQUE":
|
||||
output_node.node_tree = bpy.data.node_groups["OUTPUT_2CYCLE_OPA"]
|
||||
else:
|
||||
output_node.node_tree = bpy.data.node_groups["OUTPUT_2CYCLE_XLU"]
|
||||
else:
|
||||
if material.blend_method == "OPAQUE":
|
||||
output_node.node_tree = bpy.data.node_groups["OUTPUT_1CYCLE_OPA"]
|
||||
else:
|
||||
output_node.node_tree = bpy.data.node_groups["OUTPUT_1CYCLE_XLU"]
|
||||
f3dMat: "F3DMaterialProperty" = material.f3d_mat
|
||||
cycle = f3dMat.rdp_settings.g_mdsft_cycletype.lstrip("G_CYC_").rstrip("_CYCLE")
|
||||
output_method = get_output_method(material)
|
||||
|
||||
output_group_name = f"OUTPUT_{cycle}CYCLE_{output_method}"
|
||||
output_group = bpy.data.node_groups[output_group_name]
|
||||
output_node.node_tree = output_group
|
||||
|
||||
for inp in output_node.inputs:
|
||||
remove_first_link_if_exists(material, inp.links)
|
||||
output_node.inputs["Cycle_C_1"].default_value = (0.0, 0.0, 0.0, 1.0)
|
||||
output_node.inputs["Cycle_A_1"].default_value = 0.5
|
||||
output_node.inputs["Cycle_C_2"].default_value = (0.0, 0.0, 0.0, 1.0)
|
||||
output_node.inputs["Cycle_A_2"].default_value = 0.5
|
||||
if output_method == "CLIP":
|
||||
output_node.inputs["Alpha Threshold"].default_value = 0.125
|
||||
material.node_tree.links.new(nodes["Cycle_1"].outputs["Color"], output_node.inputs["Cycle_C_1"])
|
||||
material.node_tree.links.new(nodes["Cycle_1"].outputs["Alpha"], output_node.inputs["Cycle_A_1"])
|
||||
material.node_tree.links.new(nodes["FogBlender"].outputs["Color"], output_node.inputs["Cycle_C_2"])
|
||||
material.node_tree.links.new(nodes["Cycle_2"].outputs["Alpha"], output_node.inputs["Cycle_A_2"])
|
||||
material.node_tree.links.new(output_node.outputs[0], nodes["Material Output F3D"].inputs[0])
|
||||
|
||||
|
||||
def update_light_colors(material, context):
|
||||
@@ -1680,43 +1691,33 @@ def update_light_colors(material, context):
|
||||
f3dMat.ambient_light_color = new_amb
|
||||
|
||||
if f3dMat.set_lights:
|
||||
remove_first_link_if_exists(material, nodes["Shade Color"].inputs["Shade Color"].links)
|
||||
remove_first_link_if_exists(material, nodes["Shade Color"].inputs["Ambient Color"].links)
|
||||
remove_first_link_if_exists(material, nodes["Shade Color"].inputs["AmbientColor"].links)
|
||||
remove_first_link_if_exists(material, nodes["Shade Color"].inputs["Light0Color"].links)
|
||||
remove_first_link_if_exists(material, nodes["Shade Color"].inputs["Light1Color"].links)
|
||||
|
||||
# TODO: feature to toggle gamma correction
|
||||
light = f3dMat.default_light_color
|
||||
light0 = f3dMat.default_light_color
|
||||
light1 = [0.0, 0.0, 0.0, 1.0]
|
||||
if not f3dMat.use_default_lighting:
|
||||
if f3dMat.f3d_light1 is not None:
|
||||
light = f3dMat.f3d_light1.color
|
||||
else:
|
||||
light = [1.0, 1.0, 1.0, 1.0]
|
||||
light0 = f3dMat.f3d_light1.color if f3dMat.f3d_light1 is not None else [1.0, 1.0, 1.0, 1.0]
|
||||
light1 = f3dMat.f3d_light2.color if f3dMat.f3d_light2 is not None else light1
|
||||
|
||||
corrected_col = gammaCorrect(light)
|
||||
corrected_col.append(1.0)
|
||||
corrected_amb = gammaCorrect(f3dMat.ambient_light_color)
|
||||
corrected_amb.append(1.0)
|
||||
|
||||
nodes["Shade Color"].inputs["Shade Color"].default_value = tuple(c for c in corrected_col)
|
||||
nodes["Shade Color"].inputs["Ambient Color"].default_value = tuple(c for c in corrected_amb)
|
||||
nodes["Shade Color"].inputs["AmbientColor"].default_value = s_rgb_alpha_1_tuple(f3dMat.ambient_light_color)
|
||||
nodes["Shade Color"].inputs["Light0Color"].default_value = s_rgb_alpha_1_tuple(light0)
|
||||
nodes["Shade Color"].inputs["Light1Color"].default_value = s_rgb_alpha_1_tuple(light1)
|
||||
else:
|
||||
col = [1.0, 1.0, 1.0, 1.0]
|
||||
amb_col = [0.5, 0.5, 0.5, 1.0]
|
||||
nodes["Shade Color"].inputs["Shade Color"].default_value = tuple(c for c in col)
|
||||
nodes["Shade Color"].inputs["Ambient Color"].default_value = tuple(c for c in amb_col)
|
||||
link_if_none_exist(material, nodes["ShadeColOut"].outputs[0], nodes["Shade Color"].inputs["Shade Color"])
|
||||
link_if_none_exist(material, nodes["AmbientColOut"].outputs[0], nodes["Shade Color"].inputs["Ambient Color"])
|
||||
nodes["Shade Color"].inputs["AmbientColor"].default_value = (0.5, 0.5, 0.5, 1.0)
|
||||
nodes["Shade Color"].inputs["Light0Color"].default_value = (1.0, 1.0, 1.0, 1.0)
|
||||
nodes["Shade Color"].inputs["Light1Color"].default_value = (0.0, 0.0, 0.0, 1.0)
|
||||
link_if_none_exist(material, nodes["AmbientColorOut"].outputs[0], nodes["Shade Color"].inputs["AmbientColor"])
|
||||
link_if_none_exist(material, nodes["Light0ColorOut"].outputs[0], nodes["Shade Color"].inputs["Light0Color"])
|
||||
link_if_none_exist(material, nodes["Light1ColorOut"].outputs[0], nodes["Shade Color"].inputs["Light1Color"])
|
||||
|
||||
|
||||
def update_color_node(combiner_inputs, color: Color, prefix: str):
|
||||
"""Function for updating either Prim or Env colors"""
|
||||
# TODO: feature to toggle gamma correction
|
||||
corrected_prim = gammaCorrect(color)
|
||||
combiner_inputs[f"{prefix} Color"].default_value = (
|
||||
corrected_prim[0],
|
||||
corrected_prim[1],
|
||||
corrected_prim[2],
|
||||
1.0,
|
||||
)
|
||||
combiner_inputs[f"{prefix} Color"].default_value = s_rgb_alpha_1_tuple(color)
|
||||
combiner_inputs[f"{prefix} Alpha"].default_value = color[3]
|
||||
|
||||
|
||||
@@ -1758,13 +1759,24 @@ def update_node_values_of_material(material: Material, context):
|
||||
else:
|
||||
nodes["UV"].node_tree = bpy.data.node_groups["UV"]
|
||||
|
||||
# This is a temporary measure to be able to see the vertex colors in packed materials.
|
||||
if bpy.context.scene.f3d_type == "F3DEX3" and f3dMat.rdp_settings.g_packed_normals:
|
||||
nodes["Shade Color"].node_tree = bpy.data.node_groups["ShdCol_V"]
|
||||
elif f3dMat.rdp_settings.g_lighting:
|
||||
nodes["Shade Color"].node_tree = bpy.data.node_groups["ShdCol_L"]
|
||||
else:
|
||||
nodes["Shade Color"].node_tree = bpy.data.node_groups["ShdCol_V"]
|
||||
shdcol_inputs = nodes["Shade Color"].inputs
|
||||
for propName in [
|
||||
"g_ambocclusion",
|
||||
"g_packed_normals",
|
||||
"g_lighttoalpha",
|
||||
"g_lighting_specular",
|
||||
"g_fresnel_color",
|
||||
"g_fresnel_alpha",
|
||||
"g_fog",
|
||||
"g_lighting",
|
||||
]:
|
||||
shdcol_inputs[propName.upper()].default_value = getattr(f3dMat.rdp_settings, propName)
|
||||
|
||||
shdcol_inputs["AO Ambient"].default_value = f3dMat.ao_ambient
|
||||
shdcol_inputs["AO Directional"].default_value = f3dMat.ao_directional
|
||||
shdcol_inputs["AO Point"].default_value = f3dMat.ao_point
|
||||
shdcol_inputs["Fresnel Lo"].default_value = f3dMat.fresnel_lo
|
||||
shdcol_inputs["Fresnel Hi"].default_value = f3dMat.fresnel_hi
|
||||
|
||||
update_light_colors(material, context)
|
||||
|
||||
@@ -2245,7 +2257,7 @@ def load_handler(dummy):
|
||||
|
||||
bpy.app.handlers.load_post.append(load_handler)
|
||||
|
||||
SCENE_PROPERTIES_VERSION = 1
|
||||
SCENE_PROPERTIES_VERSION = 2
|
||||
|
||||
|
||||
def createOrUpdateSceneProperties():
|
||||
@@ -2300,14 +2312,27 @@ def createOrUpdateSceneProperties():
|
||||
_nodeFogFar: NodeSocketFloat = tree_interface.new_socket(
|
||||
"FogFar", socket_type="NodeSocketFloat", in_out="OUTPUT"
|
||||
)
|
||||
_nodeShadeColor: NodeSocketColor = tree_interface.new_socket(
|
||||
"ShadeColor", socket_type="NodeSocketColor", in_out="OUTPUT"
|
||||
)
|
||||
|
||||
_nodeAmbientColor: NodeSocketColor = tree_interface.new_socket(
|
||||
"AmbientColor", socket_type="NodeSocketColor", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLightDirection: NodeSocketVector = tree_interface.new_socket(
|
||||
"LightDirection", socket_type="NodeSocketVector", in_out="OUTPUT"
|
||||
_nodeLight0Color: NodeSocketColor = tree_interface.new_socket(
|
||||
"Light0Color", socket_type="NodeSocketColor", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLight0Dir: NodeSocketVector = tree_interface.new_socket(
|
||||
"Light0Dir", socket_type="NodeSocketVector", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLight0Size: NodeSocketFloat = tree_interface.new_socket(
|
||||
"Light0Size", socket_type="NodeSocketFloat", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLight1Color: NodeSocketColor = tree_interface.new_socket(
|
||||
"Light1Color", socket_type="NodeSocketColor", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLight1Dir: NodeSocketVector = tree_interface.new_socket(
|
||||
"Light1Dir", socket_type="NodeSocketVector", in_out="OUTPUT"
|
||||
)
|
||||
_nodeLight1Size: NodeSocketFloat = tree_interface.new_socket(
|
||||
"Light1Size", socket_type="NodeSocketFloat", in_out="OUTPUT"
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -2318,11 +2343,14 @@ def createOrUpdateSceneProperties():
|
||||
_nodeBlender_Game_Scale: NodeSocketFloat = new_group.outputs.new("NodeSocketFloat", "Blender_Game_Scale")
|
||||
_nodeFogNear: NodeSocketInt = new_group.outputs.new("NodeSocketInt", "FogNear")
|
||||
_nodeFogFar: NodeSocketInt = new_group.outputs.new("NodeSocketInt", "FogFar")
|
||||
_nodeShadeColor: NodeSocketColor = new_group.outputs.new("NodeSocketColor", "ShadeColor")
|
||||
|
||||
_nodeAmbientColor: NodeSocketColor = new_group.outputs.new("NodeSocketColor", "AmbientColor")
|
||||
_nodeLightDirection: NodeSocketVectorDirection = new_group.outputs.new(
|
||||
"NodeSocketVectorDirection", "LightDirection"
|
||||
)
|
||||
_nodeLight0Color: NodeSocketColor = new_group.outputs.new("NodeSocketColor", "Light0Color")
|
||||
_nodeLight0Dir: NodeSocketVectorDirection = new_group.outputs.new("NodeSocketVectorDirection", "Light0Dir")
|
||||
_nodeLight0Size: NodeSocketInt = new_group.outputs.new("NodeSocketInt", "Light0Size")
|
||||
_nodeLight1Color: NodeSocketColor = new_group.outputs.new("NodeSocketColor", "Light1Color")
|
||||
_nodeLight1Dir: NodeSocketVectorDirection = new_group.outputs.new("NodeSocketVectorDirection", "Light1Dir")
|
||||
_nodeLight1Size: NodeSocketInt = new_group.outputs.new("NodeSocketInt", "Light1Size")
|
||||
|
||||
# Set outputs from render settings
|
||||
sceneOutputs: NodeGroupOutput = new_group.nodes["Group Output"]
|
||||
@@ -2340,22 +2368,29 @@ def createScenePropertiesForMaterial(material: Material):
|
||||
# create a new group node to hold the tree
|
||||
scene_props = node_tree.nodes.new(type="ShaderNodeGroup")
|
||||
scene_props.name = "SceneProperties"
|
||||
scene_props.location = (-420, -360)
|
||||
scene_props.location = (-320, -23)
|
||||
scene_props.node_tree = bpy.data.node_groups["SceneProperties"]
|
||||
# link the new node to correct socket
|
||||
|
||||
# Fog links to reroutes and the CalcFog block
|
||||
node_tree.links.new(scene_props.outputs["FogEnable"], node_tree.nodes["FogEnable"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["FogColor"], node_tree.nodes["FogColor"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["FogNear"], node_tree.nodes["CalcFog"].inputs["FogNear"])
|
||||
node_tree.links.new(scene_props.outputs["FogFar"], node_tree.nodes["CalcFog"].inputs["FogFar"])
|
||||
node_tree.links.new(scene_props.outputs["F3D_NearClip"], node_tree.nodes["CalcFog"].inputs["F3D_NearClip"])
|
||||
node_tree.links.new(scene_props.outputs["F3D_FarClip"], node_tree.nodes["CalcFog"].inputs["F3D_FarClip"])
|
||||
node_tree.links.new(
|
||||
scene_props.outputs["Blender_Game_Scale"], node_tree.nodes["CalcFog"].inputs["Blender_Game_Scale"]
|
||||
)
|
||||
node_tree.links.new(scene_props.outputs["F3D_NearClip"], node_tree.nodes["CalcFog"].inputs["F3D_NearClip"])
|
||||
node_tree.links.new(scene_props.outputs["F3D_FarClip"], node_tree.nodes["CalcFog"].inputs["F3D_FarClip"])
|
||||
node_tree.links.new(scene_props.outputs["FogNear"], node_tree.nodes["CalcFog"].inputs["FogNear"])
|
||||
node_tree.links.new(scene_props.outputs["FogFar"], node_tree.nodes["CalcFog"].inputs["FogFar"])
|
||||
|
||||
node_tree.links.new(scene_props.outputs["ShadeColor"], node_tree.nodes["ShadeColor"].inputs[0])
|
||||
# Lighting links to reroutes. The colors are connected to other reroutes for update_light_colors,
|
||||
# the others go directly to the Shade Color block.
|
||||
node_tree.links.new(scene_props.outputs["AmbientColor"], node_tree.nodes["AmbientColor"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["LightDirection"], node_tree.nodes["LightDirection"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light0Color"], node_tree.nodes["Light0Color"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light0Dir"], node_tree.nodes["Light0Dir"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light0Size"], node_tree.nodes["Light0Size"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light1Color"], node_tree.nodes["Light1Color"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light1Dir"], node_tree.nodes["Light1Dir"].inputs[0])
|
||||
node_tree.links.new(scene_props.outputs["Light1Size"], node_tree.nodes["Light1Size"].inputs[0])
|
||||
|
||||
|
||||
def link_f3d_material_library():
|
||||
@@ -2474,7 +2509,7 @@ def createF3DMat(obj: Object | None, preset="Shaded Solid", index=None):
|
||||
add_f3d_mat_to_obj(obj, material, index)
|
||||
|
||||
material.is_f3d = True
|
||||
material.mat_ver = 5
|
||||
material.mat_ver = F3D_MAT_CUR_VERSION
|
||||
|
||||
update_preset_manual_v4(material, preset)
|
||||
|
||||
@@ -4577,6 +4612,7 @@ class F3DRenderSettingsPanel(Panel):
|
||||
layout = self.layout
|
||||
layout.ui_units_x = 16
|
||||
renderSettings = context.scene.fast64.renderSettings
|
||||
isF3DEX3 = bpy.context.scene.f3d_type == "F3DEX3"
|
||||
|
||||
globalSettingsBox = layout.box()
|
||||
labelbox = globalSettingsBox.box()
|
||||
@@ -4591,8 +4627,14 @@ class F3DRenderSettingsPanel(Panel):
|
||||
globalSettingsBox.separator(factor=0.125)
|
||||
# TODO: (v5) add headings
|
||||
prop_split(globalSettingsBox, renderSettings, "ambientColor", "Ambient Light")
|
||||
prop_split(globalSettingsBox, renderSettings, "lightColor", "Light Color")
|
||||
prop_split(globalSettingsBox, renderSettings, "lightDirection", "Light Direction")
|
||||
prop_split(globalSettingsBox, renderSettings, "light0Color", "Light 0 Color")
|
||||
prop_split(globalSettingsBox, renderSettings, "light0Direction", "Light 0 Direction")
|
||||
if isF3DEX3:
|
||||
prop_split(globalSettingsBox, renderSettings, "light0SpecSize", "Light 0 Specular Size")
|
||||
prop_split(globalSettingsBox, renderSettings, "light1Color", "Light 1 Color")
|
||||
prop_split(globalSettingsBox, renderSettings, "light1Direction", "Light 1 Direction")
|
||||
if isF3DEX3:
|
||||
prop_split(globalSettingsBox, renderSettings, "light1SpecSize", "Light 1 Specular Size")
|
||||
prop_split(globalSettingsBox, renderSettings, "useWorldSpaceLighting", "Use World Space Lighting")
|
||||
|
||||
if context.scene.gameEditorMode in ["SM64", "OOT"]:
|
||||
@@ -4627,16 +4669,16 @@ class F3DRenderSettingsPanel(Panel):
|
||||
else:
|
||||
numLightsNeeded = 1
|
||||
if header.skyboxLighting == "Custom":
|
||||
r2 = b.row()
|
||||
r2 = b.row().split(factor=0.4)
|
||||
r2.prop(renderSettings, "ootForceTimeOfDay")
|
||||
if renderSettings.ootForceTimeOfDay:
|
||||
r2.label(text="Light Index sets first of four lights.", icon="INFO")
|
||||
numLightsNeeded = 4
|
||||
if header.skyboxLighting != "0x00":
|
||||
if header.skyboxLighting != "LIGHT_MODE_TIME":
|
||||
r.prop(renderSettings, "ootLightIdx")
|
||||
if renderSettings.ootLightIdx + numLightsNeeded > len(header.lightList):
|
||||
b.label(text="Light does not exist.", icon="QUESTION")
|
||||
if header.skyboxLighting == "0x00" or (
|
||||
if header.skyboxLighting == "LIGHT_MODE_TIME" or (
|
||||
header.skyboxLighting == "Custom" and renderSettings.ootForceTimeOfDay
|
||||
):
|
||||
r.prop(renderSettings, "ootTime")
|
||||
|
||||
Binary file not shown.
@@ -8,13 +8,14 @@ from .utility import *
|
||||
from bl_operators.presets import AddPresetBase
|
||||
|
||||
|
||||
def upgradeF3DVersionAll(objs, version):
|
||||
def upgrade_f3d_version_all_meshes() -> None:
|
||||
objs = [obj for obj in bpy.data.objects if obj.type == "MESH"]
|
||||
f3d_node_tree = get_f3d_node_tree()
|
||||
|
||||
# Remove original v2 node groups so that they can be recreated.
|
||||
deleteGroups = []
|
||||
for node_tree in bpy.data.node_groups:
|
||||
if node_tree.name[-6:] == "F3D v" + str(version):
|
||||
if node_tree.name[-6:] == "F3D v" + str(F3D_MAT_CUR_VERSION):
|
||||
deleteGroups.append(node_tree)
|
||||
for deleteGroup in deleteGroups:
|
||||
bpy.data.node_groups.remove(deleteGroup)
|
||||
@@ -152,7 +153,7 @@ def convertF3DtoNewVersion(
|
||||
node_tree_copy(f3d_node_tree, material.node_tree)
|
||||
|
||||
material.is_f3d, material.f3d_update_flag = True, False
|
||||
material.mat_ver = 5
|
||||
material.mat_ver = F3D_MAT_CUR_VERSION
|
||||
|
||||
createScenePropertiesForMaterial(material)
|
||||
with bpy.context.temp_override(material=material):
|
||||
@@ -264,9 +265,8 @@ class BSDFConvert(bpy.types.Operator):
|
||||
|
||||
class MatUpdateConvert(bpy.types.Operator):
|
||||
# set bl_ properties
|
||||
version = 5
|
||||
bl_idname = "object.convert_f3d_update"
|
||||
bl_label = "Recreate F3D Materials As v" + str(version)
|
||||
bl_label = "Recreate F3D Materials As v" + str(F3D_MAT_CUR_VERSION)
|
||||
bl_options = {"UNDO"}
|
||||
|
||||
update_conv_all: bpy.props.BoolProperty(default=True)
|
||||
@@ -279,10 +279,7 @@ class MatUpdateConvert(bpy.types.Operator):
|
||||
raise PluginError("Operator can only be used in object mode.")
|
||||
|
||||
if self.update_conv_all:
|
||||
upgradeF3DVersionAll(
|
||||
[obj for obj in bpy.data.objects if obj.type == "MESH"],
|
||||
self.version,
|
||||
)
|
||||
upgrade_f3d_version_all_meshes()
|
||||
else:
|
||||
if len(context.selected_objects) == 0:
|
||||
raise PluginError("Mesh not selected.")
|
||||
|
||||
@@ -113,7 +113,7 @@ class SceneLighting:
|
||||
light2[1],
|
||||
exportColor(lightProp.fogColor),
|
||||
lightProp.fogNear,
|
||||
lightProp.fogFar,
|
||||
lightProp.z_far,
|
||||
lightProp.transitionSpeed,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1089,7 +1089,7 @@ def parseLightList(
|
||||
blendFogShort = hexOrDecInt(lightParams[18])
|
||||
fogNear = blendFogShort & ((1 << 10) - 1)
|
||||
transitionSpeed = blendFogShort >> 10
|
||||
fogFar = hexOrDecInt(lightParams[19])
|
||||
z_far = hexOrDecInt(lightParams[19])
|
||||
|
||||
lightHeader = sceneHeader.lightList.add()
|
||||
lightHeader.ambient = ambientColor + (1,)
|
||||
@@ -1106,7 +1106,7 @@ def parseLightList(
|
||||
|
||||
lightHeader.fogColor = fogColor + (1,)
|
||||
lightHeader.fogNear = fogNear
|
||||
lightHeader.fogFar = fogFar
|
||||
lightHeader.z_far = z_far
|
||||
lightHeader.transitionSpeed = transitionSpeed
|
||||
|
||||
index += 1
|
||||
|
||||
@@ -178,7 +178,7 @@ class OOTLightProperty(PropertyGroup):
|
||||
)
|
||||
fogNear: IntProperty(name="", default=993, min=0, max=2**10 - 1, update=on_update_oot_render_settings)
|
||||
transitionSpeed: IntProperty(name="", default=1, min=0, max=63, update=on_update_oot_render_settings)
|
||||
fogFar: IntProperty(name="", default=0x3200, min=0, max=2**16 - 1, update=on_update_oot_render_settings)
|
||||
z_far: IntProperty(name="", default=0x3200, min=0, max=2**15 - 1, update=on_update_oot_render_settings)
|
||||
expandTab: BoolProperty(name="Expand Tab")
|
||||
|
||||
def draw_props(
|
||||
@@ -212,8 +212,8 @@ class OOTLightProperty(PropertyGroup):
|
||||
box.prop(self, "useCustomDiffuse1")
|
||||
|
||||
prop_split(box, self, "fogColor", "Fog Color")
|
||||
prop_split(box, self, "fogNear", "Fog Near")
|
||||
prop_split(box, self, "fogFar", "Fog Far")
|
||||
prop_split(box, self, "fogNear", "Fog Near (Fog Far=1000)")
|
||||
prop_split(box, self, "z_far", "Z Far (Draw Distance)")
|
||||
prop_split(box, self, "transitionSpeed", "Transition Speed")
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ def on_update_sm64_render_settings(self, context: bpy.types.Context):
|
||||
area: bpy.types.Object = renderSettings.sm64Area
|
||||
renderSettings.fogPreviewColor = tuple(c for c in area.area_fog_color)
|
||||
renderSettings.fogPreviewPosition = tuple(round(p) for p in area.area_fog_position)
|
||||
|
||||
renderSettings.clippingPlanes = tuple(float(p) for p in area.clipPlanes)
|
||||
|
||||
|
||||
@@ -26,22 +25,22 @@ def on_update_oot_render_settings(self, context: bpy.types.Context):
|
||||
if header is None:
|
||||
return
|
||||
lMode = header.skyboxLighting
|
||||
if lMode == "0x01" or (lMode == "Custom" and not renderSettings.ootForceTimeOfDay):
|
||||
if lMode == "LIGHT_MODE_SETTINGS" or (lMode == "Custom" and not renderSettings.ootForceTimeOfDay):
|
||||
if renderSettings.ootLightIdx >= len(header.lightList):
|
||||
return
|
||||
l = header.lightList[renderSettings.ootLightIdx]
|
||||
renderSettings.ambientColor = tuple(c for c in l.ambient)
|
||||
col0, dir0 = ootGetBaseOrCustomLight(l, 0, False, False)
|
||||
renderSettings.lightColor = tuple(c for c in col0)
|
||||
renderSettings.lightDirection = tuple(d for d in dir0)
|
||||
# TODO: Implement light1 into shader nodes
|
||||
# col1, dir1 = ootGetBaseOrCustomLight(l, 1, False, False)
|
||||
# renderSettings.light1Color = tuple(c for c in col1)
|
||||
# renderSettings.light1Direction = tuple(d for d in dir1)
|
||||
renderSettings.light0Color = tuple(c for c in col0)
|
||||
renderSettings.light0Direction = tuple(d for d in dir0)
|
||||
col1, dir1 = ootGetBaseOrCustomLight(l, 1, False, False)
|
||||
renderSettings.light1Color = tuple(c for c in col1)
|
||||
renderSettings.light1Direction = tuple(d for d in dir1)
|
||||
renderSettings.fogPreviewColor = tuple(c for c in l.fogColor)
|
||||
renderSettings.fogPreviewPosition = (l.fogNear, l.fogFar)
|
||||
renderSettings.fogPreviewPosition = (l.fogNear, 1000) # fogFar is always 1000 in OoT
|
||||
renderSettings.clippingPlanes = (10.0, l.z_far) # zNear seems to always be 10 in OoT
|
||||
else:
|
||||
if header.skyboxLighting == "0x00":
|
||||
if lMode == "LIGHT_MODE_TIME":
|
||||
tod = header.timeOfDayLights
|
||||
lights = [tod.dawn, tod.day, tod.dusk, tod.night]
|
||||
else:
|
||||
@@ -69,37 +68,34 @@ def on_update_oot_render_settings(self, context: bpy.types.Context):
|
||||
renderSettings.ambientColor = interpColors(la.ambient, lb.ambient, fade)
|
||||
col0a, _ = ootGetBaseOrCustomLight(la, 0, False, False)
|
||||
col0b, _ = ootGetBaseOrCustomLight(lb, 0, False, False)
|
||||
renderSettings.lightColor = col0a + (col0b - col0a) * fade
|
||||
# TODO: Implement light1 into shader nodes
|
||||
# col1a, _ = ootGetBaseOrCustomLight(la, 1, False, False)
|
||||
# col1b, _ = ootGetBaseOrCustomLight(lb, 1, False, False)
|
||||
# renderSettings.light1Color = col1a * fa + col1b * fb
|
||||
renderSettings.light0Color = col0a + (col0b - col0a) * fade
|
||||
col1a, _ = ootGetBaseOrCustomLight(la, 1, False, False)
|
||||
col1b, _ = ootGetBaseOrCustomLight(lb, 1, False, False)
|
||||
renderSettings.light1Color = col1a + (col1b - col1a) * fade
|
||||
sint, cost = math.sin(math.tau * t / 24.0), math.cos(math.tau * t / 24.0)
|
||||
renderSettings.lightDirection = mathutils.Vector(
|
||||
renderSettings.light0Direction = mathutils.Vector(
|
||||
(
|
||||
sint * 120.0 / 127.0,
|
||||
cost * 20.0 / 127.0,
|
||||
-cost * 120.0 / 127.0,
|
||||
-cost * 20.0 / 127.0,
|
||||
)
|
||||
).normalized()
|
||||
# TODO: Implement light1 into shader nodes
|
||||
# renderSettings.light1Direction = -renderSettings.lightDirection
|
||||
renderSettings.fogColor = interpColors(la.fogColor, lb.fogColor, fade)
|
||||
renderSettings.fogPreviewPosition = (
|
||||
renderSettings.light1Direction = -renderSettings.light0Direction
|
||||
renderSettings.fogPreviewColor = interpColors(la.fogColor, lb.fogColor, fade)
|
||||
renderSettings.fogPreviewPosition = ( # fogFar is always 1000 in OoT
|
||||
la.fogNear + int(float(lb.fogNear - la.fogNear) * fade),
|
||||
la.fogFar + int(float(lb.fogFar - la.fogFar) * fade),
|
||||
1000,
|
||||
)
|
||||
renderSettings.clippingPlanes = ( # zNear seems to always be 10 in OoT
|
||||
10.0,
|
||||
la.z_far + float(lb.z_far - la.z_far) * fade,
|
||||
)
|
||||
|
||||
|
||||
def update_lighting_space(renderSettings: "Fast64RenderSettings_Properties"):
|
||||
if renderSettings.useWorldSpaceLighting:
|
||||
bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[
|
||||
"GeometryNormal_WorldSpace"
|
||||
]
|
||||
else:
|
||||
bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[
|
||||
"GeometryNormal_ViewSpace"
|
||||
]
|
||||
bpy.data.node_groups["GetSpecularNormal"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[
|
||||
"GeometryNormal_WorldSpace" if renderSettings.useWorldSpaceLighting else "GeometryNormal_ViewSpace"
|
||||
]
|
||||
|
||||
|
||||
def update_scene_props_from_render_settings(
|
||||
@@ -107,26 +103,24 @@ def update_scene_props_from_render_settings(
|
||||
sceneOutputs: bpy.types.NodeGroupOutput,
|
||||
renderSettings: "Fast64RenderSettings_Properties",
|
||||
):
|
||||
enableFog = int(renderSettings.enableFogPreview)
|
||||
sceneOutputs.inputs["FogEnable"].default_value = enableFog
|
||||
|
||||
sceneOutputs.inputs["FogColor"].default_value = tuple(c for c in renderSettings.fogPreviewColor)
|
||||
sceneOutputs.inputs["FogEnable"].default_value = int(renderSettings.enableFogPreview)
|
||||
sceneOutputs.inputs["FogColor"].default_value = s_rgb_alpha_1_tuple(renderSettings.fogPreviewColor)
|
||||
sceneOutputs.inputs["F3D_NearClip"].default_value = float(renderSettings.clippingPlanes[0])
|
||||
sceneOutputs.inputs["F3D_FarClip"].default_value = float(renderSettings.clippingPlanes[1])
|
||||
sceneOutputs.inputs["Blender_Game_Scale"].default_value = float(get_blender_to_game_scale(context))
|
||||
sceneOutputs.inputs["FogNear"].default_value = renderSettings.fogPreviewPosition[0]
|
||||
sceneOutputs.inputs["FogFar"].default_value = renderSettings.fogPreviewPosition[1]
|
||||
|
||||
sceneOutputs.inputs["F3D_NearClip"].default_value = float(renderSettings.clippingPlanes[0])
|
||||
sceneOutputs.inputs["F3D_FarClip"].default_value = float(renderSettings.clippingPlanes[1])
|
||||
|
||||
sceneOutputs.inputs["ShadeColor"].default_value = tuple(c for c in renderSettings.lightColor)
|
||||
sceneOutputs.inputs["AmbientColor"].default_value = tuple(c for c in renderSettings.ambientColor)
|
||||
sceneOutputs.inputs["LightDirection"].default_value = tuple(
|
||||
d for d in (mathutils.Vector(renderSettings.lightDirection) @ transform_mtx_blender_to_n64())
|
||||
)
|
||||
sceneOutputs.inputs["AmbientColor"].default_value = s_rgb_alpha_1_tuple(renderSettings.ambientColor)
|
||||
sceneOutputs.inputs["Light0Color"].default_value = s_rgb_alpha_1_tuple(renderSettings.light0Color)
|
||||
sceneOutputs.inputs["Light0Dir"].default_value = renderSettings.light0Direction
|
||||
sceneOutputs.inputs["Light0Size"].default_value = renderSettings.light0SpecSize
|
||||
sceneOutputs.inputs["Light1Color"].default_value = s_rgb_alpha_1_tuple(renderSettings.light1Color)
|
||||
sceneOutputs.inputs["Light1Dir"].default_value = renderSettings.light1Direction
|
||||
sceneOutputs.inputs["Light1Size"].default_value = renderSettings.light1SpecSize
|
||||
|
||||
update_lighting_space(renderSettings)
|
||||
|
||||
sceneOutputs.inputs["Blender_Game_Scale"].default_value = float(get_blender_to_game_scale(context))
|
||||
|
||||
|
||||
def on_update_render_preview_nodes(self, context: bpy.types.Context):
|
||||
sceneProps = bpy.data.node_groups.get("SceneProperties")
|
||||
@@ -165,10 +159,9 @@ def poll_oot_scene(self, object):
|
||||
|
||||
|
||||
def resync_scene_props():
|
||||
if "ShdCol_L" in bpy.data.node_groups and "GeometryNormal_WorldSpace" in bpy.data.node_groups:
|
||||
renderSettings: "Fast64RenderSettings_Properties" = bpy.context.scene.fast64.renderSettings
|
||||
if "GetSpecularNormal" in bpy.data.node_groups:
|
||||
# Lighting space needs to be updated due to the nodes being shared and reloaded
|
||||
update_lighting_space(renderSettings)
|
||||
update_lighting_space(bpy.context.scene.fast64.renderSettings)
|
||||
|
||||
|
||||
class Fast64RenderSettings_Properties(bpy.types.PropertyGroup):
|
||||
@@ -191,8 +184,8 @@ class Fast64RenderSettings_Properties(bpy.types.PropertyGroup):
|
||||
default=(0.5, 0.5, 0.5, 1),
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
lightColor: bpy.props.FloatVectorProperty(
|
||||
name="Light Color",
|
||||
light0Color: bpy.props.FloatVectorProperty(
|
||||
name="Light 0 Color",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
min=0,
|
||||
@@ -200,13 +193,45 @@ class Fast64RenderSettings_Properties(bpy.types.PropertyGroup):
|
||||
default=(1, 1, 1, 1),
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
lightDirection: bpy.props.FloatVectorProperty(
|
||||
name="Light Direction",
|
||||
light0Direction: bpy.props.FloatVectorProperty(
|
||||
name="Light 0 Direction",
|
||||
subtype="DIRECTION",
|
||||
size=3,
|
||||
min=-1,
|
||||
max=1,
|
||||
default=mathutils.Vector((0.5, 0.5, 1)).normalized(), # pre normalized
|
||||
default=mathutils.Vector((1.0, -1.0, 1.0)).normalized(), # pre normalized
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
light0SpecSize: bpy.props.IntProperty(
|
||||
name="Light 0 Specular Size",
|
||||
min=1,
|
||||
max=255,
|
||||
default=3,
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
light1Color: bpy.props.FloatVectorProperty(
|
||||
name="Light 1 Color",
|
||||
subtype="COLOR",
|
||||
size=4,
|
||||
min=0,
|
||||
max=1,
|
||||
default=(0, 0, 0, 1),
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
light1Direction: bpy.props.FloatVectorProperty(
|
||||
name="Light 1 Direction",
|
||||
subtype="DIRECTION",
|
||||
size=3,
|
||||
min=-1,
|
||||
max=1,
|
||||
default=mathutils.Vector((-1.0, 1.0, -1.0)).normalized(), # pre normalized
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
light1SpecSize: bpy.props.IntProperty(
|
||||
name="Light 1 Specular Size",
|
||||
min=1,
|
||||
max=255,
|
||||
default=3,
|
||||
update=on_update_render_preview_nodes,
|
||||
)
|
||||
useWorldSpaceLighting: bpy.props.BoolProperty(
|
||||
@@ -214,7 +239,7 @@ class Fast64RenderSettings_Properties(bpy.types.PropertyGroup):
|
||||
)
|
||||
# Fog Preview is int because values reflect F3D values
|
||||
fogPreviewPosition: bpy.props.IntVectorProperty(
|
||||
name="Fog Position", size=2, min=0, max=0x7FFFFFFF, default=(985, 1000), update=on_update_render_preview_nodes
|
||||
name="Fog Position", size=2, min=0, max=1000, default=(985, 1000), update=on_update_render_preview_nodes
|
||||
)
|
||||
# Clipping planes are float because values reflect F3D values
|
||||
clippingPlanes: bpy.props.FloatVectorProperty(
|
||||
|
||||
@@ -1321,6 +1321,12 @@ def gammaCorrect(linearColor):
|
||||
return list(mathutils.Color(linearColor[:3]).from_scene_linear_to_srgb())
|
||||
|
||||
|
||||
def s_rgb_alpha_1_tuple(linearColor):
|
||||
s_rgb = gammaCorrect(linearColor)
|
||||
s_rgb.append(1.0)
|
||||
return tuple(s for s in s_rgb)
|
||||
|
||||
|
||||
def gammaCorrectValue(linearValue):
|
||||
# doesn't need to use `colorToLuminance` since all values are the same
|
||||
return mathutils.Color((linearValue, linearValue, linearValue)).from_scene_linear_to_srgb().v
|
||||
@@ -1687,14 +1693,14 @@ def ootGetBaseOrCustomLight(prop, idx, toExport: bool, errIfMissing: bool):
|
||||
# code without circular dependencies.
|
||||
assert idx in {0, 1}
|
||||
col = getattr(prop, "diffuse" + str(idx))
|
||||
dir = (mathutils.Vector((1.0, 1.0, 1.0)) * (1.0 if idx == 0 else -1.0)).normalized()
|
||||
dir = (mathutils.Vector((1.0, -1.0, 1.0)) * (1.0 if idx == 0 else -1.0)).normalized()
|
||||
if getattr(prop, "useCustomDiffuse" + str(idx)):
|
||||
light = getattr(prop, "diffuse" + str(idx) + "Custom")
|
||||
if light is None:
|
||||
if errIfMissing:
|
||||
raise PluginError("Error: Diffuse " + str(idx) + " light object not set in a scene lighting property.")
|
||||
else:
|
||||
col = light.color
|
||||
col = tuple(c for c in light.color) + (1.0,)
|
||||
lightObj = lightDataToObj(light)
|
||||
dir = getObjDirectionVec(lightObj, toExport)
|
||||
col = mathutils.Vector(tuple(c for c in col))
|
||||
|
||||
Reference in New Issue
Block a user