The rules have been updated, read them now: Rules!

Convert MDX/MDS from PS4 Themes to FBX

Post questions about game models here, or help out others!
Post Reply
User avatar
BlackCrow613
n00b
Posts: 10
Joined: Tue Feb 18, 2020 2:42 pm
Has thanked: 7 times

Convert MDX/MDS from PS4 Themes to FBX

Post by BlackCrow613 » Thu Apr 01, 2021 2:17 am

Hello
I need help with mdx files. Do not confuse with warcraft files.
They are ps4. Used in ps4 themes.
I tried everything. I used gmotool to extract it with noesis but it didn't work.
I tried to convert the file to mds (text format) but still can't convert the files to fbx.

mdx header is "XDM.00.1MSP" here is an example of a file.
Image

the header of the mds file is ".MDS 1.00"
Image
You do not have the required permissions to view the files attached to this post.
Last edited by BlackCrow613 on Thu Apr 01, 2021 2:53 pm, edited 1 time in total.
Changing Seasons.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Thu Apr 01, 2021 2:02 pm

only mesh and texture.
the texture should be in the same folder as the model

Code: Select all

from inc_noesis import *
import noesis
import rapi

def registerNoesisTypes():
    handle = noesis.register("mesh MDS", ".MDS")
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel)
    
    noesis.logPopup()
    return 1

NOEPY_HEADER = ".MDS"

def noepyCheckType(data):
    bs = NoeBitStream(data)
    if len(data) < 4:
        return 0
    if bs.readBytes(4).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
        return 0
    return 1
	
def noepyLoadModel(data, mdlList):
    m = CreateModel()
    
    mdl = NoeModel([],[],[])
    mdl.setMeshes(m.MeshList)
    mdl.setModelMaterials(NoeModelMaterials([], m.matList))
    mdlList.append(mdl)
    return 1

class CreateModel:
    def __init__(self):
        self.p = ParseFile()

        self.MeshList = []
        self.matList = []
        #function
        self.CreateMaterial()
        self.CreateMesh()

    def CreateMesh(self):
        for part in self.p.Parts:
            for msh in part.Meshes:
                mesh = NoeMesh([],[],msh.Name+"_"+part.Name, msh.SetMaterial)
                mesh.setIndices(msh.Indices)
                for array in part.Arrays:
                    if msh.SetArrays in array.Name:
                        mesh.setPositions(array.POSITION)
                        mesh.setNormals(array.NORMAL)
                    #Scale and Translate UVs
                        for mat in self.matList:
                            if msh.SetMaterial in mat.name:
                                for tx in self.p.Textures:
                                    if tx.FileName in mat.texName.split('\\')[-1]:
                                        for i in range(0,len(array.TEXCOORD)):
                                            array.TEXCOORD[i] += tx.UVTranslate
                                            array.TEXCOORD[i] *= tx.UVScale
                    #-end
                        mesh.setUVs(array.TEXCOORD)
                self.MeshList.append(mesh)

    def CreateMaterial(self):
        matName = ""
        TxName = ""
        
        for mat in self.p.Materials:
            matName = mat.Name
            for layer in mat.Layers:
                for tx in self.p.Textures:
                    if layer.SetTexture in tx.Name:
                        TxName = tx.FileName
                diffTex = ""
                if not not TxName:
                    basepath = rapi.getDirForFilePath(rapi.getInputName())
                    diffTex = basepath + TxName
                material = NoeMaterial(matName, diffTex)
                self.matList.append(material)

class ParseFile: 
    def __init__(self):
        dirPath = rapi.getDirForFilePath(rapi.getInputName())
        filename = rapi.getLocalFileName(rapi.getInputName())
        f =  open(dirPath + filename).read().splitlines()
        
        self.Parts = []
        self.Materials = []
        self.Textures = []
        
        for i in range(0,len(f)):
            if "Part" in f[i].split():
                arr = []
                bracket = 0
                for q in range(i,len(f)):
                    if "{" in f[q]:
                        bracket += 1
                    if "}" in f[q]:
                        bracket -= 1
                    if bracket==0:
                        break
                    else:
                        arr.append(f[q])
                self.Parts.append(Part(arr))
                
            if "Texture" in f[i].split():
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Textures.append(Texture(arr))
                
            if "Material" in f[i].split():
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Materials.append(Material(arr))

