Join also our Discord channel! Click here.

Perfect World Games for noesis

Post questions about game models here, or help out others!
jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Perfect World Games for noesis

Post by jayn23 » Tue Oct 29, 2019 10:53 pm

Since this thread has turned into a Perfect world games thread heres a summery of everything found in here:

1.Saint Seiya Online
Support for .ski, .bon, .stck, .mox, .bmd
skinned mesh + animation + static mesh

2.Perfect World
Support for .ski, .bon, .stck, .mox, .bmd
skinned mesh + animation + static mesh

3.Jade Dynasty
Support for .ski, .bon
skinned mesh

4.Forsaken World
Support .ski, .bon, .mox, .bmd (ski works with Perfect World script )

5.Swordsman Online
Support for .ski, .bon
skinned mesh

.........................................................................................................................
Hi,

In order to complete my basic noesis study i started working on a noesis script for .stck animation based of the following topic:
viewtopic.php?f=16&t=11776&hilit=animation#p98283

iv been working on this for the past few days - most of them trying to resolve an issue where my weights were being assigned to the wrong
bone id, had to ditch the .rapi and learn NoeMesh so i could manipulate the data - finally got it fixed. but now i am stuck with the animation part and have some issues i cant seem to resolve.

i tried following both shakotay2 and killercracker script. (also credit to zaramot - used his script to try and t/s my issues)
i am able to get the correct quat and translation vector but for some frames they are not equal, for example frame 8 has 93 translation vectors and 97 rotation quats, so what do i do with the missing translation? does it mean translation for quat is 0?

additionally what is "at time((i-1) * timeMult)"? is this a maxscript thing? or something that is relevant for my understanding of animations?
in shakotay2 script keyframe 200 was used didnt understand what that was for either?
also the line marked in black box - i understand changing numFrames, but what is rotFrames?

thanks in advance
for xentax1.png
my current noesis script (animation not working)

Code: Select all

from os.path import *
from math import *
from inc_noesis import *


def ReadStringKnown(f, size): # read string of known size
    String = []
    k = 0
    for i in range(size): 
        num = int(f.readUByte()) # bug reading 31 as ASCII 0 end existing
        if (num > 64 and num < 91) or(num > 45 and num < 58) or (num > 96 and num < 123) or num == 95 : #num == 95 add _ charecter
            if k == 0:
                k += 1
                Name = chr(num)
            else:
                Name = Name + chr(num)
    return Name



def registerNoesisTypes():
    handle = noesis.register("Perefect World Mesh", ".ski;.bon;.stck")    
    noesis.setHandlerTypeCheck(handle, noepyCheckType)
    noesis.setHandlerLoadModel(handle, noepyLoadModel)
    #opens debug consle
    noesis.logPopup()
    return 1


def noepyCheckType(data):
    '''Verify that the format is supported by this plugin. Default yes'''
    #I preform my check while reading mesh data
    return 1


#load skeleton data
def Skeleton(data):
    bones = []
    
    g = NoeBitStream(data, NOE_LITTLEENDIAN)
    g.seek(16,1)
    BoneCount = g.readUInt()
    g.seek(80,1)
    ####
    for i in range(BoneCount):#BoneCount
        boneNameLength = g.readUInt()
        boneName = ReadStringKnown(g, boneNameLength)
        boneID = g.readUInt()
        parentID = g.readInt()
        siblingID = g.readUInt()
        unkcount = g.readUInt()
        tfm2 = NoeMat44.fromBytes( g.readBytes(0x40), NOE_LITTLEENDIAN )
        tfm = NoeMat44.fromBytes( g.readBytes(0x40), NOE_LITTLEENDIAN )
        #boneMat = tfm.toMat43()
        boneMat = tfm.toMat43().inverse()
        #print("boneMat =", boneMat)

        for j in range(unkcount):
            g.seek(4,1)

        bones.append( NoeBone(i, boneName, boneMat, None, parentID) )

    return bones

