Skip to content

Commit

Permalink
Shape Keys handling fix
Browse files Browse the repository at this point in the history
  • Loading branch information
SpectrumQT committed Jul 3, 2024
1 parent 3b61365 commit 68dd9d4
Show file tree
Hide file tree
Showing 14 changed files with 93 additions and 53 deletions.
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,22 @@

## For Mod Authors

The 1.1 update has introduced huge changes into the rendering pipeline and 3d assets, to update mods that were made for 1.0 please follow the steps below:
1. Update your [WWMI Tools Blender plugin to 0.8.1](https://github.com/SpectrumQT/WWMI-TOOLS/releases/tag/v0.8.1).
2. Make a new frame dump of modded object (with mod disabled!) and extract it again.
3. Import newly extracted object into Blender (use default Merged Skeleton setting)
4. Make changed Vertex Groups ids in your custom mesh match ones of new import (you may use [Weight Match Blender Addon](https://gamebanana.com/tools/15699) to speed up the process)
5. Export your updated custom model as new mod into new folder (use default Merged Skeleton setting).
6. Check textures one by one and move the ones you've edited from old to new mod folder.
**WWMI 0.6.1** and **WWMI Tools 0.8.2** updates resolved issues with Shape Keys (face and shoulder animations). To fix existing mods:
1. Update **WWMI** to the [latest version](https://github.com/SpectrumQT/WWMI/releases/latest).
2. Update **WWMI Tools** Blender plugin to the [latest version](https://github.com/SpectrumQT/WWMI-TOOLS/releases/latest).
3. Restart Bledner.
4. If you created WWMI mod before Wuthering Waves 1.0 update, follow [Modder Guide](https://github.com/SpectrumQT/WWMI-TOOLS/blob/main/guides/modder_guide.md) instead.
5. Export mod to the new folder (or backup and use existing one).
6. Apply any desired manual tweaks to the new mod.ini and move textures.

## Known Issues
Blurry edges on modded model during fast movement (fix: disable DLSS or FSR)
Glitching see-through 'white shadow' when character is behind large boss (fix: reduce Shadow Quality in Graphics Settings)
Shape Keys aren't (fully) loading for Jinshi and other characters (research required)

- Blurry edges on modded model during fast movement (fix: disable DLSS or FSR)
- Glitch with duplicate modded objects on screen (merged skeleton limitation)

## Disclaimers

- **Alpha-1 Warning** — WWMI is in early alpha testing phase, so you can expect all kinds of issues. Also, please keep in mind that WWMI feature set and formats are not set in stone and may be subject to change.

## Features

Expand All @@ -35,10 +39,6 @@ The 1.1 update has introduced huge changes into the rendering pipeline and 3d as
- **Shape Keys Support** — Automatically handles original shape keys and supports custom ones
- **Customizable Export** — Fast mod export engine with per-buffer export support

## Disclaimers

- **Alpha-1 Warning** — WWMI is in early alpha testing phase, so you can expect all kinds of issues. Also, please keep in mind that WWMI feature set and formats are not set in stone and may be subject to change.

## How To Use

All fields and actions of the plugin have basic tooltips. Refer to [Modder Guide](https://github.com/SpectrumQT/WWMI-TOOLS/blob/main/guides/modder_guide.md) for more details.
Expand Down
9 changes: 9 additions & 0 deletions guides/modder_guide.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
<h1>WWMI Tools Modder Guide</h1>

<h2>How To Update WWMI 1.0 Mod to 1.1</h2>

The WuWa 1.1 update has introduced huge changes into the rendering pipeline and 3d assets, to update mods that were made for 1.0 please follow the steps below:
1. Make a new frame dump of modded object (with mod disabled!) and extract it again.
2. Import newly extracted object into Blender (use default Merged Skeleton setting)
3. Make changed Vertex Groups ids in your custom mesh match ones of new import (you may use [Weight Match Blender Addon](https://gamebanana.com/tools/15699) to speed up the process)
4. Export your updated custom model as new mod into new folder (use default Merged Skeleton setting).
5. Check textures one by one and move the ones you've edited from old to new mod folder.

<h2>Frame Dump Objects Export</h2>

1. Start the game with **WWMI Loader.exe**
Expand Down
4 changes: 2 additions & 2 deletions wwmi-tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

bl_info = {
"name": "WWMI Tools",
"version": (0, 8, 1),
"wwmi_version": (0, 6, 0),
"version": (0, 8, 3),
"wwmi_version": (0, 6, 1),
"blender": (2, 80, 0),
"author": "SpectrumQT, DarkStarSword",
"location": "View3D > Sidebar > Tool Tab",
Expand Down
8 changes: 4 additions & 4 deletions wwmi-tools/blender_export/blender_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ def get_default_data_map():
BufferSemantic(AbstractSemantic(Semantic.RawData), DXGIFormat.R32_UINT),
],
'ShapeKeyVertexOffset': [
BufferSemantic(AbstractSemantic(Semantic.RawData, 0), DXGIFormat.R16_FLOAT, stride=6),
BufferSemantic(AbstractSemantic(Semantic.RawData, 1), DXGIFormat.R16_FLOAT, stride=6),
BufferSemantic(AbstractSemantic(Semantic.RawData, 0), DXGIFormat.R16_FLOAT),
],
},
)
Expand Down Expand Up @@ -233,7 +232,7 @@ def extract_shapekey_data(loop_data, shapekeys, shapekey_data):

for vertex_id, vertex_offsets in shapekey.items():
shapekey_vertex_ids.extend([vertex_id])
shapekey_vertex_offsets.extend(vertex_offsets)
shapekey_vertex_offsets.extend(vertex_offsets + [0, 0, 0])
shapekey_verts_count += 1

return shapekey_offsets, shapekey_vertex_ids, shapekey_vertex_offsets
Expand Down Expand Up @@ -307,7 +306,8 @@ def blender_export(operator, context, cfg, data_map):

object_merger = ObjectMerger(
extracted_object=extracted_object,
ignore_hidden=cfg.ignore_hidden,
ignore_hidden_objects=cfg.ignore_hidden_objects,
ignore_muted_shape_keys=cfg.ignore_muted_shape_keys,
apply_modifiers=cfg.apply_all_modifiers,
context=context,
collection=cfg.component_collection,
Expand Down
37 changes: 23 additions & 14 deletions wwmi-tools/blender_export/ini_maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

from ..migoto_io.buffers.byte_buffer import ByteBuffer

from ..migoto_io.ini_builder.IniBuilder import IniBuilder, IniSection, SectionType, IniSectionConditional

from ..extract_frame_data.metadata_format import ExtractedObject

from .object_merger import MergedObject, SkeletonType
from .metadata_collector import Version, ModInfo
from .texture_collector import Texture
from .ini_builder.IniBuilder import IniBuilder, IniSection, SectionType, IniSectionConditional


def is_ini_edited(ini_path):
Expand Down Expand Up @@ -109,7 +110,7 @@ def make_mod_state_group(self):
self.ini.add_section(constants, 0)

constants.body.add_comment(r'Allows WWMI to safely disable incompatible mod and notify user about it')
constants.body.add_command(r'global $required_wwmi_version = %.1f' % self.mod_info.required_wwmi_version.as_float())
constants.body.add_command(r'global $required_wwmi_version = %.2f' % self.mod_info.required_wwmi_version.as_float())

constants.body.add_comment(r'Number of indices in original model')
constants.body.add_command(r'global $object_guid = %d' % self.extracted_object.index_count)
Expand Down Expand Up @@ -176,12 +177,12 @@ def make_mod_state_group(self):
last_draw_count_if_body = last_draw_count_condition.add_if_clause('$last_draw_count == 0 && $\WWMIv1\in_character_menu')
last_draw_count_if_body.add_command(r'$delay_load = time + 0.5')

draw_count_body.add_comment(r'Delays load of custom model for 0.5s if there were more than 1.5x time of expected draw calls')
draw_count_body.add_comment(r'Avoids skeleton glitch when there are more than one object with modded model on screen')
component_draw_count_condition = draw_count_body.add_command(IniSectionConditional())
# draw_count_body.add_comment(r'Delays load of custom model for 0.5s if there were more than 1.5x time of expected draw calls')
# draw_count_body.add_comment(r'Avoids skeleton glitch when there are more than one object with modded model on screen')
# component_draw_count_condition = draw_count_body.add_command(IniSectionConditional())

last_draw_count_if_body = component_draw_count_condition.add_if_clause('$draw_counter > $\WWMIv1\component_draw_calls_count')
last_draw_count_if_body.add_command(r'$delay_load = time + 0.5')
# last_draw_count_if_body = component_draw_count_condition.add_if_clause('$draw_counter > $\WWMIv1\component_draw_calls_count')
# last_draw_count_if_body.add_command(r'$delay_load = time + 0.5')

draw_count_body.add_comment(r'Copy completed merged skeleton from previous frame to override original skeleton with it in current frame')
copy_skeleton_condition = draw_count_body.add_command(IniSectionConditional())
Expand Down Expand Up @@ -443,19 +444,27 @@ def make_draw_calls_group(self):

mod_enabled_body.add_comment(r'Skip original draw call')
mod_enabled_body.add_command(r'handling = skip')

mod_enabled_body.add_comment(r'Override shared resources')
mod_enabled_body.add_command(f'run = {replace_shared_resources.get_section_title()}')

mod_enabled_body.add_comment(r'Override textures')
mod_enabled_body.add_command(f'run = {replace_textures.get_section_title()}')

custom_component = self.merged_object.components[component_id]
if len(custom_component.objects) > 0:

mod_enabled_body.add_comment(r'Override shared resources')
mod_enabled_body.add_command(f'run = {replace_shared_resources.get_section_title()}')

mod_enabled_body.add_comment(r'Override textures')
mod_enabled_body.add_command(f'run = {replace_textures.get_section_title()}')

for obj in custom_component.objects:
mod_enabled_body.add_persistent_comment(f'Draw {obj.name}')
mod_enabled_body.add_command(f'drawindexed = {obj.index_count}, {obj.index_offset}, 0')
else:

mod_enabled_body.add_comment(r'Override shared resources')
mod_enabled_body.add_persistent_comment(f'run = {replace_shared_resources.get_section_title()}')

mod_enabled_body.add_comment(r'Override textures')
mod_enabled_body.add_persistent_comment(f'run = {replace_textures.get_section_title()}')

mod_enabled_body.add_persistent_comment(f'Draw skipped: No matching custom components found')

def make_texture_resources_group(self):
Expand Down Expand Up @@ -592,7 +601,7 @@ def make_shape_keys_override_group(self):
)
self.ini.add_section(multiply_shapekeys, 4)
multiply_shapekeys.body.add_comment(r'Pass number of shapekeyed vertices to adjust required threads count via dipatch_y')
multiply_shapekeys.body.add_command(r'$\WWMIv1\shapekey_vertex_count = $shapekey_vertex_count')
multiply_shapekeys.body.add_command(r'$\WWMIv1\custom_vertex_count = $mesh_vertex_count')
multiply_shapekeys.body.add_comment(r'Run custom Shape Key Multiplier CS to set deformation intensity')
multiply_shapekeys.body.add_command(r'run = CustomShader\WWMIv1\ShapeKeyMultiplier')

Expand Down
34 changes: 24 additions & 10 deletions wwmi-tools/blender_export/object_merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class ObjectMerger:
# Input
context: bpy.context
extracted_object: ExtractedObject
ignore_hidden: bool
ignore_hidden_objects: bool
ignore_muted_shape_keys: bool
apply_modifiers: bool
collection: str
skeleton_type: SkeletonType
Expand Down Expand Up @@ -90,7 +91,7 @@ def import_objects_from_collection(self):

for obj in get_collection_objects(self.collection):

if self.ignore_hidden and object_is_hidden(obj):
if self.ignore_hidden_objects and object_is_hidden(obj):
continue

if obj.name.startswith('TEMP_'):
Expand Down Expand Up @@ -118,21 +119,34 @@ def prepare_temp_objects(self):

for temp_object in component.objects:
temp_obj = temp_object.object
# Remove ignored or unexpected vertex groups
if self.skeleton_type == SkeletonType.Merged:
total_vg_count = sum([component.vg_count for component in self.extracted_object.components])
ignore_list = [vg for vg in get_vertex_groups(temp_obj) if 'ignore' in vg.name.lower() or vg.index >= total_vg_count]
elif self.skeleton_type == SkeletonType.PerComponent:
extracted_component = self.extracted_object.components[component_id]
total_vg_count = len(extracted_component.vg_map)
ignore_list = [vg for vg in get_vertex_groups(temp_obj) if 'ignore' in vg.name.lower() or vg.index >= total_vg_count]
# Remove muted shape keys
if self.ignore_muted_shape_keys and temp_obj.data.shape_keys:
for shapekey_id in range(len(temp_obj.data.shape_keys.key_blocks)):
sheape_key = temp_obj.data.shape_keys.key_blocks[shapekey_id]
if sheape_key.mute:
temp_obj.shape_key_remove(sheape_key)
# Apply all modifiers to temporary object
if self.apply_modifiers:
with OpenObject(self.context, temp_obj) as obj:
selected_modifiers = [modifier.name for modifier in get_modifiers(obj)]
apply_modifiers_for_object_with_shape_keys(self.context, selected_modifiers, None)
# Triangulate temporary object, this step is crucial as export supports only triangles
triangulate_object(self.context, temp_obj)
# Handle Vertex Groups
vertex_groups = get_vertex_groups(temp_obj)
if self.skeleton_type == SkeletonType.Merged:
# Exclude VGs with 'ignore' tag or with higher id VG count from Metadata.ini for current component
total_vg_count = sum([component.vg_count for component in self.extracted_object.components])
ignore_list = [vg for vg in vertex_groups if 'ignore' in vg.name.lower() or vg.index >= total_vg_count]
elif self.skeleton_type == SkeletonType.PerComponent:
# Exclude VGs with 'ignore' tag or with higher id VG count from Metadata.ini for current component
extracted_component = self.extracted_object.components[component_id]
total_vg_count = len(extracted_component.vg_map)
ignore_list = [vg for vg in vertex_groups if 'ignore' in vg.name.lower() or vg.index >= total_vg_count]
# Rename VGs to their indicies to merge ones of different components together
for vg in vertex_groups:
vg.name = str(vg.index)
# Remove ignored or unexpected vertex groups
remove_vertex_groups(temp_obj, ignore_list)
# Calculate vertex count of temporary object
temp_object.vertex_count = len(temp_obj.data.vertices)
Expand Down
26 changes: 17 additions & 9 deletions wwmi-tools/wwmi_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ class WWMI_Settings(bpy.types.PropertyGroup):

mirror_mesh: BoolProperty(
name="Mirror Mesh",
description="Automatically mirror mesh to match actual in-game left-right",
default=True,
description="Automatically mirror mesh to match actual in-game left-right. May cause issues with some Blender tools. Can be me manually set via adding or removing '-' sign for Scale X in Transform section of Object Properties",
default=False,
) # type: ignore

########################################
Expand All @@ -136,12 +136,6 @@ class WWMI_Settings(bpy.types.PropertyGroup):
type=bpy.types.Collection,
# default=False
) # type: ignore

ignore_hidden: BoolProperty(
name="Ignore Hidden Objects",
description="If enabled, hidden objects inside Components collection won't be exported",
default=False,
) # type: ignore

mod_output_folder: StringProperty(
name="Mod Folder",
Expand Down Expand Up @@ -244,6 +238,18 @@ class WWMI_Settings(bpy.types.PropertyGroup):
description="Contains shape keys data",
default=True,
) # type: ignore

ignore_hidden_objects: BoolProperty(
name="Ignore Hidden Objects",
description="If enabled, hidden objects inside Components collection won't be exported",
default=False,
) # type: ignore

ignore_muted_shape_keys: BoolProperty(
name="Ignore Muted Shape Keys",
description="If enabled, muted (unchecked) shape keys won't be exported",
default=True,
) # type: ignore

apply_all_modifiers: BoolProperty(
name="Apply All Modifiers",
Expand Down Expand Up @@ -580,13 +586,15 @@ def draw_menu_export_mod(self, context):
layout.row()

layout.row().prop(cfg, 'component_collection')
layout.row().prop(cfg, 'ignore_hidden')
layout.row().prop(cfg, 'object_source_folder')
layout.row().prop(cfg, 'mod_output_folder')
layout.row().prop(cfg, 'mod_skeleton_type')

layout.row()

layout.row().prop(cfg, 'ignore_hidden_objects')
layout.row().prop(cfg, 'ignore_muted_shape_keys')

layout.row().prop(cfg, 'partial_export')

if cfg.partial_export:
Expand Down

0 comments on commit 68dd9d4

Please sign in to comment.