Shenmue Animation Debug Thread

I had to admit that I'm definitely surprised to see the game go from the leg sticking out behind the player, to an animated walk cycle on a single leg. I went ahead ahead and passed the parameter into my parser to less than effective results. So let's go ahead and grab more data. The best way to do this is to probably disable each axis to test by adding one animation to see what the effect of each axis is.

That means that we will test x, xy and xyz. Admittedly it would be better to test x, y, z as each axis separately, but that would require a script to rewrite the order of the animation. To be lazy we'll do this by adding in one axis at a time. We're working with the fourth instruction which is 0x11c0. This is node id 8, which right now I think is attached to bone 33 in the mt5 rig. The instruction will have 3 bits for x, y and z. The bit for x is 0x100, the bit for y should be 0x80, and the bit for z is 0x40.

This means that to test only x we want to replace this instruction with 0x1100. To test xy we will replace the instruction with 0x1180, and then we already have the effect of xyz, which is the original value. Time to pull up the emulator and see how horribly this turns out.


Can't say I was expecting this. When we replace 0x11c0 with 0x1100 (and then 0x0000 in the the following instruction), we get the surprising result that this causes Ryo to pump his leg up and down. So we have the surprising result that the X axis is actually the Y axis. We can go ahead and pin that to the the wall of surprises. Let's go ahead and see what the next axis has in store for us.


Just when I think i've had enough crazy pills they just keep coming. Replacing 0x11c0 with 0x1180 showed no change from the previous animation. But this should provide us with a little of context with how the animation works. This could indicate that the x and y axis are swapped for the non-root position key values. Shenmue uses a pretty standard coordinate system. The z-axis is front to back with -z being the direction Ryo moves forward. The X axis is the direction to the left and right of his body, so it looks like the feet don't have any translation in that direction.

The keyframes should be in YXZ order, and then only Y and Z axis should have any values. We can go back and check the values we read from the MOTN file to confirm if this is what we see.
 
Last edited:
My relationship with my laptop literally has been touch and go. If I had more time, or shame then I might try and present a clear and consistent series of notes. But I have neither time or shame, so I'm writing what I can when I have time to pick up on and continue with.

I went ahead and loaded up the 0x11c0 instruction in my test environment, only applied that one animation. And split each axis of the animation into a separate axis. Here's the animation with only X:


Basically it does nothing.


In the Y direction, our happy little bones gets it up.


And then in Z only, it seems to start behind the model and move forward.

First weird thing is definitely the discrepancy with the game. I don't know why that the game moved the foot in the Y-direction even though threorhetically that bit was commented out. But the good news is that it looks like the actual key frames being read are in order and don't need to be shuffled around to be interpreted.

Now the issue is moving on to trying to replicate this functionality. As far as normal animations go, foot position is only going to stretch the foot and move the foot around and not any other bones on the leg. And it really does look the animation is defining the foot position. So what I'm going to do is isolate the Y axis of the animation and then see what it takes to get the knee to bend.
 
Screenshot_2020-08-02 three js webgl - loaders - MMD loader.png

I got tired of looking at sticks, and thought that being able to work with a mesh would probably help with visualizing how horribly the animations were being applied to be able to troubleshoot. This meant going back and parsing the strip format, which is pretty hard to work with, but surprisingly simple once you learn your way around it. Not sure how well documented this is, I'll go ahead and throw in what I found.

Screenshot from 2020-08-02 13-46-24.png

The MT5 model looks like a tweaked version of the .nj model type from the Dreamcast. It follows most of the same conventions, but with it's own minor tweaks. The bone/node format is almost completely the same. The vertex list is a little simpler because it has a simple vertex list weighted to a bone instead of a vertex chunk. And then strips look like they follow the chunk format.

Since I'm only working with the Ryo model, I'll write what applied to Ryo. I think this applied to most if not all of the models, the main different being the face index format which I will address later. The strip uses a chunk format which is a strategy for encoding information information in binary where the length of the information included doesn't use fixed structs sizes. Basically when it comes to the strips for each of the different models, the number of strips isn't fixed, and depending on the model, the information contained in the strip might be different.