class Part:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Meshes = []
        self.Arrays = []
        #Parsing Part
        self.ParsePart(arr)
        
    def ParsePart(self,arr):
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "Mesh" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Meshes.append(Mesh(arr0))
            if "Arrays" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Arrays.append(Array(arr0))

class Mesh:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.SetMaterial = ""
        self.SetArrays = ""
        self.Indices = []
        #Parsing Mesh
        self.ParseMesh(arr)
        
    def ParseMesh(self,arr):
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "SetArrays" in split:
                self.SetArrays = arr[i].split('"')[1] 
            if "DrawArrays" in split:
                self.Indices = [int(x) for x in split[4:]]
            if "SetMaterial" in split:
                self.SetMaterial = arr[i].split('"')[1] 

class Array:
    def __init__(self,arr):
        self.Name = arr[0].split()[1].replace('"','')
        self.POSITION = []
        self.NORMAL = []
        self.TEXCOORD = []
        #Parsing Array
        self.ParseArray(arr)
        
    def ParseArray(self,arr):
        Header = arr[0].split()[2]
        for i in arr[1:]:
            split = i.split()
            if "POSITION" in Header:
                self.POSITION.append(NoeVec3([float(x) for x in split[:3]]))
            if "NORMAL" in Header:
                self.NORMAL.append(NoeVec3([float(x) for x in split[3:6]]))
            if "TEXCOORD" in Header:
                self.TEXCOORD.append(NoeVec3([float(x) for x in split[6:8]+[0]]))

class Material:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Layers = []
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "Layer" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Layers.append(Layer(arr0))

class Layer:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.SetTexture = ""
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "SetTexture" in split:
                self.SetTexture = arr[i].split('"')[1]

class Texture:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.FileName = ""
        self.UVTranslate = NoeVec3((0,0,0))
        self.UVScale = NoeVec3((1,1,0))
    
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "FileName" in split:
                self.FileName = arr[i].split('"')[1]
            if "UVTranslate" in split:
                self.UVTranslate = NoeVec3([float(x) for x in split[1:]+[0]])
            if "UVScale" in split:
                self.UVScale =  NoeVec3([float(x) for x in split[1:]+[0]])
You do not have the required permissions to view the files attached to this post.
Last edited by Durik256 on Fri Apr 09, 2021 12:23 pm, edited 1 time in total.

User avatar
BlackCrow613
n00b
Posts: 10
Joined: Tue Feb 18, 2020 2:42 pm
Has thanked: 7 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by BlackCrow613 » Thu Apr 01, 2021 2:25 pm

the model looks like this in a ps4 mdx file viewer:

Image

Image

has animation, the model scrolls up.

edit: here the DDS File: https://www.mediafire.com/file/wdrbssjk ... t.dds/file
Changing Seasons.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Fri Apr 02, 2021 12:49 am

bone problem
Image

Code: Select all

from inc_noesis import *
import noesis
import rapi

def registerNoesisTypes():
    handle = noesis.register("mesh MDS", ".MDS")
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel)
    
    noesis.logPopup()
    return 1

NOEPY_HEADER = ".MDS"

def noepyCheckType(data):
    bs = NoeBitStream(data)
    if len(data) < 4:
        return 0
    if bs.readBytes(4).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
        return 0
    return 1
	
def noepyLoadModel(data, mdlList):
    m = CreateModel()
    
    mdl = NoeModel([],[],[])
    mdl.setMeshes(m.MeshList)
    mdl.setBones(m.boneList)
    mdl.setModelMaterials(NoeModelMaterials([], m.matList))
    mdlList.append(mdl)
    return 1

