READ THE RULES: Click here

Follow us on Facebook: https://www.facebook.com/xentax/ :)

Diablo III .app

Post questions about game models here, or help out others!
Post Reply
anhhungmeo1234
beginner
Posts: 20
Joined: Sun Aug 15, 2010 9:48 am

Diablo III .app

Post by anhhungmeo1234 » Sun Sep 11, 2011 4:29 am

This is file in Diablo III, i think it's model. File simple:
http://www.mediafire.com/?5aacnbdea8mbneg

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Tue Sep 13, 2011 8:41 pm

Moving the .app research here from the game archive research forum.

I'll be updating this post as I make progress with the format.
Currently we have vertex, poly, normal, uv, tangent, bitangent and blendweight data mapped properly, there's still some stuff left to decipher.

Update #1: figured out what some of the unknown stuff is for, added hinge points
Update #2: finally found a good lead on the animation data, nothing to see yet, but I updated the script - maybe someone can work on it while I'm away
Update #3: animation stuff might have been a dead end, refactored the script a bit with new names
Update #4: some more refactoring of names as things get more clear

My current 010 editor template for parsing .app files is the following: (the text output in the editor is a wavefront object file that can be loaded into deep exploration for example)

Code: Select all

//--------------------------------------
//--- 010 Editor v3.2.1 Binary Template
//
// File: Diablo 3 appearance file template
// Author: BoyC
// Revision: v0.37
// Purpose: Analyzing 3D data in Diablo 3
//--------------------------------------

local unsigned int vxcnt=0;
local unsigned int LookCount=0;

struct ChunkData
{
    unsigned int Count<bgcolor=0xff00ff>;
    unsigned int Offset<format=hex,bgcolor=0xff00ff>;
    unsigned int Size<bgcolor=0xff00ff>;
};

struct ChunkHeader
{
    unsigned int h[4];
};

struct BONEDATA //size = 68
{
    unsigned int unk1[4];
    float unk2[3];
    unsigned int unk[3];
    float unk4[7];
};

struct BONE //size = 236
{
    char Name[64];
    int ParentID;
    float unk2[34]; //two matrices plus extra
    ChunkData UnkChunk;
    unsigned int unk[4];
    int unk3;
    Printf("# Bone: %s\n",Name);

    local int pos=FTell();
    FSeek(UnkChunk.Offset+16);
    
    if (UnkChunk.Offset)
    {
        struct 
        {
            BONEDATA bonedata[UnkChunk.Count]<optimize=false>;
        } bonedata<bgcolor=0x00f0a0,comment="Unknown purpose bone data">;        
    }

    FSeek(pos);
}; 

struct VERTEX //size = 44
{
    float x,y,z;
    unsigned char nx,ny,nz,nw;
    int unk3,unk4;
    unsigned short u,v;
    unsigned int unk1;
    char tx,ty,tz,tw;
    char bx,by,bz,bw;
    unsigned int unk2;

    //obj export part
    /**/
    local float ru=u,rv=v,rnx=nx,rny=ny,rnz=nz;
    ru=(ru-32767)/512.0f;
    rv=(rv-32767)/512.0f;
    rnx=(rnx-127)/127.0f;
    rny=(rny-127)/127.0f;
    rnz=(rnz-127)/127.0f;

    Printf("v %f %f %f\n",x,y,z);
    Printf("vt %f %f\n",ru,rv);    
    Printf("vn %f %f %f\n",rnx,rny,rnz);/**/
};

struct TRIINDICES
{
    unsigned short a,b,c;

    //obj export part
    Printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n",vxcnt+a+1,vxcnt+a+1,vxcnt+a+1,vxcnt+b+1,vxcnt+b+1,vxcnt+b+1,vxcnt+c+1,vxcnt+c+1,vxcnt+c+1);
}; //complete

struct BLENDWEIGHT
{
    int BoneID;
    float BoneWeight;
}; //complete

struct BLENDDATA //size = 24
{
    BLENDWEIGHT Weights[3]<optimize=false>;
}; //complete

struct LOOKDATA //size = 248
{
    unsigned int Five;
    int MinusOne;
    unsigned int DataOffset1<format=hex>;
    unsigned int DataSize1;
    unsigned int unk[3];
    float Matrix[16];
    unsigned int unk2[2];
    unsigned int DataOffset2<format=hex>;
    unsigned int DataSize2;
    unsigned int unk3[35];
};

struct SUBOBJECT //size = 140
{
    char Name[128];
    unsigned int Offset,Size,Zero;
    
    local int pos=FTell();
    FSeek(Offset+16);
    
    struct 
    {
        LOOKDATA lookdata[LookCount]<optimize=false>;
    } LookDataList<bgcolor=0x00a0f0,comment="Look Descriptors">;        