def animation (data, bones): #def animation (data, bones):
    s = 0
    BoneMat = []
    Rotation_Arr = []
    translation_arr = []
    anims = []
    animFrameMats = []
    animName = "test"
    animFrameRate = 30

    f = NoeBitStream(data, NOE_LITTLEENDIAN)
    Magic = ReadStringKnown(f, 8)
    print("anim magic")
    print(Magic)
    unk = f.readUInt()
    boneCount = f.readUInt()
    f.seek(20,0)
    numFrames = f.readUInt()
    ukw = f.readUInt()

    for i in range (boneCount):
        
        boneID = f.readUInt()
        TransCount = f.readUInt() # number of translation vectors
        f.seek(8,1)

        for k in range(TransCount):
            #Tran = NoeVec3.fromBytes(f.readBytes(12))
            x = (f.readFloat())
            y = (f.readFloat())
            z = (f.readFloat())
            translation_arr.append((x,y,z))

        f.seek(16,1)

        RotCount = f.readUInt() # number of quats
        f.seek(8,1)
        print("TransCount=",TransCount)
        print("RotCount=",RotCount)
        
        for j in range(RotCount):
            x = f.readFloat()
            y = f.readFloat()
            z = f.readFloat()
            w = f.readFloat()
            Rot = NoeQuat((x,y,z,w))
            print("quat - original", Rot)
            #Rot = Rot.normalize()
            #Rotation_Arr.append((x,y,z,w)) #quat(x,y,z,w)
            frameMat = Rot.toMat43(transposed = 1)
            frameMat = frameMat.inverse()
            print("matrix_inverse =",frameMat)           
            #uat = frameMat.toQuat()
            #rint("quat", quat)
            frameMat[3] = translation_arr[s]
            #if TransCount >= RotCount:
            #if   s += 1
            #print(frameMat)
            animFrameMats.append(frameMat)
            
        
        f.seek(16,1)
        #a = f.tell()
    
    #bones must be a list of NoeBone objects, frameMats must be a flat list of NoeMat43 object
    if numFrames < TransCount:
        numFrames = TransCount
    print(numFrames)
    print(len(animFrameMats))
    anim = NoeAnim(animName, bones, 80, animFrameMats, animFrameRate) #numFrames
    anims.append(anim)

    return anims
    
#load mesh data
def Mesh(data, bones):
    
    ctx = rapi.rpgCreateContext()
    bs = NoeBitStream(data, NOE_LITTLEENDIAN)
   
    Magic = noeStrFromBytes(bs.readBytes(8), "ASCII")
    print(Magic)
    if Magic != "MOXBIKSA":
        print("worng file format")
    
    unk2 = bs.readInt()
    meshCount = bs.readInt()

    bs.seek(12,1)  
    
    textureCount = bs.readInt()
    materialCount = bs.readInt()
    mesh_boneCount = bs.readInt()
    null = bs.readInt()
    ukw4 = bs.readInt()
    
    bs.seek(60,1)
    
    boneName_Arr = []
    texName_Arr = []
    
    for l in range(len(bones)):
        print(l)
        print(bones[l].name)
    
    for i in range(mesh_boneCount):
        count = bs.readInt()
        boneName_Arr.append(ReadStringKnown(bs, count)) 

    for i in range(textureCount):
        count = bs.readInt()
        texName_Arr.append(ReadStringKnown(bs, count)) 

    for i in range(materialCount):
        bs.seek(80,1)
    
    for i in range(meshCount):
        nameLength = bs.readInt()
        meshName = ReadStringKnown(bs, nameLength)
    
        matID = bs.readInt()
        ukw2 = bs.readInt()
        vertCount = bs.readInt()
        faceCount = bs.readInt()
    
        Positions = []
        PolygonIndex = []
        Normals = []
        UV =[]
        weightList = []
        meshes = []
    
        for j in range(vertCount): # vert position
            bonesid = []
            weights = []
            vx = bs.readFloat()
            vy = bs.readFloat()
            vz = bs.readFloat()       
            Positions.append(NoeVec3([vx,vy,vz]))
              
            
            weight1 = bs.readFloat() 
            weight2 = bs.readFloat() 
            weight3 = bs.readFloat()
            weight4 = 0.0
                       

            for i in range(4):
                bone = bs.readUByte()
                if bone <= len(boneName_Arr):
                    name = boneName_Arr[bone]
                    for l in range(len(bones)):
                        if bones[l].name == name:
                            index = bones[l].index
                            break
                else:
                    index = 300
                if i == 0:
                   
                   bone1 = index
                if i == 1:
                   bone2 = index
                if i == 2:
                   bone3 = index
                if i == 3:
                   bone4 = index                                     

            
            if weight1 != 0:
                bonesid.append(bone1)
                weights.append(weight1)
            if weight2 != 0:
                bonesid.append(bone2)
                weights.append(weight2)
            if weight3 != 0:
                bonesid.append(bone3)
                weights.append(weight3)
            if weight4 != 0:
                bonesid.append(bone4)
                weights.append(weight4)
            
            weightList.append(NoeVertWeight(bonesid,weights))
            
            #print(j)
            #print(vx,vy,vz)
            #print(bonesid)
            #print(weights)
            
            
            nx = bs.readFloat()
            ny = bs.readFloat()
            nz = bs.readFloat()      
            Normals.append(NoeVec3([nx,ny,nz])) 
            
            tu = bs.readFloat()
            tv = bs.readFloat() * -1
            UV.append(NoeVec3([tu,tv,0.0])) 
            
        for j in range(0, int(faceCount)): # faces / triangles
            PolygonIndex.append(bs.readUShort())

    mesh = NoeMesh(PolygonIndex, Positions, meshName)
    mesh.setWeights(weightList)
    mesh.setNormals(Normals)
    mesh.setUVs(UV)
    meshes.append(mesh)
    
    return meshes
   