What the game does it it declares a chunk header as a word, and the parser will know what information included inside that chunk. Following the chunk header is a word that contains the chunk length in bytes. It's basically a condensed version of the interchange file format. The strip chunks generally starts with the chunk type of 0x0e, which is probably the material definition. We can see that after the chunk type is declared, the length is given as 0x08. We have 8 bytes of what basically looks like 0xFFFFFFFF, which is basically white diffuse color. Not sure what 0x000000FF is, probably something stupid like a black ambient color.

Following that we have a chunktype defined as 0x08, which is followed by 0x00 as a value. Then we have a chunktype of 0x02, with a length of 0x10. Not sure what each one of these are, but it's easy enough to detect them and then seek passed them based on the chunktype. The chunktype 0x09 is the texture id definition for the strip. In this case the value is 0x00.

The following chunk 0x0b has the value of 0x400, and this is the value for converting uv's into a float. 0x400 represents 1.0 for the uv coordinates. So any uv values read in the strip for face vertex uv values will be words that are divided by this number. And then finally we come to the actual strips. There are three strip header types that I know of:

0x11 - index, u0 , v0
0x13 - index
0x1c - index, u0, v0, u1, v1

Depending on which header will define the index type definition. Each one of the value is 2 bytes. The chunk header for the strip type will define if there are 3, 1, or 5 two bytes values for each index. Following the chunk type header is the length of the chunk in bytes. Sometime the chunk length isn't exactly the size of the strips and indices, it can also include 2 bytes of padding to align to 4 byte boundaries, even though the programmers don't really seem to care that often.

After the length is the number of strips. And then each strip is defined by a length of indices, followed by the actual indices. The strip length is often given by a negative value, and this should define the wind order.

Code:
let clockwise = stripLen < 0;
for (let i = 0; i < strip.length - 2; i++) {
    let a, b, c;

    if (clockwise && i % 2 === 0) {
        a = strip[i + 1];
        b = strip[i + 0];
        c = strip[i + 2];
    } else {
        a = strip[i + 0];
        b = strip[i + 1];
        c = strip[i + 2];
    }

    let face = new THREE.Face3(a.i, b.i, c.i);
    face.materialIndex = texId;
    this.faces.push(face);

    let auv = new THREE.Vector2(a.u, a.v);
    let buv = new THREE.Vector2(b.u, b.v);
    let cuv = new THREE.Vector2(c.u, c.v);

    this.faceVertexUvs.push([auv, buv, cuv]);
}

When converting the strips to triangles, You start with three indices, and then alternate directions for each new triangle. Depending on if the strip length is positive or negative will dictate if the first triangle will start clockwise or counter-clockwise.

Next we have the indices, which are a little quirky. When strips are declared, they are created align side a list of vertices weighted to a specific bone. The strip indices are numbered relative to the start of the local vertex list. For instance if a model already has 365 vertices, and 97 vertices are declared, the strip indices will be labeled 0-96 referencing the local vertices. To read the file these indices will need to be mapped to full vertex list.

With indices there is a troublesome aspect, in that they can have negative values. And when they have negative values, they reference from the end of the local list declared in the parent bone. So if you have bone 0, 1, 2, 3. And bone 3 is a child of bone 0, you will need to seek back and reference the bone indexes from bone 0 even if more vertices were created in bones 1 and 2. So negative values aren't relative to the end of the total vertex stack, but to the vertices declared in the parent bone.

I understand that the Shenmue community already has a pretty good understanding of the model format, but I wasn't able to get a complete model of the strip format when made the Noesis plugin, so it was a little rewarding to comeback and get a more complete picture of what's going on. I need to port over my motn reading code into my newer texting environment and then I can get back to the regular schedule of failing at animations.
 
Last edited:
Okay, finally some progress. Can't say that it's very encouraging progress, but progress none the less. After managing to parse the mesh and get that displayed, I went ahead and added in weights, adding in the skeleton, and ported over the code for reading the key frame from the animation file.