class CreateModel:
    def __init__(self):
        self.p = ParseFile()

        self.boneList = []
        self.MeshList = []
        self.matList = []

        #function
        self.AddBlendBone()
        self.CreateBones()
        self.CreateMaterial()
        self.CreateMesh()
        
    def CreateMesh(self):
        for part in self.p.Parts:
            for msh in part.Meshes:
                mesh = NoeMesh([],[],msh.Name+"_"+part.Name, msh.SetMaterial)
                mesh.setIndices(msh.Indices)
                for array in part.Arrays:
                    if msh.SetArrays in array.Name:
                        mesh.setPositions(array.POSITION)
                        mesh.setNormals(array.NORMAL)
                    #Scale and Translate UVs
                        for mat in self.matList:
                            if msh.SetMaterial in mat.name:
                                for tx in self.p.Textures:
                                    if tx.FileName in mat.texName.split('\\')[-1]:
                                        for i in range(0,len(array.TEXCOORD)):
                                            array.TEXCOORD[i] += tx.UVTranslate
                                            array.TEXCOORD[i] *= tx.UVScale
                        for wght in array.WEIGHT:
                            print(wght)
                    #-end
                        mesh.setUVs(array.TEXCOORD)
                self.MeshList.append(mesh)
                
    def CreateMaterial(self):
        matName = ""
        TxName = ""
        
        for mat in self.p.Materials:
            matName = mat.Name
            for layer in mat.Layers:
                for tx in self.p.Textures:
                    if layer.SetTexture in tx.Name:
                        TxName = tx.FileName
                diffTex = ""
                if not not TxName:
                    basepath = rapi.getDirForFilePath(rapi.getInputName())
                    diffTex = basepath + TxName
                material = NoeMaterial(matName, diffTex)
                self.matList.append(material)
                
    def CreateBones(self): 
        for bone in self.p.Bones:
            boneName = bone.Name
            ParentBone = bone.ParentBone
            boneMat = bone.Mat43
            if len(bone.BlendBones) == 0:
                self.boneList.append(NoeBone(len(self.boneList),boneName,boneMat,ParentBone))
            
        for bone in self.boneList:
            pName = bone.parentName
            if pName not in "RootNode":
                for b in self.boneList:
                    if b.name in pName: 
                        bone.setMatrix(bone.getMatrix() + b.getMatrix())
                        
    def AddBlendBone(self):
        for bone in self.p.Bones:
             if len(bone.BlendBones)> 0:
                for blend in bone.BlendBones:
                    for b in self.p.Bones:
                        if blend.Name in b.Name:
                            b.Mat43 += blend.Mat43
                            
class ParseFile: 
    def __init__(self):
        dirPath = rapi.getDirForFilePath(rapi.getInputName())
        filename = rapi.getLocalFileName(rapi.getInputName())
        f =  open(dirPath + filename).read().splitlines()
        
        self.Parts = []
        self.Materials = []
        self.Textures = []
        self.Bones = []
        
        for i in range(0,len(f)):
            split = f[i].split()
            if "Part" in split:
                arr = []
                bracket = 0
                for q in range(i,len(f)):
                    if "{" in f[q]:
                        bracket += 1
                    if "}" in f[q]:
                        bracket -= 1
                    if bracket==0:
                        break
                    else:
                        arr.append(f[q])
                self.Parts.append(Part(arr))
                
            if "Texture" in split:
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Textures.append(Texture(arr))
                
            if "Material" in split:
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Materials.append(Material(arr))
            if "Bone" in split:
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Bones.append(Bone(arr))

class Part:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Meshes = []
        self.Arrays = []
        #Parsing Part
        self.ParsePart(arr)
        
    def ParsePart(self,arr):
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "Mesh" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Meshes.append(Mesh(arr0))
            if "Arrays" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Arrays.append(Array(arr0))

class Mesh:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.SetMaterial = ""
        self.SetArrays = ""
        self.Indices = []
        self.BlendIndices = []
        #Parsing Mesh
        self.ParseMesh(arr)
        
    def ParseMesh(self,arr):
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "SetArrays" in split:
                self.SetArrays = arr[i].split('"')[1] 
            if "DrawArrays" in split:
                self.Indices = [int(x) for x in split[4:]]
            if "SetMaterial" in split:
                self.SetMaterial = arr[i].split('"')[1] 
            if "BlendIndices" in split:
                self.BlendIndices = arr[i].split()[1:]

