Users browsing this thread: 5 Guest(s)
Renderware Delta Morph Mesh ripping and repacking
#1
Renderware is a graphics suite used by most companies around the 7th console Gen. Most notably GTA SA-VC, though that unfortunately does not use DMA delta morphs

The game in question is Shadow The Hedgehog, which uses Renderware version 3.7

In the event.one files, DFF and DMA pairs of the "cheek" files contain the facial mesh info for morphs. If RWanalyze is used, you can even see what the name for the morphs are
[Image: unknown.png]

For Sonic and co (bar Vector, he doesn't use morphs for the face), the mesh names are;
cheek_a 
cheek_i 
cheek_u 
cheek_la 
cheek_ni
For Gun Commander and the President;
head_a 
head_i 
head_u 
head_e 
head_o 
head_la 
head_ni

Unfortunately, the current DFF tools only rip the base "neutral" pose, and editing it while being unable to edit the other meshes causes issues

Here are the files: https://mega.nz/file/xuxwAY7K#fL5Th115nk...hvV3Iybhho

From my research and the RW SDK docs, it seems the DMAs simply are animation timers, while the morph PLG contains all the vertex info in the DFF
I'd be grateful for the help, and hope to see custom facial anims for cutscenes!
Reply
Thanked by:
#2
Hi, I'm also working on this issue (but only on another game Silent Hil Origins for ps2, I don't know the version of the engine). Here's what I was able to dig myself
The structure delta morph plg (0x122) is as follows (at least in my version of the engine, it seems like yours, even the constants are the same):
Code:
struct Base{
    uint32_t count;
    Record recs[count];
};
struct Record {
    uint32_t nameLength;
    char name[nameLength]; //name of delta
    uint32_t unknown; //constant 18
    uint32_t unknown; //constant 6, may be number components in data1
    uint32_t size;
    uint32_t count;
    char data0[size]; //may be contain data distribution to mesh, usually large and small numbers alternate
    float data1[count * 6]; //main data, may be vec3 normals deltas of count and after vec3 vertex deltas of count
    float data2[4]; //may be bounding sphere xyzr
};
In my game for example, i have mesh with 587 points (with 1310 indices for triangle strip). All delta morph data contains this
Code:
unknown unknown size    count   name
18      6       54      107     Travis_Eyes_Open
18      6       102     320     Travis_Oat
18      6       84      270     Travis_Cage
18      6       91      293     Travis_Wet
18      6       92      200     Travis_Bump
18      6       88      248     Travis_Size
18      6       104     235     Travis_Frown
18      6       140     239     Travis_Smile
18      6       68      131     Travis_Blink
18      6       38      78      Travis_RaiseRightEye
18      6       94      253     Travis_Fave
18      6       46      68      Travis_RaiseLeftEye
Example data0
Code:
Travis_Eyes_Open
7F 0A 93 01 82 01 84 04 81 18 86 24 83 11 84 01 87 06 81 17 83 02 81 08 82 43 81 03 93 01 82 01 83 02 81 04 81 0F 86 23 82 10 84 01 87 04 81 10 83 01 82 07 82 2F
Travis_RaiseRightEye
7F 04 81 05 9C 03 81 01 81 01 83 11 87 24 83 11 84 01 8F 09 82 0B 83 01 83 02 81 04 82 43 81 1C 81 55 81 01 81 59
Travis_RaiseLeftEye
7F 04 81 1E 83 5D 81 01 81 17 82 0F 81 4E 81 03 82 01 8C 02 81 02 86 02 81 01 81 01 83 0F 85 23 82 10 84 01 8D 0F 83 01 82 02 81 04 82 2F
First number always large (not always 7F)

data2 very close (in values) to mesh bounding sphere

It remains to decrypt data0 and well done
Reply
Thanked by:
#3
Xentax forums might be a good place to ask, they're pretty cluey about reverse engineering stuff.
Reply
Thanked by:
#4
I found solution, simple lossless compression, RLE
first bit flag (mask 0x80) if 1 then include indices else exclude, other bits data (mask 0x7F)
data1 contains deltas, vertices, normals, colors and uv by flags from first unknown number (18 is vertices and normals)
example
Code:
FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE 92

FE : 0xFE & 0x80 != 0 -> include, count: 0xFE & 0x7F = 0x7E = 126
92 : 0x92 & 0x80 != 0 -> include, count: 0x92 & 0x7F = 0x12 = 18
in result 126 + ... + 126 + 18 = 1908, include all indices from 0 to 1908
for my model eyes open and smile
   
Reply
Thanked by:
#5
Woah, glad to see someone looked at this thread
I wonder if there's a way to repack this for edits
Reply
Thanked by:
#6
(01-25-2022, 04:48 AM)Sonikku A Wrote: I wonder if there's a way to repack this for edits
My game uses this too and I have no idea how its store as animation, I can extract only static meshes for every state. Animation data store in dma
This video may be helpful
https://www.youtube.com/watch?v=6Cain-u9_g4
uses states exported from dff and use dma params and create animation
Reply
Thanked by:
#7
You have private messaging disabled. I can't respond to your message regarding discord
Reply
Thanked by:
#8
In recent news, ripping delta morphs, and ripping/editing DMAs are now possible with Psycrow's Blender plugin here: https://github.com/Psycrow101/Blender-3D-SH-Dma-plugin

There's one issue though: Custom morphs aren't possible yet, likely due to handling normals

DeadlyFugu's notes on Deltas:
```````````
struct DeltaMorphPLG {
// NOTE: for some absurd reason this struct is NOT aligned after each string, meaning most of the data is misaligned Sad
u32 targetCount;
struct {
u32 nameLength;
char name[nameLength]; // null terminated, name length includes null character
u32 flags = {2, 12}; // 0x10: has morphNormals
u32 unknown = {2, 6};
u32 mappingLength;
u32 morphVertexCount;

// mapping is a series of bytes each representing a run of vertices
// lowest 7 bits is length
// if highest bit is 1 then vertices start..length are included
// in morphVertices, else they are excluded
// 'start' is the end of the run
// e.g. 830281 means:
// 3 vertices 0,1,2 included (0x83)
// 2 vertices 3,4 excluded (0x02)
// 1 vertex 5 included (0x81)
// vertex 5 would have it's position delta stored in morphVertices[3]
u8 mapping[mappingLength];

// values added to each vertex
// mapping from morphVertex index to real vertex index given
// by above mapping array
struct {
float x, y, z;
} morphVertices[morphVertexCount];

if (flags & 0x10) {
struct {
float x, y, z;
} morphNormals[morphVertexCount];
}

// bounding sphere?
float x, y, z;
float radius;
} target[targetCount];
}
`````````````
Reply
Thanked by:


Forum Jump: