Skip to content

Fix Combine Same Materials on 2.80 and older and related issues + Faulty UV fix optimisation #482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 50 additions & 26 deletions tools/armature.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import bpy
import copy
import math
import platform
import numpy as np
from mathutils import Matrix

from . import common as Common
Expand Down Expand Up @@ -391,6 +391,8 @@ def execute(self, context):
else:
meshes = Common.get_meshes_objects()

# Track how many uv coordinate components we fix
fixed_uv_coords = 0
for mesh in meshes:
Common.unselect_all()
Common.set_active(mesh)
Expand Down Expand Up @@ -424,41 +426,40 @@ def execute(self, context):

Common.sort_shape_keys(mesh.name, shapekey_order)


# Clean material names. Combining mats would do this too
Common.clean_material_names(mesh)
if not context.scene.combine_mats:
# Clean material names. Combining mats would do this too
Common.clean_material_names(mesh)

# If all materials are transparent, make them visible. Also set transparency always to Z-Transparency
if version_2_79_or_older():
all_transparent = True
for mat_slot in mesh.material_slots:
mat_slot.material.transparency_method = 'Z_TRANSPARENCY'
if mat_slot.material.alpha > 0:
all_transparent = False
mat = mat_slot.material
if mat:
mat.transparency_method = 'Z_TRANSPARENCY'
if mat.alpha > 0:
all_transparent = False
if all_transparent:
for mat_slot in mesh.material_slots:
mat_slot.material.alpha = 1
mat = mat_slot.material
if mat:
mat.alpha = 1
else:
if context.scene.fix_materials:
# Make materials exportable in Blender 2.80 and remove glossy mmd shader look
# Common.remove_toon_shader(mesh)
if mmd_tools_installed:
Common.fix_mmd_shader(mesh)
Common.fix_vrm_shader(mesh)
Common.add_principled_shader(mesh)
for mat_slot in mesh.material_slots: # Fix transparency per polygon and general garbage look in blender. Asthetic purposes to fix user complaints.
mat_slot.material.shadow_method = "HASHED"
mat_slot.material.blend_method = "HASHED"
mat = mat_slot.material
mat.shadow_method = "HASHED"
mat.blend_method = "HASHED"

# Remove empty shape keys and then save the shape key order
# Remove empty shape keys and then save the shape key order
Common.clean_shapekeys(mesh)
Common.save_shapekey_order(mesh.name)

# Combines same materials
if context.scene.combine_mats:
bpy.ops.cats_material.combine_mats()


# Reorders vrc shape keys to the correct order
Common.sort_shape_keys(mesh.name)

Expand All @@ -468,15 +469,38 @@ def execute(self, context):
shapekey.name = Translate.fix_jp_chars(shapekey.name)

# Fix faulty UV coordinates
fixed_uv_coords = 0
for uv in mesh.data.uv_layers:
for vert in range(len(uv.data) - 1):
if math.isnan(uv.data[vert].uv.x):
uv.data[vert].uv.x = 0
fixed_uv_coords += 1
if math.isnan(uv.data[vert].uv.y):
uv.data[vert].uv.y = 0
fixed_uv_coords += 1
uvs = np.empty(len(mesh.data.loops) * 2, dtype=np.single)
uvs_is_non_finite = np.empty(uvs.shape, dtype=bool)
for uv_layer in mesh.data.uv_layers:
uv_layer.data.foreach_get('uv', uvs)
# Get mask of all uvs components that are finite (not Nan and not +/- infinity) and temporarily store
# them in uvs_is_non_finite
np.isfinite(uvs, out=uvs_is_non_finite)
# Invert uvs_is_non_finite so that it is now correctly a mask of all uv components that are non-finite
# (NaN or +/- infinity)
np.invert(uvs_is_non_finite, out=uvs_is_non_finite)

# Count how many non-finite uv components there are
num_non_finite = np.count_nonzero(uvs_is_non_finite)
if num_non_finite > 0:
fixed_uv_coords += num_non_finite
# Fix the non-finite uv components by setting them to zero
uvs[uvs_is_non_finite] = 0
# Update the uvs with the fixed values
uv_layer.data.foreach_set('uv', uvs)

# Combines same materials
# combine_mats runs on all meshes in Common.get_meshes_objects() and gathers material hashes of all the
# materials of those meshes before combining, so it must be run after we have fixed all the materials.
if context.scene.combine_mats:
bpy.ops.cats_material.combine_mats()

# Adding principled shader to materials must happen after same materials have been combined, otherwise
# mmd_shader materials that are considered duplicates will have their same diffuse and ambient colors baked
# to different images, making the materials no longer be considered duplicates.
if not version_2_79_or_older() and context.scene.fix_materials:
for mesh in meshes:
Common.add_principled_shader(mesh)

# Translate bones and unhide them all
to_translate = []
Expand Down
14 changes: 7 additions & 7 deletions tools/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1769,13 +1769,13 @@ def get_bone_orientations(armature):


def clean_material_names(mesh):
for j, mat in enumerate(mesh.material_slots):
if mat.name.endswith('.001'):
mesh.active_material_index = j
mesh.active_material.name = mat.name[:-4]
if mat.name.endswith(('. 001', ' .001')):
mesh.active_material_index = j
mesh.active_material.name = mat.name[:-5]
for mat_slot in mesh.material_slots:
mat = mat_slot.material
if mat:
if mat.name.endswith(('. 001', ' .001')):
mat.name = mat.name[:-5]
elif mat.name.endswith('.001'):
mat.name = mat.name[:-4]


def mix_weights(mesh, vg_from, vg_to, mix_strength=1.0, mix_mode='ADD', delete_old_vg=True):
Expand Down
19 changes: 10 additions & 9 deletions tools/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,15 +796,16 @@ def execute(self, context):
objname = obj.name
if bpy.data.objects[objname].type == "MESH":
print("lowercasing material name for gmod for object "+objname)
for material in bpy.data.objects[objname].material_slots:
mat = material.material
sanitized_material_name = ""
for i in mat.name.lower():
if i.isalnum() or i == "_":
sanitized_material_name += i
else:
sanitized_material_name += "_"
mat.name = sanitized_material_name
for mat_slot in bpy.data.objects[objname].material_slots:
mat = mat_slot.material
if mat:
sanitized_material_name = ""
for i in mat.name.lower():
if i.isalnum() or i == "_":
sanitized_material_name += i
else:
sanitized_material_name += "_"
mat.name = sanitized_material_name


print("zeroing transforms and then scaling to gmod scale, then applying transforms.")
Expand Down
Loading