Skip to content

Commit

Permalink
move the thing into the thing and back
Browse files Browse the repository at this point in the history
  • Loading branch information
Lilaa3 committed Oct 26, 2024
1 parent f01d5e9 commit 2a2128e
Showing 1 changed file with 62 additions and 57 deletions.
119 changes: 62 additions & 57 deletions fast64_internal/f3d/bsdf_converter/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ def get_color_from_input(inp: str, previous_color: Color, f3d_mat: F3DMaterialPr


def fake_color_from_cycle(cycle: list[str], previous_color: Color, f3d_mat: F3DMaterialProperty, is_alpha=False):
default_colors = [Color(), Color(), Color(), Color(1.0, 1.0, 1.0, 1.0)]
a, b, c, d = [get_color_from_input(inp, previous_color, f3d_mat, is_alpha) for inp in cycle]
sign_extended_c = c.wrap(-1.0, 1.0001)
unwrapped_result = (a - b) * sign_extended_c + d
Expand Down Expand Up @@ -540,8 +539,10 @@ def find_linked_nodes(
return list(dict.fromkeys(nodes).keys())


def bsdf_mat_to_abstracted(material: Material, output_node: ShaderNode | None):
def bsdf_mat_to_abstracted(material: Material):
abstracted_mat = AbstractedN64Material(color=None)

output_node = find_output_node(material)
if output_node is None:
abstracted_mat.color = material.diffuse_color
return abstracted_mat
Expand Down Expand Up @@ -661,55 +662,13 @@ def get_vtx_layer(nodes):
def material_to_f3d(
obj: Object,
material: Material,
colors: np.ndarray,
uvs: np.ndarray | None = None,
lights_for_colors=False,
fog=False,
set_render_mode=False,
):
print(f"Converting BSDF material {material.name}")

output_node = find_output_node(material)

abstracted_mat = bsdf_mat_to_abstracted(material, output_node)

materials = obj.data.materials
loop_indexes = [
loop_idx
for poly in obj.data.polygons
for loop_idx in poly.loop_indices
if poly.material_index < len(materials) and materials[poly.material_index] == material
]

if uvs is not None:
uv_map_layer = obj.data.uv_layers.get(abstracted_mat.uv_map or "", obj.data.uv_layers.active)
print(f"Updating main UV map with {uv_map_layer.name} UVs from {material.name}.")
if uv_map_layer is not None:
for loop_index in loop_indexes:
uvs[loop_index] = uv_map_layer.data[loop_index].uv

def get_layer_and_convert(layer_name: str | None):
layer = obj.data.color_attributes.get(layer_name or "", obj.data.color_attributes.active)
if layer is None:
return None
layer_name = layer.name
convertColorAttribute(obj.data, layer_name)
return obj.data.color_attributes[layer_name] # HACK: layer cannot be trusted

# vertex colors are much more complex because of vertex alpha, we always handle them
col_layer = get_layer_and_convert(abstracted_mat.vertex_color)
if col_layer is not None:
for loop_idx in loop_indexes:
colors[loop_idx, :3] = col_layer.data[loop_idx].color[:3]

alpha_layer = get_layer_and_convert(abstracted_mat.vertex_alpha)
if alpha_layer is not None:
if abstracted_mat.alpha_is_median:
for loop_idx in loop_indexes:
colors[loop_idx, 3] = colorToLuminance(alpha_layer.data[loop_idx].color)
else:
for loop_idx in loop_indexes:
colors[loop_idx, 3] = alpha_layer.data[loop_idx].color[3]
abstracted_mat = bsdf_mat_to_abstracted(material)

# TODO: we need to implement a system that can handle different material setups
preset = getDefaultMaterialPreset("Shaded Solid")
Expand Down Expand Up @@ -743,22 +702,67 @@ def get_layer_and_convert(layer_name: str | None):
with bpy.context.temp_override(material=new_material):
update_all_node_values(new_material, bpy.context) # Reload everything

return new_material
return new_material, abstracted_mat


def obj_to_f3d(obj: Object, materials: dict[Material, Material]):
def obj_to_f3d(obj: Object, converted_materials: dict[Material, tuple[Material, AbstractedN64Material]]):
assert obj.type == "MESH"
if len(obj.data.materials) == 0:
preset = getDefaultMaterialPreset("Shaded Solid")
createF3DMat(obj, preset=preset)
return
print(f"Converting BSDF materials in {obj.name}")
uvs = np.empty((len(obj.data.loops), 2), dtype=np.float32) if len(obj.data.uv_layers) != 1 else None
colors = np.ones((len(obj.data.loops), 4), dtype=np.float32) # vertex colors
colors = np.ones((len(obj.data.loops), 4), dtype=np.float32) if len(obj.data.color_attributes) != 0 else None

loop_indexes: dict[Material, list] = {}
for poly in obj.data.polygons:
material = obj.data.materials[poly.material_index] if poly.material_index < len(obj.data.materials) else None
if material is None:
continue
if material not in loop_indexes:
loop_indexes[material] = []
for loop_idx in poly.loop_indices:
loop_indexes[material].append(loop_idx)

def get_layer_and_convert(layer_name: str | None):
layer = obj.data.color_attributes.get(layer_name or "", obj.data.color_attributes.active)
if layer is None:
return None
layer_name = layer.name
convertColorAttribute(obj.data, layer_name)
return obj.data.color_attributes[layer_name] # HACK: layer cannot be trusted

for index, material_slot in enumerate(obj.material_slots):
material = material_slot.material
if material is None or is_mat_f3d(material):
continue
if material in materials:
obj.material_slots[index].material = materials[material]
else:
obj.material_slots[index].material = material_to_f3d(obj, material, colors, uvs, colors)
if material not in converted_materials:
converted_materials[material] = material_to_f3d(obj, material, colors)
new_material, abstracted_mat = converted_materials[material]
obj.material_slots[index].material = new_material

if uvs is not None: # apply the used uv or fallback on active
uv_map_layer = obj.data.uv_layers.get(abstracted_mat.uv_map or "", obj.data.uv_layers.active)
print(f"Updating main UV map with {uv_map_layer.name} UVs from {material.name}.")
if uv_map_layer is not None:
for loop_index in loop_indexes[material]:
uvs[loop_index] = uv_map_layer.data[loop_index].uv

# apply the used color/alpha or fallback on active
col_layer = get_layer_and_convert(abstracted_mat.vertex_color)
if col_layer is not None:
for loop_idx in loop_indexes[material]:
colors[loop_idx, :3] = col_layer.data[loop_idx].color[:3]
alpha_layer = get_layer_and_convert(abstracted_mat.vertex_alpha)
if alpha_layer is not None:
if abstracted_mat.alpha_is_median:
for loop_idx in loop_indexes[material]:
colors[loop_idx, 3] = colorToLuminance(alpha_layer.data[loop_idx].color)
else:
for loop_idx in loop_indexes[material]:
colors[loop_idx, 3] = alpha_layer.data[loop_idx].color[3]

if uvs is not None: # If there wasn´t exactly one UV map, we need to create one singular UV map
while len(obj.data.uv_layers.values()) > 0:
obj.data.uv_layers.remove(obj.data.uv_layers.values()[0])
Expand All @@ -768,15 +772,16 @@ def obj_to_f3d(obj: Object, materials: dict[Material, Material]):

while len(obj.data.color_attributes) > 0: # remove all existing colors
obj.data.color_attributes.remove(obj.data.color_attributes[0])
alpha_layer = obj.data.color_attributes.new("Alpha", "FLOAT_COLOR", "CORNER")
# get the alpha as rgb, then flatten it
alpha_layer = obj.data.color_attributes.new("Alpha", "FLOAT_COLOR", "CORNER")
alpha_layer.data.foreach_set("color", np.repeat(colors[:, 3][:, np.newaxis], 4, axis=1).flatten())
# set the alpha to 1 for the color layer
color_layer = obj.data.color_attributes.new("Col", "FLOAT_COLOR", "CORNER")
colors[:, 3] = 1 # set the alpha to 1 for the color layer
colors[:, 3] = 1
color_layer.data.foreach_set("color", colors.flatten())


def obj_to_bsdf(obj: Object, materials: dict[Material, Material], put_alpha_into_color: bool):
def obj_to_bsdf(obj: Object, converted_materials: dict[Material, Material], put_alpha_into_color: bool):
assert obj.type == "MESH"
print(f"Converting F3D materials in {obj.name}")
if put_alpha_into_color:
Expand All @@ -785,7 +790,7 @@ def obj_to_bsdf(obj: Object, materials: dict[Material, Material], put_alpha_into
material = material_slot.material
if material is None or not is_mat_f3d(material):
continue
if material in materials:
obj.material_slots[index].material = materials[material]
if material in converted_materials:
obj.material_slots[index].material = converted_materials[material]
else:
obj.material_slots[index].material = material_to_bsdf(material, put_alpha_into_color)

0 comments on commit 2a2128e

Please sign in to comment.