Transferring a costume from one character or game to another - eArmada8/gust_stuff GitHub Wiki
Transferring a costume from one character or game to another
Tutorial time! This is a longer and more complex tutorial, but it is worth your time to try. First, once you know how to do this, it can actually be done fairly quickly. Second, it will teach you many skills, such as weight transfer / mesh segmentation, adding new meshes and textures, etc. I am going to take Ryza's Sunlight Flower DLC from Ryza 1, and port it to Ryza 2. This is the finished product that we will achieve in this tutorial:
You want to know how to get a model into Blender and through the compilation process in the first place. Please try this tutorial at least once, then come back. Also install the following three plugins: blender_select_polygons_in_vgmap.py, blender_lock_groups_with_vgmap.py and blender_delete_empty_vertex_groups.py (Right Click, Save As)
Please understand that this is an advanced skill and you should already know how to use Blender and make basic modifications; I recommend also learning how to make basic texture modifications although this is not strictly needed. Also, I highly recommend understanding the basics of skeletal animation and weight transfer, or parts of this tutorial will seem like black magic and troubleshooting will be difficult. If you've never watched "3DMigoto Costume Mod Tutorial for Fairy Tail (PC)" by Ikaros, watch it.
Preparing the recipient model
First, let's get the models we need. I grabbed Ryza's Sunlight Flower (pc00i) from Ryza 1, which I will refer to as the donor model, and Ryza's Tropical Summer (pc20f) from Ryza 2, which I will refer to as the recipient model.
Extract both models.
Let's examine pc20f (the recipient model) first. Let's figure out which meshes we will delete - basically the entire body. We will be replacing or deleting 4, 5, 6, 7 and 9. We will not be keeping any parts of those meshes, but sometimes you will want to keep something (a piece of jewelry for example) - in which case you will delete the parts you do not need while keeping the parts you do (tutorial here).
Hide these meshes, but do not delete them. We will need them for weight transfer later!
Copying assets from the donor model
Ok, on to the donor model! Import all of pc00i. Figure out what you are keeping, and delete the rest. Here I figured out I am keeping 0, 3, 6, 7, 8, 9, and possibly 10. Note: Mesh 0, which is part of the swimsuit top tie, is a cloth mesh (4D) and thus it cannot be transferred as weighted.
Mesh 10 is a troubling one - it has its own shader and is completely hidden behind the other meshes - it is never visible! Here I have loaded it in the gltf with textures, so I can see what it looks like. It does not look like a mesh Gust ever intended to be seen. We will leave it out. In the end, I transferred only 0, 3, 6, 7, 8, 9.
I will also be removing the hair clip and the black hair band. They overlap in the wrong places, and she will have a similar hair band from her cap anyway. Delete these parts of the mesh.
Merging meshes with identical materials
Before we proceed to dealing with weight transfer, let's merge the meshes that we can merge. This will make life easier coming up, since there are steps that we must repeat on every single transferred mesh.
Open up mesh_metadata.json for the donor, Ryza's Sunlight Flower (pc00i). Remember we are transferring meshes 0, 3, 6, 7, 8, 9. Go to the MESH_LOD section of the metadata, and take note of which shaders draw those meshes. You can see here that actually the same shaders (@339F19F6 in block 0 and @00012B6D in block 1) draw all five of our basic meshes (3, 6, 7, 8, 9). Which shader draws mesh 0 is irrelevant, because it is a cloth mesh and we cannot transfer it directly.
Looking in the SUBMESH section, we can see what textures and shader parameters the shaders use. Here is a sample, for mesh 3, which is using textures (materialIndex) from MATERIALS section 0 and parameters (shaderParamIndex) from SHADER_PARAMS section 0.
Going through the metadata, I find:
Mesh 0: materialIndex 0, shaderParamIndex 2.
Mesh 3: materialIndex 0, shaderParamIndex 0.
Mesh 6: materialIndex 0, shaderParamIndex 2.
Mesh 7: materialIndex 0, shaderParamIndex 2.
Mesh 8: materialIndex 0, shaderParamIndex 2.
Mesh 9: materialIndex 0, shaderParamIndex 2.
Since I have confirmed that meshes 6, 7, 8, and 9 all use the same shader with the same materialIndex and shaderParamIndex sections, I can safely merge them for the coming steps. In Object mode, select all four meshes (hold down Ctrl and click on each one), then press Ctrl-J.
Note: Mesh 0 also has matching parameters and will be merged, but do not merge it yet as it is a cloth mesh!
Note that they all use the same material (textures+shader), but they all have different bone palettes! If you merge them and attempt to push them into the game, this will be the result.
We are only merging them now because we will be segmenting them back into pieces later.
Merging cloth meshes into basic meshes
We also need to place mesh 0 somewhere. As we can see from our investigations in the prior section, mesh 0 uses materialIndex 0 and shaderParamIndex 2, so it can join the body mesh. (It is strange that it is not part of the bikini mesh, but this is how the model is designed.)
The vertex groups for this mesh are meaningless; the only vertices with meaningful group assignments are the ones that touch the basic mesh it is attached to. As you can see, the vertices at the top have correct weights, the vertices below do not.
This vertex touches a basic mesh (7.vb), and so it has normal weights that add up to 1.0
This vertex is a 4D vertex, and has it no weights. (Some may be partially weighted.)
On the left, you can see the blue section in the lower section of the ribbon on both sides - there is no weight assigned there. On the right, the final product that is properly weighted.
In the image above, you can see that the vertices at the top are mostly governed by Spine2 (weight of 0.985, which means that 98.5% of the vertex movement is from Spine2). Therefore, the easiest way to proceed is to assign all the weight on the rest of the strip to Spine 2.
Go into Edit Mode, and turn on X-ray mode.
Use Circle Select (Select menu -> Circle Select), and select all the vertices except for the vertices that touch the basic mesh.
Select Spine2 in the list of vertex groups, make sure assignment is set to 1.000 (right below the Assign / Remove buttons), and press Assign.
In Weight Paint mode, use Normalize All (Weights Menu -> Normalize All), and deselect Lock Active.
Finally, merge mesh 0 into the body mesh (meshes 6+7+8+9). Repeat for any other cloth meshes that you want to transfer.
Note: This was a fairly simple mesh to merge, because we were able to satisfactorily assign all the weight to Spine2. For some meshes, you may need to assign the weight to more than one bone (vertex group). If that is the case, then follow the instructions below on joining the head to the neck. There I am copying the weights from the head to the neck - instead you will copy the weights from the properly weighted vertices to the vertices with empty weight assignments.
Finding missing bones
Now we need to evaluate the weight groups, to make sure the donor model meshes are compatible with the recipient skeleton. We will do this for each mesh. Before scanning for missing groups, go ahead and delete any unneeded groups. In object model, go to Object Data Properties (the upside down green triangle icon) on the side bar, vertex groups, and select Delete empty (unlocked) vertex groups (this is one of the plugins above).
Next, we need to find any missing groups by going to the same menu and selecting Lock groups using VGMap. Select all the recipient vgmaps from the backup folder.
Looking through the list, almost every bone is available from Ryza's skeleton from Ryza 2, but SWING000_L_Bust and SWING000_R_Bust are missing. (These are for breast physics.)
Luckily they actually exist in Ryza 2; if we look at 5.vgmap, we can see that there is a SWING000_L_Bust001 and SWING000_R_Bust001. (In fact, in Ryza 2, the breast physics bones have been split into two sets, SWING000_L_Bust001, SWING000_L_Bust002 and SWING000_R_Bust001, SWING000_R_Bust002, presumably for better physics.)
Just rename SWING000_L_Bust and SWING000_R_Bust to SWING000_L_Bust001 and SWING000_R_Bust001, respectively, and the model is ready for weight transfer. Here I am verifying readiness by running Lock groups using VGMap again. Every group is locked!
When you are done, be sure to unlock all the groups.
Repeat for each mesh that you are transferring.
Removing missing bones
Many times we are not so lucky. What if SWING000_L_Bust and SWING000_R_Bust did not exist in any form? Perhaps you are trying to move a costume from a character with those bones to one without, or similarly with skirt bones, etc. In these cases, we can remove the influence of those bones entirely by assigning their influence to those of their parents.
Remember that I actually renamed the bones above and now they exist. I do not need to remove them! I am including the following to teach you how to remove missing bones, but for this actual mod I have not removed them.
Looking at Ryza's Sunlight Flower (pc00i) skeleton (import the gltf), you can see that the parent of SWING000_L_Bust and SWING000_R_Bust is Spine2. (and looking at Ryza's skeleton from Ryza 2, you can see those bones are absent) NOTE: Do not edit or work with the meshes in the gltf, you will be wasting your time! Just use the gltf to see the skeleton!
This is our goal, moving the weight of SWING000_L_Bust and SWING000_R_Bust to Spine2. Then we should be able to safely delete SWING000_L_Bust and SWING000_R_Bust.
Blue -> Green -> Yellow -> Orange -> Red is weight going from 0% influence up to 100% influence. You can see how there is influence from Spine2 on the left, but very little on the breasts - because they are influenced primarily by SWING000_L_Bust and SWING000_R_Bust.
Unlock all the weight groups. In the sidebar, click Modifier Properties (the wrench icon), then Add Modifier, then Vertex Weight Mix. Set A to the bone we keep (Spine2), B to the bone we will delete (SWING000_R_Bust), set Vertex Set to VGroup A or B, set Mix Mode to Add. Repeat for SWING000_L_Bust. Apply the modifiers (it is in the drop down menu next to the camera icon).
Check in weight paint mode to make sure that Spine2 has the weight.
Now it is safe to delete the weight groups. Delete both groups.
Repeat for each mesh you are transferring. So we would have had to do this twice, once for the swimsuit and once for the body. But, luckily since all we had to do was rename the groups to SWING000_L_Bust001 and SWING000_R_Bust001, we saved time and preserved the physics of the model.
Preparing the meshes for segmentation
Now that we have meshes that are compatible with our recipient skeleton, it is time to segment them into smaller meshes that are compatible with our recipient bone palettes. Here is a preview of what we need to achieve:
NOTE: When I performed the following steps, I found that this mesh did not require any weight adjustment at all prior to mesh segmentation - I was very lucky and all of the triangles and vertices fit into the pc20f bone palettes! (Of course I still needed to segment the mesh.) This is not a common scenario, but I was lucky. Therefore, the following section is from an older tutorial I wrote, and that is why you may notice the meshes are not the same.
Now it is time to look for vertices that do not fit in the .vgmaps. Edit Mode > Select Menu > Select polygons using VGMap. Since we are going to start by fixing vertices, uncheck "Select intact polygons." It will now check each vertex against each map individually. Vertices that are not selected are ones that have groups that do not fit into a single map.
Here you can see the non-matching vertices; I have hidden the rest. On the one I've selected, SK_R_Index01 is on one vgmap and SK_L_ForeArm is on another. (Not surprising they are on separate maps, the bones are not even on the same side of the body!) If you look at the weights, SK_L_ForeArm contributes almost nothing to this vertex. We will remove it.
Here you can see me removing the last weight on another vertex that has almost no effect. Press X to delete the group, then press Normalize so that the weights are recalculated to add up to 1. Then press "H" to hide that vertex and move on to the next vertex. (Note that you can skip the normalize step as long as you use "Normalize All" {Weight Paint mode -> Weight menu -> Normalize All} after fixing all your vertices which will normalize all your vertices at once.)
Be sure to scan again when you are done. Sometimes there are multiple vertices at the same position. Notice I still have problematic vertices even after fixing all the vertices I could see. So I hide again, and fix, and scan again until all the vertices are fixed. (Above I said to hide as you work, this really cuts down on the number of hidden vertices; I did not yet discover that trick when I first wrote this.)
OPTIONAL: Repeat the same scan with fewer vgmaps (base them on the donor model) so you can figure out which vgmaps you actually need. I found I could select all the vertices with just 4, 5, 6, 7 and 9 - I removed all the head / face groups. Note that you do not need to do this, you can just use all the vgmaps and then whittle it down at the end, but I prefer to know which maps and meshes I need (and if I need to create new submeshes because the maps I need will be used by existing meshes that I am not replacing, etc).
Note that the scans above guarantees that all the vertices have a home, but not all polygons. For successful segmentation, the vertices on each segmented edge must be able to exist on BOTH vgmaps since they will be part of polygons on both edges! To understand this better, here is one of the edges where I will separate the mesh:
As you can see, the red arrow vertices belong to the upper mesh, and the blue arrow vertices belong to the lower mesh. For the triangle above to exist, all three red arrow vertices must belong to the upper mesh. For the triangle below to exist, all three blue arrow vertices must belong to the lower mesh. Therefore, the red/blue arrow vertices must belong to BOTH meshes. Blender will take care of this properly and automatically, as long as the vertices can fit in BOTH vgmaps.
Time to use polygon mode. Repeat the scan, using "Select Intact Polygons."
Notice that the gray polygons would be lost even though all the vertices belong to a vgmap! I will first work on the missing polygons on the upper thighs. I've labeled which mesh the hips and legs will be (9 and 4, respectively) on the picture.
I hid the intact polygons (press 'H') then I hid the forearm and hand polygons (I will work on them after). I've decided that I'm going to put those polygons on submesh 4 (looking at vertices above and below, I decided on above). I run a scan on vertices (select intact polygons unchecked) on map 4 only.
You can see above that the unselected vertices are the reason that these polygons will be lost. I hide the vertices that are good, and then I can start removing groups on the vertices that do not work. Same as before, do not forget to run the scan again after fixing the vertices to make sure there aren't any hidden ones.
Repeat the same process for any other homeless polygons.
Note: Ok, I actually did have to do the above process, just not with her body. But with her swimsuit, there was literally ONE vertex that prevented the swimsuit from fitting neatly into map 9 - the corner of the bracelet.
I decided to split the bracelet off from the swimsuit and merge it elsewhere. The bracelet itself fit perfectly into map 5 - but map five is already needed for her body. So I will be creating a new submesh instead, stay tuned.
Segmenting the Mesh
We will now start segmenting the body mesh. Select the first map. As stated earlier, I determined that I could account for the entire body mesh with 4 vgmaps (4,5,6,7). That means currently my body mesh has the contents of the future mesh 4, 5, 6 and 7 (4+5+6+7). Here I started with 4. Switch to face mode after selecting with vgmaps. You can see my first segment, every triangle here is covered by 4.vgmap.
Go to object mode, and duplicate the mesh (Shift-D). I now have two copies of the body mesh, and both copies have the same selection. Go back to edit mode on one of the meshes, invert the selection (Ctrl-I), and delete the faces. What is left behind will be the new 4.vb. Rename it to “New4” to reduce confusion.
Edit the other copy of the body mesh and delete the faces (without inverting). This mesh has everything that isn't in New4 (it is now 5+6+7).
Now pick another vgmap, and repeat on the second mesh. For me, I used 5.vgmap, and at the end I had New5 and (6+7). Keep going until you have segmented the mesh completely - you are done when the final scan lights up every remaining polygon. As planned, I needed 4 vgmaps in the end (4, 5, 6, 7).
Repeat for all your meshes. Once I was done with the body, I did the swimsuit. That one I separated into 2, without using the tool. The bracelet will use 5.vgmap and everything else will use 9.vgmap.
Weight transfer
Finally, once you have your segmented meshs, it is time to merge them into the real meshes. You cannot skip this step! Merging it into the real submeshes will rewrite the blend indices into the true vgmaps that the game uses, a process known as weight transfer. (Right now my meshes are still using internal Blender-derived indices.)
So far I have used 4.vgmap, 5.vgmap, 6.vgmap and 7.vgmap from pc20f, but remember the vgmaps are meaningless to Blender and to the game. We need the actual meshes that those vgmaps belong to. Import 4.vb, 5.vb, 6.vb, 7.vb from pc20f (hereafter I will refer to them as the recipient meshes). Note in the picture below that you can see both the mod meshes that we have been working on (the donor meshes) and the original pc20f meshes (the recipient meshes).
*Before going on, make sure to duplicate any mesh that you will need more than one of! Remember that I have both a body segment and the bracelet using 5.vgmap, so I need TWO copies of 5.vb. I duplicated it before moving on.
Let’s start with mesh 4. Go into edit mode on your newly-made submesh (New4, from the donor) and Select None.
Go into edit mode on the submesh with the true vgmap that you will replace (4.vb, from the recipient) and Select All.
Now in object mode, select the donor mesh New4 (click) then select the recipient mesh 4.vb (shift-click, or ctrl-click if you use the outliner window in the upper right). Press Ctrl-J.
There should only be one mesh now, and it should have the name of the recipient mesh (4.vb - very important this is not reversed!!!).
You can see that 4.vb is present, but New4 is gone. Be absolutely sure you merged in the correct direction! A->B is NOT the same as B->A!
Go into edit mode, and the vertices / polygons you want to delete should be selected. Delete them, leaving behind the vertices / polygons you want to keep. (It does not matter if you are in vertex, edge or face mode as long as you DO NOT CHANGE MODES before deleting.)
Again, repeat for all your other meshes (New5 into 5.vb, New6 into 6.vb, so on).
Repeat the above steps on the swimsuit (New9 into 9.vb). For the bracelet, I performed the anbove merge-and-delete into the second copy of 5.vb (bracelet into 5.vb.001). To remind myself of where it will go, I renamed the mesh 16.vb after I finished the merge-and-delete.
Export 4.vb, 5.vb, 6.vb, 7.vb, 9.vb and 16.vb: File menu -> Export -> 3DMigoto raw buffers (.vb + .ib). Overwrite the originals in your recipient (pc20f) folder.
This is an excellent time to check your work. There is still a decent amount of tutorial left, but none of it matters if you cannot get your weights correct. Therefore it would be prudent to load the model into game now to check your weights. Repack your model and load it in-game. Note that I was not able to check my bracelet since it would be inserted as a brand new mesh, but I can preview meshs 4,5,6,7 and 9 without editing metadata.)
We will still need to properly bond the neck to the head and fix all the materials, but the weight transfer was successful! If your weight transfer is not successful, do not attempt to keep going. Go back, fix your meshes, then return.
Connecting the recipient and donor meshes
Next, let's connect the body to the head.
First, scale the model, since for some reason Ryza is a little bit taller in Ryza 2. Select all your new meshes (4, 5, 6, 7, 9, 16). Object -> Transform -> Scale, then pull the mesh until neck lines up with the head (I use the chin here to make sure I'm accurate). Then apply your changes (Object -> Apply -> Scale).
Now I will move the vertices from mesh 5 (body, including neck) so that they are at the same place as mesh 3 (the rim of the face). Be sure to turn on Snap To Vertex. Select the Move tool(Shift-Spacebar, G) and the vertices at the edge of mesh 5 to connect to mesh 3.
Note, only move the vertices from mesh 5 to keep things simple! Although if you find it easier to move the vertices from mesh 3, then be sure to export it when you are done.
We will now duplicate the vertex weights from the donor head mesh (3) to the recipient neck mesh (5). If the vertices at head and the neck have differing weights, then they will move separately when the model is animated (since the weights tell the GPU how much to move each vertex when the skeleton is posed). Thus, the head and neck will come apart, which we definitely do not want.
There is more than one way to do this - this is the fastest way I have found. I am going to make all the changes to the neck, since that is the donor. I will not be changing the head.
We need the head to be temporarily part of the neck / body mesh. Duplicate the head (Object Mode -> Object Menu -> Duplicate Objects, or Shift-D). It will be moveable when you duplicate, move it upward a little to keep it away from the neck and then left-click to apply. Hide the original head.
Click on the head (in the layout, not in the outliner), then ctrl-click on the neck. The head should be outlined in red, the neck in orange. Join the meshes. (Object Mode -> Object Menu -> Join, or Ctrl-J). Be sure you joined the head to the neck, and not the neck to the head! (Order matters!) In the outliner, only the name of the neck/body mesh should remain, not the name of the duplicated head.
Note: for this specific mod, the weights already matched. The following images are from a different mod. I simply got lucky; expect the weights to be mismatched when you transfer meshes - especially when you transfer from one character to another!
Go into Edit mode, then vertex select mode. Here I selected a vertex, and I can see the vertex weights are Head 0.180003 and ago 0.819997. That means this vertex will move 18% from the influence of the Head bone, and 82% from the influence of the ago bone.
Ctrl-click on the vertex that it should match on the head. Notice that this vertex has 0.183246 on head and 0.816754 on ago. Very close, but different enough that the head will disconnect from the neck in animation! Press the Copy button, right below the weight values (next to Normalize). When you Ctrl-click on vertices, it selects multiple vertices. When you press copy, the weights of the most recent vertex are copied to all the others selected. Note that this does not work when the two objects are separate meshes for some reason, even if they are being edited together. You have to duplicate the head!)
Sometimes when you select a vertex, you'll notice that not all the edges running to that vertex light up (see the red arrow pointing at the edge that is not lit up). That means there are two or more vertices in the same location.
Go into X-Ray mode (Alt Z), and use Circle Select (Press C) to select all the vertices at the same time. (Notice in the picture below, now that edge on the right is lit up.) Ctrl-click on the upper vertex, and copy the weights.
Sometimes you might notice that there is a missing group, such as on this vertex that is 100% Head while the upper vertex is a mix of Head and ago. Select the lower vertex that you want to add a group to, select ago from the group list on the right, and press Assign. Now you can copy the weights correctly!
Other times you might find a group that should not be there. In this case, select the lower vertex, and press the X next to the weight group you want to get rid of. Again, you should now be able to copy the weights correctly.
Finally, when you are done, delete the duplicate head. You don't want that in the final model.
Adding a new texture pack
Because I do not want to edit any textures or move around any UV maps, I will expand pc20f.g1t to include new textures.
Up in the section Merging meshes with identical materials, we went through the donor metadata and made a table of the materialIndex and shaderParamIndex for the donor. In the donor model, I had found that all of my meshes used materialIndex 0 (of pc00i), which used 4 textures - 000.dds, 001.dds, 002.dds and 003.dds.
Since pc20f.g1t has 23 textures (000.dds through 022.dds), I will name the new ones 023.dds, 024.dds, 025.dds and 026.dds and then add them to pc20f.g1t
I will copy over the sections from g1t.json of pc00i into g1t.json of pc20f and renumber 000-003 to 023-026. Be careful with commas!!
Now we need to evaluate materialIndex and shaderParamIndex for the recipient model (pc20f); specifically for the meshes we are replacing.
Going through the metadata, I find:
Mesh 4: materialIndex 0, shaderParamIndex 2.
Mesh 5: materialIndex 0, shaderParamIndex 2.
Mesh 6: materialIndex 0, shaderParamIndex 2.
Mesh 7: materialIndex 0, shaderParamIndex 2.
Mesh 9: materialIndex 0, shaderParamIndex 0.
Additionally, I found that there are a total of 6 sections in MATERIAL, which are materialIndex 0 through materialIndex 5.
I will create a 7th section by copying the first section "id_referenceonly": 0
and placing it at the end. I named it "id_referenceonly": 6
so that I will not confuse myself, but it is not strictly necessary. I will replace the textures with the new ones that we added to the texture pack.
Now we tell the game to utilize the new texture pack. Go to the SUBMESH section. Go to the section for mesh 4, and then change materialIndex to 6. Repeat for meshes 5, 6, 7, and 9.
Adding a new mesh
Remember how we saved the bracelet as mesh 16? It needs to be added to the metadata so that the import tool will know to incorporate it into the g1m. A material (shader + textures) must be assigned so that the game is able to render it properly.
First, we will create a new entry in SUBMESH for mesh 16. The best method to do this is to copy another section that uses the same bone palette (vgmap). Because our new mesh utilizes 5.vgmap, I am going to copy the SUBMESH section "id_referenceonly": 5
.
I copied the section and pasted the copy at the end of the SUBMESH section. I changed the id to "id_referenceonly": 16
. Again, setting the id is not important to the tool - I do this to reduce my own confusion.
I want it to use the same materialIndex and shaderParamIndex as mesh 9 (the swimsuit), since the bracelet came from that mesh. Set materialIndex to 6, and then set shaderParamIndex to 0.
Remember that the material in g1m consists of 3 parts: the shader assignment, the shader parameter assignment and the texture assignment. We have assigned the latter two, but we have not yet assigned the submesh to an actual shader yet. We want to assign mesh 16 to the same shader as mesh 9, which are "@339F19F6"
and "@00012B6D"
in block 0 and block 1, respectively, of the MESH_LOD section. Add the number 16 to each list.
Repacking the mesh
Repack the meshes. If you did not repack the textures earlier, be sure to do that as well.
Test it in game. Hopefully everything went well! (You can see I am also using an altered texture that removes the sunburn from her legs. Thank you to the The Silver Vox.)
If you made it to the end of this tutorial, congratulations! Time to fire up photo mode and enjoy your mod!