class Array:
    def __init__(self,arr):
        self.Name = arr[0].split()[1].replace('"','')
        self.POSITION = []
        self.NORMAL = []
        self.TEXCOORD = []
        self.WEIGHT = []
        self.INDICES = []
        #Parsing Array
        self.ParseArray(arr)
        
    def ParseArray(self,arr):
        Header = arr[0].split()[2]
        for i in arr[1:]:
            split = i.split()
            if "POSITION" in Header:
                self.POSITION.append(NoeVec3([round(float(x),4) for x in split[:3]]))
            if "NORMAL" in Header:
                self.NORMAL.append(NoeVec3([round(float(x),4) for x in split[3:6]]))
            if "TEXCOORD" in Header:
                self.TEXCOORD.append(NoeVec3([round(float(x),4) for x in split[6:8]+[0]]))
            if "WEIGHT" in Header:
                if len(split[8:])<9:
                    if "INDICES" in Header:
                        q = int(len(split[8:])/2)
                        self.WEIGHT.append(split[8:8+q])
                        self.INDICES.append(split[8+q:])
                    else:
                        self.WEIGHT.append(split[8:])
                else:
                    print(len(split[8:]))
class Material:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Layers = []
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "Layer" in split:
                arr0 = []
                for q in range(i,len(arr)):
                    if "}" in arr[q]:
                        break
                    else:
                        arr0.append(arr[q])
                self.Layers.append(Layer(arr0))

class Layer:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.SetTexture = ""
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "SetTexture" in split:
                self.SetTexture = arr[i].split('"')[1]

class Texture:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.FileName = ""
        self.UVTranslate = NoeVec3((0,0,0))
        self.UVScale = NoeVec3((1,1,0))
    
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "FileName" in split:
                self.FileName = arr[i].split('"')[1]
            if "UVTranslate" in split:
                self.UVTranslate = NoeVec3([round(float(x),4) for x in split[1:]+[0]])
            if "UVScale" in split:
                self.UVScale =  NoeVec3([round(float(x),4) for x in split[1:]+[0]])
                
class Bone:
    def __init__(self,arr):
        self.Name = ""
        self.ParentBone = ""
        self.Mat43 = NoeMat43()
        self.BlendBones = []
        #function
        self.ParseBone(arr)
        
    def ParseBone(self,arr):
        self.Name = arr[0].split('"')[1]
        Translate = NoeVec3((0,0,0))
        Rotate = NoeQuat((0,0,0,1))
        Scale = NoeVec3((1,1,1))
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "ParentBone" in split:
                self.ParentBone = arr[i].split('"')[1]
            if "Translate" in split:
                Translate = NoeVec3([round(float(x),4) for x in arr[i].split()[1:]])
            if "Rotate" in split:
                Rotate = NoeQuat([round(float(x),4) for x in arr[i].split()[1:]])
            if "Scale" in split:
                Scale = NoeVec3([round(float(x),4) for x in arr[i].split()[1:]])
            if "BlendBone" in split:
                self.BlendBones.append(BlendBone(arr[i:i+5]))
                
        mat = Rotate.toMat43(transposed = 1)
        mat[3] = Translate
        mat[0][0] = Scale[0]
        mat[1][1] = Scale[1]
        mat[2][2] = Scale[2]
        self.Mat43 = mat
                
class BlendBone:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Mat43 = NoeMat43()
        for i,line in enumerate(arr[1:]):
             split = [round(float(x), 4) for x in line.replace('\\','').split()]
             self.Mat43[i] = split[:3]
You do not have the required permissions to view the files attached to this post.
Last edited by Durik256 on Fri Apr 09, 2021 3:21 pm, edited 4 times in total.

User avatar
BlackCrow613
n00b
Posts: 10
Joined: Tue Feb 18, 2020 2:42 pm
Has thanked: 7 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by BlackCrow613 » Fri Apr 02, 2021 2:02 am

Good job!

but the animation is missing.

Here is an example of the animation (sorry for the bad quality):

https://drive.google.com/file/d/1SB2S3x ... sp=sharing
Changing Seasons.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Fri Apr 02, 2021 6:51 pm

you can share the tools you can use to convert mdx to mds. and more model files ...

User avatar
BlackCrow613
n00b
Posts: 10
Joined: Tue Feb 18, 2020 2:42 pm
Has thanked: 7 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by BlackCrow613 » Sat Apr 03, 2021 2:10 am

Done!
look at private messages
Changing Seasons.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Mon Apr 05, 2021 9:44 am

if parsing one model with one bone:
Image
but if there are a lot of bones, then something is wrong with them:
111.png
You do not have the required permissions to view the files attached to this post.

User avatar
BlackCrow613
n00b
Posts: 10
Joined: Tue Feb 18, 2020 2:42 pm
Has thanked: 7 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by BlackCrow613 » Mon Apr 05, 2021 12:16 pm