def noepyLoadModel(data, mdlList):
        ctx = rapi.rpgCreateContext()
               
        skel_data = rapi.loadPairedFile("skel_file- 1", ".bon")
        mesh_data = rapi.loadPairedFile("mesh_file- 2", ".ski")
        try:
            anim_data = rapi.loadPairedFile("anim_file - 3", ".stck")
        except:
            pass
        
        bones = Skeleton(skel_data) # get skeleton data
        anims = animation(anim_data, bones)    
        #print(anims)
        #print(anims[0].bones)
        #print(anims[0].name)
        #print(anims[0].numFrames)
        #print(anims[0].frameMats)
        #print(len((anims[0].frameMats)))
        
        meshes = Mesh(mesh_data, bones) # need to edit bone id index
        
        mdl = NoeModel(meshes)
        mdl.setBones(bones)           
        mdl.setAnims(anims) 
        
        mdlList.append(mdl)
        rapi.rpgClearBufferBinds()
        
        return 1                     
You do not have the required permissions to view the files attached to this post.
Last edited by jayn23 on Sat May 09, 2020 9:39 pm, edited 7 times in total.

User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 3143
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 843 times
Been thanked: 1711 times

Re: Perfect world animation .stck for noesis

Post by shakotay2 » Wed Oct 30, 2019 10:22 am

jayn23 wrote:
Tue Oct 29, 2019 10:53 pm
Hi,

In order to complete my basic noesis study i started working on a noesis script for .stck animation
Hi,
that's great! :)
i am able to get the correct quat and translation vector but for some frames they are not equal, for example frame 8 has 93 translation vectors and 97 rotation quats, so what do i do with the missing translation?
Afair (from my understanding) max interpolates the missing frames but I may be wrong.
additionally what is "at time((i-1) * timeMult)"? is this a maxscript thing? or something that is relevant for my understanding of animations?
"time" refers to the timeline for the animation (frames, translation/rotation).
timeMult = 2.0, just a variable killercracker introduced
in shakotay2 script keyframe 200 was used didnt understand what that was for either?
timeline thing again
btw: seems there's a bug in my script:

Code: Select all

    for fd=1 to Frame_cnt do
	    (
		    rot = RotationAnimation()
		    rot.BoneId = i
		    rot.KeyFrame = i*200-10
		    x = ReadFloat stream
		    y = ReadFloat stream
		    z = ReadFloat stream
		    w = ReadFloat stream
			
		    rot.Quaternion = quat x y z w
	
		    append allRotations rot
	    )
I'm pretty sure it should read
rot.KeyFrame = fd*200-10
but I can't check it because I don't have max installed any more. (Dependend on the (max) Frame_cnt "200" might be to big, better use 20 or such.)
Bigchillghost, Reverse Engineering a Game Model: viewtopic.php?f=29&t=17889
extracting simple models: viewtopic.php?f=29&t=10894
Make_H2O-ForzaHor3-jm9.zip
"You quoted the whole thing, what a mess."

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Wed Oct 30, 2019 10:48 pm

Thanks again for your help :)

sorry in advance for the lengthy post,

what i wrote here wasnt correct
i am able to get the correct quat and translation vector but for some frames they are not equal, for example frame 8 has 93 translation vectors and 97 rotation quats, so what do i do with the missing translation?
to be exact, for every bone there is a set of translation vectors and a set of rotation matrix, for bone 8 there were 93 translation vectors and 97 rotation quats, some also have 1 vs 97 or 97 to 31 etc..

what i am assuming based on max code is that every rotation and translation have a specific time calculated by ((i-1) * timeMult) so for say bone 8, i would take the translation and matrix at time 120, and if at time 190 i have only a rotation and no translation i would take the last translation (meaning it didnt move)
is this correct?
is there a way in 3dsmax i can see all of my animation matrix? so i can verify if my data is correct?

i also think i am not using the correct noesis function for this, i found in inc_noesis.py NoeKeyFramedAnim class, i am going to try with this one

One last question - just because i am curious :D
on the left code by killercracker i see he just applays the inverse quat and translation
on the right code by you, you first apply b.pos to the rotation matrix from quat then transform it, why not apply allTranslations.Position instead of b.pos ?
for xentax1.png
You do not have the required permissions to view the files attached to this post.

User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 3143
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 843 times
Been thanked: 1711 times

Re: Perfect world animation .stck for noesis

Post by shakotay2 » Thu Oct 31, 2019 1:44 pm

jayn23 wrote:
Wed Oct 30, 2019 10:48 pm
what i am assuming based on max code is that every rotation and translation have a specific time calculated by ((i-1) * timeMult) so for say bone 8, i would take the translation and matrix at time 120, and if at time 190 i have only a rotation and no translation i would take the last translation (meaning it didnt move)
is this correct?
sounds good :D (Can't confirm it, because I don't have max installed/used since years...)
is there a way in 3dsmax i can see all of my animation matrix? so i can verify if my data is correct?
depends on. In case you use a script, insert print commands.
In case you use an importer plugin (without source) I don't remember - didn't use max script API, if any.
(in blender you could use for example matrix=Blender.Mathutils.Matrix(bone.matrix['ARMATURESPACE']) for such)

One last question - just because i am curious :D
on the left code by killercracker i see he just applays the inverse quat and translation
on the right code by you, you first apply b.pos to the rotation matrix from quat then transform it, why not apply allTranslations[ i ].Position instead of b.pos ?
good question - that was my first max animation script (and most of the code was "borrowed" from TaylorMouse).
since my script didn't work correctly (while killerscracker's did) it's an academic question, isn't it?

Best way to get an answer, imho, is to try the different ways and print out the resulting matrixes - as you intended above.

btw: be carefull with [ i ], without the blanks the browser soft takes it as a command for the font (:
Bigchillghost, Reverse Engineering a Game Model: viewtopic.php?f=29&t=17889
extracting simple models: viewtopic.php?f=29&t=10894
Make_H2O-ForzaHor3-jm9.zip
"You quoted the whole thing, what a mess."

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Thu Oct 31, 2019 7:52 pm

depends on. In case you use a script, insert print commands.
In case you use an importer plugin (without source) I don't remember - didn't use max script API, if any.
(in blender you could use for example matrix=Blender.Mathutils.Matrix(bone.matrix['ARMATURESPACE']) for such)
to be honest before i started learning noesis i tried learning how to script with the blender API and after a week of trying i realized there are many tutorials but each works only for a specific version and not many worked for the 2.8 version...
btw: be carefull with [ i ], without the blanks the browser soft takes it as a command for the font (:
ill make sure i do :P

by the way i got it to work :)

ill post the code later today just want to clean it up a bit.
now my next ,mission is to start practicing analyzing 3d models, currently i can get verts,faces and uv most of the time but bones and animations iv never even really tried

Thanks again for the help

here is the code:
fmt_PerfectWorld.rar
You do not have the required permissions to view the files attached to this post.

KingJuls
beginner
Posts: 34
Joined: Wed Feb 28, 2018 8:29 am
Has thanked: 6 times

Re: Perfect world animation .stck for noesis

Post by KingJuls » Thu Nov 07, 2019 10:26 am

If I understand correctly now, can your Noesis Script load PW animations?

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Thu Nov 07, 2019 7:23 pm

Yes it can load animation - iv tested it only on models + animation samples that were provided in the original post, so i cant guarantee it will work for all versions ... i can only hope :)

KingJuls
beginner
Posts: 34
Joined: Wed Feb 28, 2018 8:29 am
Has thanked: 6 times

Re: Perfect world animation .stck for noesis

Post by KingJuls » Fri Nov 08, 2019 7:57 am

Okay no problem i will check :)
Maybe u can create a script for .bon Animation because many clients use this "old" animation data.

User avatar
CriticalError
double-veteran
double-veteran
Posts: 671
Joined: Sun Jul 05, 2009 2:03 am
Has thanked: 95 times
Been thanked: 36 times

Re: Perfect world animation .stck for noesis

Post by CriticalError » Mon Nov 11, 2019 12:17 pm

many thanks for the great update, well maybe you can take a look into this files, use same format as pw, Saint Seiya Online, grateful if you can help, have a nice day.