So the first thing we can do is demonstrate why translation isn't normally used in FK animations outside of root bone position:


This is taking the position values read from the motion file and applying them to the foot. And generally when you think about it, you're body doesn't actually do translation. Your limbs move, but they achieve their movement through rotation. And thus with normal animations, you'll generally have root bone translation to describe how far or how high a character will move for that animation for a set of key frames, but otherwise everything else is defined with rotation to describe how the bones move.

Looking at the movement of the foot, and looking at the movement of the game, it looks like the game is using the target position of the foot to solve for the rotation of the knee, and solve to the rotation of the thigh. Which seems compelling enough to start looking into the option of IK, to see if that could be a possibility. Because while I would be more than happy to be able to apply what I know about animations and have that just work, the animation format doesn't seem to follow the conventions that I've seen with animations from other formats. So we can give it a try and if it doesn't work, proceed to rule it out as an option after testing it.

Screenshot_2020-08-05 three js examples.png

What makes me cautiously optimistic is this example page for Miku Miku Dance in threejs. On the right you can turn IK on and off, and if you turn it off, the legs stop working complete. The legs will rotate at the thigh, but then there is no planting for the feet, and the leg remains completely straight. And that seems to be a pretty close fit for how the Shenmue animations seem to be structured based on the order of the key frames.


I went ahead and cloned the page and swapped out for Ryo, and the the animation file. Got the IK chain rigged up for his legs, only to get the result of Ryo doing the lamest soccer kick in existence. But this is the first try, and first tries most often don't work out. What's more important is that now I have a testing environment set up, where I can test and debug different approaches to animation. So my starting point is going to be the right foot, because it's a really interested place to start with. So the next step will be to jump back into the game, isolate the right foot, and then start adding different key frame values to try and see how the foot behaves based on the values passed into it.
 
I hope it's not IK!

I have bad news and good news. To start breaking down the animations for testing, I wrote a script that removes all of the instructions you don't want the game to execute in block 1. In this case I only want it to execute node 0 and node 8. So the script will read through the animation, store the values deemed relevant and then create a new file that can be patched into a save state.


Bad news is that this is only the root bone and foot position, which is a really strong indication of IK. The good news however is that we can be pretty certain about the animation parser. As we're able to read a specific set of values associated with an instruction, pass those back into the game and have it work. The other good news is that we now know that to get this result we only need two instructions. So we can really break down, isolate and analyze node 8 to see how the game will react to different foot positions.
 
Huh? There are hand position keyframes too..

What my script does it will read all of the binary from the animation file, and then rebuild the animation using only the instructions allowed to pass through. So right now I've got it down so that the only instructions being evaluated are root bone position and the foot Ik target. Everything else will remain rigid.

Screenshot_2020-08-06 Shenmue Animation Debug Thread.png

Now I'm working on swapping out values. Root bone x is zero'd out, and Root bone Y is a fixed 1.1 value. Next we can start messing with other values to see how the game reacts.
 
Now we can get to testing, but first a quick look at the output of my script file.

Screenshot from 2020-08-06 21-44-46.png

Basically it writes a new script file with only the information allowed to pass through. In this case the only information. I've allowed to pass through is the root bone position and the right foot position. The script will then grab the necessary bytes from blocks 2, 3, 4 and 5 specifically for those instructions and pack them in the order the game reads them. I then fills everything else in with zero. The advantage of this is allows slimmed down animations to be created. We can then break down and replicate how the game interprets different bones.

The other advantage is that this also validates the motion parser. If the game only plays the root bone position and right foot animation position, then that means we have the right bytes all of the information available from the game to start interpreting the motion file. The video for this was already posted in the previous post, so let's move along to the testing part where we start testing.


In this video, I set the key frame values for the Foot to (0,0,0) for every frame. You can see the foot glitch out a little bit. I think this is an issue with the calculation of the slope, as it's a curve, But then as the character moves forward the foot lags behind the player.