Can you share the plugin with me to see if I can do something?
Changing Seasons.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Tue Apr 06, 2021 9:32 pm

I don’t understand how to load bones.
source file:

Code: Select all

.MDS 1.00

Model "model-0" {
	Bone "RootNode" {
	}
	Bone "Bip001" {
		ParentBone "RootNode"
		Translate -0.001775 0.005369 0.354162
		Rotate 0.000000 0.000000 -0.707106 0.707107
		Scale 0.025400 0.025400 0.025400
	}
	Bone "Bip001 Footsteps" {
		ParentBone "Bip001"
		Translate 0.000000 0.000000 -13.943383
		Rotate 0.000000 0.000000 0.707106 0.707107
	}
	Bone "Bip001 Pelvis" {
		ParentBone "Bip001"
		Rotate -0.500000 -0.500000 -0.499999 0.500001
	}
	Bone "Bip001 Spine" {
		ParentBone "Bip001 Pelvis"
		Translate 1.444581 -0.005201 0.000002
		Rotate -0.000002 -0.000001 0.000398 1.000000
	}
	Bone "Bip001 L Thigh" {
		ParentBone "Bip001 Spine"
		Translate -1.444576 0.006348 1.256156
		Rotate 0.050377 0.998730 0.000001 -0.000000
	}
	Bone "Bip001 L Calf" {
		ParentBone "Bip001 L Thigh"
		Translate 6.280781 0.000000 0.000000
		Rotate 0.000000 -0.000000 -0.099833 0.995004
	}
	Bone "Bip001 L Foot" {
		ParentBone "Bip001 L Calf"
		Translate 6.280780 0.000000 0.000000
		Rotate -0.000000 0.000000 0.049979 0.998750
	}
	Bone "Bip001 L Toe0" {
		ParentBone "Bip001 L Foot"
		Translate 1.444579 1.859110 0.000000
		Rotate -0.000000 -0.000000 0.707107 0.707107
	}
	Bone "Bip001 L Toe0Nub" {
		ParentBone "Bip001 L Toe0"
		Translate 0.188423 -0.000000 0.000000
		Rotate 0.000000 0.000000 1.000000 -0.000000
		Scale -1.000000 -1.000000 -1.000000
	}
	Bone "Bip001 R Thigh" {
		ParentBone "Bip001 Spine"
		Translate -1.444576 0.006355 -1.256156
		Rotate 0.050377 0.998730 0.000001 -0.000000
	}
	Bone "Bip001 R Calf" {
		ParentBone "Bip001 R Thigh"
		Translate 6.280780 0.000000 0.000000
		Rotate 0.000000 -0.000000 -0.099833 0.995004
	}
	Bone "Bip001 R Foot" {
		ParentBone "Bip001 R Calf"
		Translate 6.280780 0.000000 0.000000
		Rotate -0.000000 0.000000 0.049979 0.998750
	}
	Bone "Bip001 R Toe0" {
		ParentBone "Bip001 R Foot"
		Translate 1.444579 1.859110 0.000000
		Rotate -0.000000 -0.000000 0.707107 0.707107
	}
	Bone "Bip001 R Toe0Nub" {
		ParentBone "Bip001 R Toe0"
		Translate 0.188423 0.000000 0.000000
		Rotate 0.000000 0.000000 -0.000000 1.000000
	}
	Bone "Bip001 Neck" {
		ParentBone "Bip001 Spine"
		Translate 6.532012 -0.000750 0.000000
		Rotate -0.000000 0.000000 0.000000 1.000000
	}
	Bone "Bip001 Head" {
		ParentBone "Bip001 Neck"
		Translate 0.942118 0.000000 -0.000000
		Rotate -0.000000 0.000000 -0.000399 1.000000
	}
	Bone "Bip001 HeadNub" {
		ParentBone "Bip001 Head"
		Translate 2.951967 0.000000 0.000000
		Rotate -0.000000 0.000000 0.000000 1.000000
	}
	Bone "Bip001 L Clavicle" {
		ParentBone "Bip001 Neck"
		Translate 0.000002 0.000748 0.628078
		Rotate 0.632981 -0.000253 0.774167 0.000307
	}
	Bone "Bip001 L UpperArm" {
		ParentBone "Bip001 L Clavicle"
		Translate 1.633003 0.000000 -0.000002
		Rotate 0.033530 0.592756 0.037063 0.803830
	}
	Bone "Bip001 L Forearm" {
		ParentBone "Bip001 L UpperArm"
		Translate 3.768469 0.000000 0.000000
		Rotate 0.000000 0.000000 -0.099833 0.995004
	}
	Bone "Bip001 L Hand" {
		ParentBone "Bip001 L Forearm"
		Translate 3.768469 -0.000000 0.000000
		Rotate -0.706825 -0.000000 0.000000 0.707388
	}
	Bone "Bip001 R Clavicle" {
		ParentBone "Bip001 Neck"
		Translate 0.000002 0.000752 -0.628078
		Rotate -0.632981 0.000251 0.774167 0.000309
	}
	Bone "Bip001 R UpperArm" {
		ParentBone "Bip001 R Clavicle"
		Translate 1.633003 0.000000 0.000002
		Rotate -0.033530 -0.592756 0.037063 0.803830
	}
	Bone "Bip001 R Forearm" {
		ParentBone "Bip001 R UpperArm"
		Translate 3.768467 0.000000 0.000000
		Rotate 0.000000 -0.000000 -0.099833 0.995004
	}
	Bone "Bip001 R Hand" {
		ParentBone "Bip001 R Forearm"
		Translate 3.768469 0.000000 -0.000000
		Rotate 0.706825 -0.000000 0.000000 0.707388
	}
}
script plugin py:

Code: Select all

from inc_noesis import *
import noesis
import rapi

def registerNoesisTypes():
   handle = noesis.register("test mds", ".MDS")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel)
   #noesis.logPopup()
   return 1

NOEPY_HEADER = ".MDS"

def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 4:
      return 0
   if bs.readBytes(4).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

def noepyLoadModel(data, mdlList):
    s = CreateSkl()
    
    mdl = NoeModel([],[],[])
    mdl.setBones(s.boneList)
    mdlList.append(mdl)
    return 1

class CreateSkl:
    def __init__(self):
        self.p = ParseFile()
        self.boneList = []
        #function
        self.CreateBones()
        
    def CreateBones(self): 
        for bone in self.p.Bones:
            boneName = bone.Name
            ParentBone = bone.ParentBone
            boneMat = bone.Mat43
            self.boneList.append(NoeBone(len(self.boneList),boneName,boneMat,ParentBone))
            
        for bone in self.boneList:
            pName = bone.parentName
            if pName not in "RootNode":
                for b in self.boneList:
                    if b.name in pName: 
                        bone.setMatrix(bone.getMatrix() + b.getMatrix())

class ParseFile:
    def __init__(self):
        dirPath = rapi.getDirForFilePath(rapi.getInputName())
        filename = rapi.getLocalFileName(rapi.getInputName())
        f =  open(dirPath + filename).read().splitlines()
        
        self.Bones = []

        for i in range(0,len(f)):
            if "Bone" in f[i].split():
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Bones.append(Bone(arr))
   
class Bone:
    def __init__(self,arr):
        self.Name = ""
        self.ParentBone = ""
        self.Mat43 = NoeMat43()
        #function
        self.ParseBone(arr)
        
    def ParseBone(self,arr):
        self.Name = arr[0].split('"')[1]
        Translate = NoeVec3((0,0,0))
        Rotate = NoeQuat((0,0,0,1))
        Scale = NoeVec3((1,1,1))
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "ParentBone" in split:
                self.ParentBone = arr[i].split('"')[1]
            if "Translate" in split:
                Translate = NoeVec3([float(x) for x in arr[i].replace('Translate','').split()])
            if "Rotate" in split:
                Rotate = NoeQuat([float(x) for x in arr[i].replace('Rotate','').split()])
            if "Scale" in split:
                Scale = NoeVec3([float(x) for x in arr[i].replace('Scale','').split()])
                
        mat = Rotate.toMat43(transposed = 1)
        mat[3] = Translate
        mat[0][0] = Scale[0]
        mat[1][1] = Scale[1]
        mat[2][2] = Scale[2]
        self.Mat43 = mat
xxx.png
You do not have the required permissions to view the files attached to this post.

User avatar
Durik256
beginner
Posts: 20
Joined: Wed Nov 21, 2018 7:26 pm
Been thanked: 9 times