https://www.mediafire.com/file/e2rv2eim ... es.7z/file

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Tue Nov 12, 2019 1:46 pm

well maybe you can take a look into this files, use same format as pw, Saint Seiya Online, grateful if you can help, have a nice day.
Hi,

I took a look at the mesh + skeleton files and the format was almost identical just needed to add one for loop, i also found a bug in my original script that would have prevented loading models made up of multiple meshes. (hope i didnt break anything else when fixing it [roll] )

Saint Seiya Online version supports only mesh and skeleton at the moment, hopefully ill get some time to look at the animation, using search i noticed its had a few members that are far more experienced than me work on it in the past, so i have my doubts that i can...
You do not have the required permissions to view the files attached to this post.

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Tue Nov 12, 2019 1:48 pm

This is the perfect world (original) script with bug fix

if i broke anything please let me know, didnt have time to do many tests
You do not have the required permissions to view the files attached to this post.

KingJuls
beginner
Posts: 34
Joined: Wed Feb 28, 2018 8:29 am
Has thanked: 6 times

Re: Perfect world animation .stck for noesis

Post by KingJuls » Tue Nov 12, 2019 2:12 pm

Verrry Nice - thanks! :3

Can u also find out how can import Objectfiles (.mox)?

User avatar
CriticalError
double-veteran
double-veteran
Posts: 671
Joined: Sun Jul 05, 2009 2:03 am
Has thanked: 95 times
Been thanked: 36 times

Re: Perfect world animation .stck for noesis

Post by CriticalError » Tue Nov 12, 2019 2:36 pm

jayn23 wrote:
Tue Nov 12, 2019 1:46 pm
well maybe you can take a look into this files, use same format as pw, Saint Seiya Online, grateful if you can help, have a nice day.
Hi,

I took a look at the mesh + skeleton files and the format was almost identical just needed to add one for loop, i also found a bug in my original script that would have prevented loading models made up of multiple meshes. (hope i didnt break anything else when fixing it [roll] )

Saint Seiya Online version supports only mesh and skeleton at the moment, hopefully ill get some time to look at the animation, using search i noticed its had a few members that are far more experienced than me work on it in the past, so i have my doubts that i can...
well to fast, thanks a lot for support, one thing, edit one line of the script like this:

handle = noesis.register("Perefect World Mesh", ".ski;.bon;.stck")

to

handle = noesis.register("Saint Seiya", ".ski")

so now how we disable bon and stck? because if load ski ask for bon and stck after load all nothing appear in noesis.

jayn23
veteran
Posts: 127
Joined: Sun Jul 17, 2011 9:30 pm
Has thanked: 32 times
Been thanked: 118 times

Re: Perfect world animation .stck for noesis

Post by jayn23 » Tue Nov 12, 2019 4:26 pm

handle = noesis.register("Perefect World Mesh", ".ski;.bon;.stck")

to

handle = noesis.register("Saint Seiya", ".ski")
my bad i forgot to change that :D
ill update the original post later today when i have time

It shouldn't be asking you for ,stk since i disabled it in Saint Seiya version.
I noticed that even after changing the handle it still tried to load the files using the perfect world script.
so you cant have both scripts in you plugin folder at the same time.

.bon file contains the skeleton so if you want skinned meshes i wouldn't disable it.
Can u also find out how can import Objectfiles (.mox)?
ill see what i can do..

User avatar
CriticalError
double-veteran
double-veteran
Posts: 671
Joined: Sun Jul 05, 2009 2:03 am
Has thanked: 95 times
Been thanked: 36 times

Re: Perfect world animation .stck for noesis

Post by CriticalError » Wed Nov 13, 2019 4:52 am

jayn23 wrote:
Tue Nov 12, 2019 4:26 pm
handle = noesis.register("Perefect World Mesh", ".ski;.bon;.stck")

to

handle = noesis.register("Saint Seiya", ".ski")
my bad i forgot to change that :D
ill update the original post later today when i have time

It shouldn't be asking you for ,stk since i disabled it in Saint Seiya version.
I noticed that even after changing the handle it still tried to load the files using the perfect world script.
so you cant have both scripts in you plugin folder at the same time.

.bon file contains the skeleton so if you want skinned meshes i wouldn't disable it.
understand but what I say before, I download a clean copy of noesis and only copy your script into plugin, check.

Image

Image

so now when I select ski to load it ask for .bon ok, after select a .bon it ask again to ski mesh 2, after select same mesh ski don't give error but noesis don't load nothing.

here is the test, and with all files same.

Image

Post Reply