And we can replicate this glitched behavior out of game Basically as Ryo moves forward the foot will continuously attempt to move towards the IK target which is stuck at (0,0,0) and the legs lags behind the character, like what we see in the game when we hack in these values. We can use this to interpret something interesting about how the game manages bones, and we reach an interesting conclusion that the root bone is not actually the real root bone.

Screenshot from 2020-08-06 22-04-13.png

What's actually happening is the game has a root bone that it leaves at (0,0,0) and the chest bone which is the first node in the MT5 model is what gets moved up and forward for the animation. And the IK target is moving relative to the root bone at (0,0,0). This is why my first attempt ended up having Ryo perform a soccer kick, because the IK target was moving relative to the chest, and therefor super far ahead of the model. We can update our interpretation of how the game is using these values by popping back into our test environment.


And we have something that closely resembles a walking animation. Granted it's still a little janky. There are instances where it looks like Ryo should be raising his foot, but the CCD solver ends up rotating the leg. Not sure if that will be solved if we start adding some constraints or if we calculate the slope values correctly, but either way we've read and interpreted values from the motn tile, and have been able to get them to display something coherent, so we'll continue to break down and refine more movement until we can get something that closer resembles the output from the game.

Edit:

A side note about Ryo doing a Micheal Jackson lean at the end. I think there is a point in the animation where the root boot snaps forward to a new location, where the IK targets are then calculated relative to that. We can see there is a frame where things are still normal.
Screenshot from 2020-08-06 22-14-03.png

Right before Ryo leans forward. This seems about when the root bone should be updated, and then if we look at last frame, it looks like it's basically set up to lead into the next walk animation cycle.
Screenshot from 2020-08-06 22-14-26.png

So the two factors I want to start focusing on next is to figure out how to calculate the slope animations, and then to look into constraints or anything else that would help better replicate the movement displayed in the game.
 
Last edited:
and then to look into constraints or anything else that would help better replicate the movement displayed in the game.

There really aren't any constraints used in the game. So while yes, we all agree that a lot of this seems like IK, this is where the IK thoughts kinda blur in a way. There are no known constraints used for any of the position values, but there is an array of values used with rotation values.. but that doesn't really make much sense for IK. Constraints in IK typically define the limits of influence that each bone in an IK chain would have, so it doesn't make sense that only rotation keyframes have this extra data, in IK, you'd expect to see the constraints used with the position keyframes, as those together are what would be used in the solver to determine the correct angles for all joints in the chain.

Outside of traditional IK which has effectively already been ruled out for you (no constraints), it leaves only a few options. I mentioned CCD to you via Discord a few weeks back as a very simplistic way of saying 'it's probably IK, but not conventional/traditional IK'.. but speaking to a few people, it seems that this could actually be a lot simpler than we're expecting. A 'constraint-less IK solution' exists which apparently "usually means taking the shortest path to the destination", which can be kinda seen in a couple of these GIFs of my research about a month ago:

arms.gif


Since I learned of this, I did a few more bits of testing with a debugger and found that this actually seems pretty legit. The actual motion updates seem to run for each node, for each frame of whatever the current non-"request" animation is. So perhaps instead of CCD, whereby constraints are somewhat requisitory, we should probably move to something a lot more simplistic in nature. I also tested this node's keyframes:


Code:
IKBoneID.Arm_L @ 957612
Rot X:
Frame: 0 @957612
Val: -0.1561260223388672 @ 957616
Frame: 16 @957618
Val: -13.480224609375 @ 957622
Frame: 24 @957624
Frame: 37 @957628
Val: -0.1561260223388672 @ 957632
Rot Y:
Frame: 0 @957634
Val: -5.29541015625 @ 957638
Frame: 8 @957640
Frame: 16 @957644
Val: -15.1611328125 @ 957648
Frame: 23 @957650
Val: -9.7998046875 @ 957654
Frame: 32 @957656
Val: -8.0584716796875 @ 957660
Frame: 37 @957662
Val: -5.29541015625 @ 957666
Rot Z:
Frame: 0 @957668
Val: -158.73046875 @ 957672
Frame: 4 @957674
Val: -163.125 @ 957678
Frame: 15 @957680
Val: -197.75390625 @ 957684
Frame: 17 @957686
Val: -198.28125 @ 957690
Frame: 20 @957692
Val: -197.75390625 @ 957696
Frame: 33 @957698
Val: -159.609375 @ 957702
Frame: 37 @957704
Val: -158.73046875 @ 957708

This is interesting for two reasons. 1) Elbow bends seem to be able to come from two situations: rotation keyframes on the UpperArm or Forearm 2) position keyframes on the end effector nodes. In the case of this specific walk sequence (of which there should be 2; 956058 and 953170), we seem to have both position keyframes for the end effector (LeftHandIKTarget) and the above rotation keyframes.

Example showing the LeftHandIKTarget position keyframes being modified:

 
Might as well take an opportunity to state the obvious. I think we're at the point where we can read all of the values from the game's motion file. When reading the values, the parser ends exactly at the end of the block, and the values contained are generally reasonable and fit the scale of the models. For further confirmation we can take the motion files, and trim them down and pass them back into the game, and have the game play through the partial motion file.

A full example output of the walk animation can be found here:

So now it's a matter of interpretation. A few notes to that end. My thinking is that when no value is declared for the first or last frame, the meaning is to probably use the bone's value directly for that frame. When no value is declared in a mid-frame, the purpose generally seems to adjust the curve at that frame. And when neither a value or curve is declared, the purpose seems to be to not apply any transformations to that axis.

curve_calc.png

In terms of curve calculation, I think this is going to be important for matching the look of the game. While testing using linear interpolation is going to be fine, but for the polish this is going to make a difference as there can be a pretty big difference between linear and curved as shown in the image above.

In terms of the animation, it seems pretty settled at this point that the game uses a mixture of IK and FK (which seems to be the standard for IK), specifically with IK targets for the right foot, left foot, right hand and left hand, with root bone position, and then rotation for the other limbs. I think the strategy here is to try and isolate and replicate the IK values, add in rotation, and then go back and calculate the curve values.

Currently I have a test environment loaded up in threejs, and I'm trying to track down the syntax sugar needed to make IK work. Right now I'm able to get to foot bones to follow a target, but the knees don't bend. So I'm hoping to be able to do that with the included CCD IK Solver.
 
Just for preview purposes, I manually keyframed 3 nodes' values the other day:


Still some slight inaccuracies, mainly the knee 'popping' etc, but this helps me visualize the data a bit better + gives further confidence I guess.

Also, I found the "IK solver":


Seems that the running animation is unaffected when I disable the "IK solver":

 
Last edited:
I thought I had posted the source for testing only specified bones for animations in-game. Looks like I didn't, so here's the source:
 
I took a small detour starting in August. Since working on Shenmue made me want to contrast against other more direct uses of the Ninja Library, I went ahead and wrote some tools for Ikaruga which can be found here: https://gitlab.com/dashgl/ikaruga.

Screenshot_2020-08-23 Dash Model Format - Preview(4).png

So now that's out of the way, time to get back to debugging Shenmue animations. And at this point I've managed to get threejs to use IK, the next step is to try to get all of the IK parts to animate (arms, and legs), and then move on to rotation. Which for now means to edit the animations, and make note of what happens.

Here we have only hand IK enabled.

hand.gif
 
Last edited:
I'll try to use this post as a scratchpad for the issue that I'm currently having with animation. Essentially the issue is when FK works IK doesn't work and when IK works FK doesn't work. I attempt to explain the issue is this video,


I didn't do a very good job so i'll try to break down what's going on in more detail here. Shenmue animations are FK mixed with IK and likely intepretted in the order as declared in block 1. My general approach is to implement IK on it's own, and then test the FK components on their own, and then apply both. And it's the apply both that's currently giving me problems for an issue that I will attempt to explain.

Step 1: IK

ik_walk.gif

This is what I currently have for IK. It's still rough in a few areas. As I'm using linear interpolation instead of calculating the bezier curve that's defined in the motn file. I also haven't implemented the torso or look at target. In general this is being animations with the IK targets for the hands and feet and at least generally resembles a walk animation.