Re: Convert MDX/MDS from PS4 Themes to FBX

Post by Durik256 » Fri Apr 09, 2021 6:53 pm

solved a problem:

Code: Select all

from inc_noesis import *
import noesis
import rapi

def registerNoesisTypes():
   handle = noesis.register("test mds", ".MDS")
   noesis.setHandlerTypeCheck(handle, noepyCheckType)
   noesis.setHandlerLoadModel(handle, noepyLoadModel)
   #noesis.logPopup()
   return 1

NOEPY_HEADER = ".MDS"

def noepyCheckType(data):
   bs = NoeBitStream(data)
   if len(data) < 4:
      return 0
   if bs.readBytes(4).decode("ASCII").rstrip("\0") != NOEPY_HEADER:
      return 0
   return 1       

def noepyLoadModel(data, mdlList):
    s = CreateSkl()
    
    mdl = NoeModel([],[],[])
    mdl.setBones(s.boneList)
    mdlList.append(mdl)
    return 1

class CreateSkl:
    def __init__(self):
        self.p = ParseFile()
        self.boneList = []
        #function
        self.CreateBones()
        
    def GetParentIndex (self,parentName, arr):
        for i,bone in enumerate(arr):
            if bone.Name == parentName:
                return i
        return -1 
    
    def CreateBones(self): 
        for bone in self.p.Bones:
            if len(bone.BlendBones) == 0:
                self.boneList.append(NoeBone(len(self.boneList),bone.Name,bone.Mat43,None,self.GetParentIndex(bone.ParentBone,self.p.Bones)))
        """
        for bone in self.p.Bones:
            for bl in bone.BlendBones:
                for nb in self.boneList:
                    if bl.Name in nb.name:
                        nb.setMatrix(  bl.Mat43*nb.getMatrix() )
        """
        for bone in self.boneList:
            pIndex = bone.parentIndex
            if pIndex != -1:
                bone.setMatrix(bone.getMatrix() * self.boneList[pIndex].getMatrix())
                

                        
class ParseFile:
    def __init__(self):
        dirPath = rapi.getDirForFilePath(rapi.getInputName())
        filename = rapi.getLocalFileName(rapi.getInputName())
        f =  open(dirPath + filename).read().splitlines()
        
        self.Bones = []

        for i in range(0,len(f)):
            if "Bone" in f[i].split():
                arr = []
                for q in range(i,len(f)):
                    if "}" in f[q]:
                        break
                    else:
                        arr.append(f[q])
                self.Bones.append(Bone(arr))
   
class Bone:
    def __init__(self,arr):
        self.Name = ""
        self.ParentBone = ""
        self.Mat43 = NoeMat43()
        self.BlendBones = []
        #function
        self.ParseBone(arr)
        
    def ParseBone(self,arr):
        self.Name = arr[0].split('"')[1]
        Translate = NoeVec3((0,0,0))
        Rotate = NoeQuat((0,0,0,0))
        Scale = NoeVec3((1,1,1))
        
        for i in range(0,len(arr)):
            split = arr[i].split()
            if "ParentBone" in split:
                self.ParentBone = arr[i].split('"')[1]
            if "Translate" in split:
                Translate = NoeVec3([float(x) for x in arr[i].replace('Translate','').split()])
            if "Rotate" in split:
                #Rotate = NoeQuat([float(x) for x in reversed(arr[i].replace('Rotate','').split())])
                Rotate = NoeQuat([float(x) for x in arr[i].replace('Rotate','').split()])
            if "Scale" in split:
                Scale = NoeVec3([float(x) for x in arr[i].replace('Scale','').split()])
            if "BlendBone" in split:
                self.BlendBones.append(BlendBone(arr[i:i+5]))
                
        mat = Rotate.toMat43()
        mat[3] = Translate
        #mat[0][0] = Scale[0]
        #mat[1][1] = Scale[1]
        #mat[2][2] = Scale[2]
        self.Mat43 = mat.transpose()
        
class BlendBone:
    def __init__(self,arr):
        self.Name = arr[0].split('"')[1]
        self.Mat43 = NoeMat43()
        
        for i,line in enumerate(arr[1:]):
             self.Mat43[i] = [float(x) for x in line.replace('\\','').split()[:3]]
3333.png
You do not have the required permissions to view the files attached to this post.

Post Reply