    FSeek(pos);
};

struct MESH //size = 372
{
    int unk1;
    ChunkData VertexChunk; //vertex size = 44
    ChunkData WeightChunk; //weight size = 24
    int Zero1;
    ChunkData IndexChunk; // 16bit index buffer for a triangle list
    ChunkData UnknownChunk; // points to an array of chunkdatas, could be anim
    int unk5[4];
    char SubObjectName[128];
    char MeshName[128];
    float funk1[6]; //bounding box? 
    unsigned int Zero2;
    unsigned int unk[4];

    Printf("# unk1: %4d vxcount: %4d\n",unk1,VertexChunk.Count);
    Printf("# mesh %s is part of subobject %s\n",MeshName,SubObjectName);

    local unsigned int Pos=FTell();

    if (VertexChunk.Offset)
    {
        FSeek(VertexChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            VERTEX vx[VertexChunk.Count]<optimize=false>;
        } Vertices;        
    }
    
    if (WeightChunk.Offset)
    {
        FSeek(WeightChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            BLENDDATA w[VertexChunk.Count]<optimize=false>;
        } BlendWeights;        
    }

    if (IndexChunk.Offset)
    {
        FSeek(IndexChunk.Offset);
        struct 
        {
            ChunkHeader ch;
            TRIINDICES w[IndexChunk.Count/3]<optimize=false>;
        } Triangles;        
    }

    FSeek(Pos);
    vxcnt+=VertexChunk.Count;
}; 

struct HARDPOINT //size = 96
{  
    char Name[64];
    int ParentBone;
    float qx,qy,qz,qw; //rotation as a quaternion
    float x,y,z; //position
};

struct COLLISIONOBJ //size = 104
{
    unsigned int x[26];
};

struct NAME
{
    char Name[64];
};

struct 
{
    unsigned int DEADBEEF[8];
    unsigned int Counter1;

    ChunkData BoneChunk; // size = 236
    
    FSeek(FTell()+30*4);

    ChunkData MeshChunk; // size = 372

    FSeek(FTell()+9*4);

    float FloatAray1[4]; //bounding sphere?

    ChunkData CollisionChunk; // size = 104

    FSeek(FTell()+3*4);

    ChunkData HPChunk; // size = 96

    FSeek(FTell()+5*4);

    float One;
    FSeek(FTell()+6*4);

    ChunkData UnkChunk1;

    FSeek(FTell()+4);

    ChunkData UnkChunk2;

    FSeek(FTell()+4);

    ChunkData UnkChunk3;

    FSeek(FTell()+8);

    float FloatArray2[6]; //bounding box?

    FSeek(FTell()+10*4);

    char xobject[256];
    char xobjectpath[256];
    char xmesh[256];
    char xmeshpath[256];

    FSeek(FTell()+4*4);

    unsigned int LookCnt;
    LookCount=LookCnt;

    ChunkData SubObjectChunk; // size = 140

    FSeek(FTell()+4);

    ChunkData LookNameChunk; // size = 64 count = Counter1

    FSeek(FTell()+18*4);

    //previously referenced data starts here, header size is 0x628h

    Printf("# Bone Count: %d\n",BoneChunk.Count);
    Printf("# Mesh Count: %d\n",MeshChunk.Count);
   

    if (BoneChunk.Offset)
    {
        FSeek(BoneChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            BONE bone[BoneChunk.Count]<optimize=false>;
        } Bones<bgcolor=0xa0a0a0,comment="Bone data">;
    }

    if (MeshChunk.Offset)
    {
        FSeek(MeshChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            MESH mesh[MeshChunk.Count]<optimize=false>;
        } Models<bgcolor=0xb0f0b0,comment="Model data">;        
    }

    if (SubObjectChunk.Offset)
    {
        FSeek(SubObjectChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            SUBOBJECT group[SubObjectChunk.Count]<optimize=false>;
        } SubObjects<bgcolor=0xc0c0f0,comment="SubObjects">;        
    }

    if (HPChunk.Offset)
    {
        FSeek(HPChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            HARDPOINT hardpoint[HPChunk.Count]<optimize=false>;
        } HardPoints<bgcolor=0xd0f0f0,comment="These are hardpoints where other models can be attached to this one">;        
    }

    if (CollisionChunk.Offset)
    {
        FSeek(CollisionChunk.Offset+16);
        struct 
        {
            //ChunkHeader ch;
            COLLISIONOBJ Collisions[CollisionChunk.Count]<optimize=false>;
        } CollisionObjects<bgcolor=0xf0e0f0,comment="Seems to be collision mesh data">;        
    }