There was a caveat that comes with IK, and that is I had to remove the rotation information from the bones. This is a little bit of an ambiguos statement, so I'll try and describe what I mean. Basically when reading the bones/nodes from the mt5 file, each bone is describe with a local position and a local rotation to describe the structure of the skeleton. In other words the bones are rotated and then translated into place. These means that the bones will have some rotational information associated with the t-pose, and the CCD solver doesn't seem to like this.

ikr_walk.gif

As this is the issue I was running into when trying to apply IK to the mt5 model with the skeleton as defined in the mt5 model. And this is where I had to remove rotations from the bones. Specifically what I mean by this is that I had to create a duplicate skeleton with the same world position, but no rotational values for the t-pose. The way this is done, is you take the world position of a bone, and subtract the world position of the parent bone to get the relative local position of the bone. And then you create a separate skeleton with the same position as the source file, and then rig the mesh to the cloned skeleton. But as we'll see in a second, this cloned skeleton creates complications for FK animations.

Step 2 : FK

Now that we have a proof of concept for the IK animations, we can go ahead and disable those to focus on FK. In terms of FK i think the easiest place to get started with is the thigh rotation. We can see the effects of this in game where the leg sticks out the back directly.


If this were normal FK, it's generally pretty easy to get this result. We take the rig that has been loaded in, we take the angles that have been provided for the animation, we convert that to a quaternion. And then Ryo will stick his leg out behind him.

Screenshot_2020-09-01 Shenmoo(1).png

The problem is that this is on the loaded-in rig. And not our cloned T-pose rig. So we need to do something to convert the angles so that they produce the same result on the T-pose rig, as that's the only rig IK works with. And after some trial and error I finally managed to find a combination that works.

Screenshot_2020-09-01 Shenmoo(2).png

This is the cloned rig, and we have the leg sticking out backward in the same way that normal rig does. So now finally we can put these two together and do a proof of concept to see if the leg part of the walk cycle looks correct before moving onto other limbs.
bad_walk.gif

And it's total dog shit. And this is the the frustrating part of about IK, it that it's dependent on the solver for that the result is going to be. Normally with FK you can isolate a bone, test it in game, test in your editor, disabled it move on to the next bone. And then do that for a sequence of bones and then be able to have predictable results.

In this case I think a lot of it comes down to threejs. I really prefer to use threejs over a lot of other programs because there is a lot of documentation, a lot of examples, but more importantly the data structures make sense, and there are a massive number of math tools which is more than can be said for something like blender.

The issue here is probably that IK in threejs was probably added for the MMD loader, and tailored to that particular use-case and probably flies out the window when it's not using the specific setup used for MMD. That means I'd probably have to implement a solver, which is not something I'm crazy about doing, Which means that as much as I hate working with blender, in this case it's probably going to be the better testing environment.
 
Last edited:
Okay, so debugging the animations has now taken a somewhat of an unexpected turn. The reason I wasn't too concerned about IK originally is because I figured that there would be some kind of standard human rig that the values could be plugged into in order to get something that resembles the output from the game. Since Threejs's CCD solver seems to work for a specific purpose, I sent an message to RichWhitehouse (author of Noesis) to ask for which environment is best to work with for IK, and got the following response.
You’d have to reverse engineer the game to really know how rotations are supposed to stack with their IK solver, and you probably should do that anyway just to replicate the solver math identically.

Beyond that, Noesis does have a couple solvers, but they aren’t exposed to plugin land. Just about every physics engine has some variety of IK solver too, even if that just means attaching rigid translation constraints to your joints. For a game as old as Shenmue, they probably wrote their own very simple solver which may have its own eccentricities that aren’t easily reproduced with a ready made solver.

In other words, cloning the solver from the game is probably going to produce the closest results. This has one bad implication and a few other good implications. First the bad implications means that I can't be lazy, and we'll have to replicate the IK solver with code. Even if the implementation for Shenmue is "simple", it's probably better stated as "relatively simple", in that if you have a decent grasp of IK and have a general understanding of how it works, then it shouldn't be too hard. In this case this is my first rodeo with IK, so we'll have to see how painful of an experience this is.

As for the possible good possibilities. First it means that we should be able to use the original skeleton and not have to mess with zeroing-out the rotation so that it works with the included CCD solver. The second good possibility is that it re-enforces my use of tool. A lot of times I'm somewhat embarrassed to be using Threejs which is a janmky-Javascript implementation for 3d graphics that runs in a browser. Not exactly the most professional tool. But the good news is that it's completely open source which means that if you need to jump in and edit the animation update cycle, you can change what you want and all of the changes to the source code are reflected when you refresh the page.

Basically the tools are already implemented in something that is flexible and allows for testing and editing for a custom solver. The last possible good news is that if we implement our own solver, then rather than trying to animate it directly, we have the possibility of solving every rotation for every bone, and then converting the animations to a standard FK animation, and be able to export and use that directly. But we'll have to see if we can implement the solver in the first place before we can entertain this possibility.

Which means now the issue is to reverse engineer the solver. And this is not exactly my area of specialty. What I do is generally look at a binary file, try to trace out the different structs, and then treat the game as a black box where I update values in memory and try to guess how the game is interpreting the values based on the result displayed on the screen. In this case this is actually diving in the game's programming to try and pull out the original code. The good news is that LemonHaze has already been looking in the code extensively.

Right now plan is to try and get an environment where I can look into the game using Ghidra. Right now I'm trying to get the game on steam, but am running into problems with region. I heard on the Dreamcase discord that Ghidra can also work with SH4, so I might try putting the original Dreamcase game into Ghidra. And I think there's also a debug environment for Reicast that allows you to set break points and step though code. Again I think 99% of the time I'll be working from LemonHaze's experience with this, and I'll adjust my debug environment to do what I can to follow along.

Edit:
Thanks to the Shenmue Dojo staff for helping me with a Shenmue 1&2 code for Steam.
 
Last edited:
This may not help directly, but I thought I'd mention it just in case.

A former Shenmue developer shared a couple of photos of internal documentation they used on the project. This one shows a character model with named parts, and another page shows some of the table of contents.

D2MGv8SUwAAs1ML.jpg

I was planning to translate the Japanese text in a blog post at some point, and could line it up sooner if it would be of any interest.
 
This helps a lot! This matches the number of bones and their names, which saves the time of having to track down each bone and figure out what it does. Also has the benefit of being able to use official names. Here's some of the text transcribed if it helps with translation. There's one character in the model label that's blurred and couldn't make out.

ランポリについて

モデルがモーションによって動く時に、このポリゴンがねじれます。これんみよって関節は繋がります。
計算は、パーツの断面から次の頂点の間にあるポリゴンがラムポリとなります。
ラムポリにならない部分は、そこから下のポリゴンということになります。
胸にはラムポリがありません。すべてのラムポリは胸の方向につきます。

各部の名称

Left Side

右(blurred)
右肩 migikata right_shoulder
右ひじ migihiji right_elbow
右腕 migiude right_arm
右手 migite right_hand
右親指 migioyayubi right_thumb
右人差し指1 migihitosashiyubi1 right_index_finger1
右人差し指2 migihitosashiyubi2 right_index_finger2
右人中指1 miginakayubi1 right_middle_finger1
右人中指2 miginakayubi2 right_middle_finger1
右足 migiashi right_foot
右つえ migitsue right_foot_bridge

Right Side

atama head
左(blurred)
mune chest
koshi hips
左尻 hidarishiri left_butt
左もも hidarimomo left_thigh
右尻 migishiri right_butt
右もも migimomo right_thigh
右ひざ migihiza right_knee
左ひざ hidarihiza left_knee
左足 hidariashi left_foot
左つえ hidaritsue left_foot_bridge
 
Good to hear it may be of use! Thanks for the transcription. The blurred kanji character looks to be 脇 waki which is the region of the armpit - perhaps something like "upper shoulder" might be appropriate.
 
Back
Top