    if (LookNameChunk.Offset)
    {
        FSeek(LookNameChunk.Offset+16);
        struct 
        {
            NAME Name[LookCount]<optimize=false>;
        } LookNames<bgcolor=0xf0a0a0,comment="Look Names">;                
    }


} HEADER<bgcolor=0xf0f000>;
Last edited by BoyC on Thu Sep 15, 2011 10:10 am, edited 4 times in total.

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Tue Sep 13, 2011 9:48 pm

This post is reserved for images of the best current results.

Image

Corbo
ultra-n00b
Posts: 1
Joined: Tue Sep 13, 2011 10:11 pm

Re: Diablo III .app

Post by Corbo » Tue Sep 13, 2011 10:15 pm

You're amazing!
I have no programming knowledge but I will help you in anyway I can, testing, ideas and such.

So far I've tested a few of the characters and they all seem to break, perhaps cause they are rigged? Static models seem to work out the best.
The leah model exports almost perfectly except for some normal issues.

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Tue Sep 13, 2011 11:16 pm

Well the characters don't actually break. I think the wizard_female.app and the rest of them are actually only the models prepared for the login screen with complete sets of armor. There are several meshes in each file and they are merged together with this method. Once we have all the pieces in place I'll do an exporter to a format that supports multiple models, that should fix this issue.
EDIT:
Same thing happens if you load critters for example - if you check out the wireframe, you can actually see the bone structure inside the animal ;)

npd2006
beginner
Posts: 35
Joined: Tue Sep 13, 2011 9:15 am
Been thanked: 1 time

Re: Diablo III .app

Post by npd2006 » Thu Sep 15, 2011 9:39 am

//--------------------------------------
//--- 010 Editor v3.2.1 Binary Template
//
// File: Diablo 3 appearance file template
// Author: BoyC
// Revision: v0.37
// Purpose: Analyzing 3D data in Diablo 3
//--------------------------------------
With the old version, I can extract the output to obj files, but with your current version (v0.37), I cannot. Is it a test version ??

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Thu Sep 15, 2011 10:10 am

Oh sorry the output stuff has been commented out for speedy testing. I've fixed it now but there won't be any difference in the output yet - these are progress updates on mapping the format.

litaotao
ultra-n00b
Posts: 1
Joined: Thu Sep 15, 2011 2:23 pm

Re: Diablo III .app

Post by litaotao » Thu Sep 15, 2011 2:42 pm

Can anyone put a tool for extract obj? :)

afrokid
n00b
Posts: 10
Joined: Mon Jul 11, 2011 10:20 am

Re: Diablo III .app

Post by afrokid » Fri Sep 16, 2011 1:20 pm

Edit: Nevermind, was using the wrong files.

MrRawr
beginner
Posts: 25
Joined: Tue Sep 13, 2011 6:37 pm

Re: Diablo III .app

Post by MrRawr » Fri Sep 16, 2011 5:08 pm

How goes your progress in this department man?

I'm a little stuck over in the .tex / .gam department so I thought I would poke around here :P

npd2006
beginner
Posts: 35
Joined: Tue Sep 13, 2011 9:15 am
Been thanked: 1 time

Re: Diablo III .app

Post by npd2006 » Sat Sep 17, 2011 5:59 pm

Your script worked very well BoyC. Most of mesh are extracted successfully. But when I imported it to Maya it still some trouble:
1. Mesh UV need to be flip Vertical.
2. When I extract the character, they are multiple mesh are in the single object that I was really hard to arrange them.

One more, mesh extracted have problem when import to 3DS max, they look melting. Though they are saved as .obj

MrRawr
beginner
Posts: 25
Joined: Tue Sep 13, 2011 6:37 pm

Re: Diablo III .app

Post by MrRawr » Mon Sep 19, 2011 6:41 pm

1. Mesh UV need to be flip Vertical.

I'm getting the same.... how do you flip vertical xD

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Mon Sep 19, 2011 7:10 pm

Replace the line "rv=(rv-32767)/512.0f;" with "rv=1-(rv-32767)/512.0f;"

npd2006
beginner
Posts: 35
Joined: Tue Sep 13, 2011 9:15 am
Been thanked: 1 time

Re: Diablo III .app

Post by npd2006 » Tue Sep 20, 2011 3:03 am

How about the multiple mesh in one file ?

BoyC
beginner
Posts: 34
Joined: Wed Jul 05, 2006 9:24 pm
Been thanked: 2 times

Re: Diablo III .app

Post by BoyC » Tue Sep 20, 2011 9:52 am

npd2006 wrote:How about the multiple mesh in one file ?
Still working on that but I'm swamped in real life stuff atm.

Post Reply