Ninja ASCII (.NJA) format conversion from .OBJ [Theory]

egg yolk

To actually work on implementation of bones, njaPatcher will require a large rewrite, this means separating the different functions such as loading OBJ and generating triangle strips into isolated JavaScript promises, as working with multiple OBJ will need random access to those functions and njaPatcher should also retain support for single OBJ export of NJA and NJ.

Fortunately the code for njaPatcher can be reused for the majority of this reimplementation and the new NJA with bones gives a good idea of how to break up the existing code (which I wasn't sure of earlier). It can be expected that the next major version of njaPatcher will aim to have some different functionality in support of loading multiple OBJ objects as a single NJA, but before it is in development, V0.21a will be pushed, to fix the OBJ smoothing group error.

The next major version will take a while to write, since there are some new elements to program for, and the focus will shift back to making NJA files until one can accurately be made with a bone structure.

To explain why bones are important, there are several PSOBB weapons that utilize bone positioning as projectile spawn points, or for spawning techs like Gifoie. For example, Baranz Launcher has a bone for each projectile that is shot, but also bones for the actual weapon model, on top of that, each bone has an ID. So 4 bones in Baranz Launcher have ID for a projectile start point function, the tricky part is figuring out which bone ID is associated with which action per weapon model, but there is a solution to this, which is stepping through a weapon with 1 bone, then 2 bones, then 3 etc. - It should also be noted that character models generally have around 64 bones, so it is not really that much to step through, most weapons seem to be around 4 - 10 bones.

It's simple with a weapon like Magical Piece, since it only has 4 bones. I believe 1 of them is where it's held, 2 of them are representing the shadeless/emitting parts of the model, and then a final one which displays where the particle system for Magical Piece spawns, not entirely sure how they are ordered though. Can see Magical Piece bone structure below:


Here is how Magical Piece's special attack functions with only a single bone; the Zonde still hits whatever is targeted, but the particles spawn at the map origin or (0, 0, 0). Certain weapons like Psycho Wand and Mercurius Rod with Foie techs, will spawn that Foie tech also at the map origin, generally Barta, Zonde and Anti all spawn on the character model, but this is likely to do with the bone structure per weapon described and how those tech call functions are associated with it. Below is an example of Magical Piece, and then Psycho Wand:



egg yolk

So I have implemented some new features into njaPatcher, which is mostly the re-write of code that I mentioned in the last post, but also some completely new ideas. Unfortunately my research with bone structures has turned into limbo. Before explaining why, I must remind anyone keeping up with this thread that this research is a lot of guess work and theory, even if I do now have systems that can accomplish the original aim of this thread. With this in mind, I will also say that the next version of njaPatcher is still a while away, and that the smoothing group error probably won't be fixed until then.

About bones (I will refer to them as nodes from now on), my thoughts about whether they could be used to control projectile spawn positions seems to be partially wrong. I still believe they are used as projectile spawn points, but I don't believe the function for that can be exported from njaconv.exe for example, it seems to be a proprietary export option for PSO development. To test if it worked from njaconv.exe, I reproduced the Handgun model from PSOPC using ExMLDNet's scan feature, which gives the exact positioning of nodes for an NJ loaded into it.

With those node positions I wrote an NJA file that chains the nodes in the exact same order as the original Handgun model, but the model still spawns projectiles at the wrong place. My guess is still that the property of projectile spawn position is validated in some way by the model file, since it changes per model, but just not sure how it's communicated from the model file to the game client. The Handgun model details can be seen below, compared to the original model.


I didn't check if node structure controls Foie tech spawn points yet, since I feel like that will also be inconclusive. Instead I have shifted my efforts into writing a parser for ExMLDNet's scan output, the purpose of this is to reverse engineer already existing PSO/NJ model files back into NJA, this way, existing node structures can be reproduced with custom models, which will allow better testing for stuff like swapping enemy models or character models (not saying it will work).

egg yolk

Today I managed to copy some node structures, like HUcast and Ill Gill. The process works by taking every node position from an ExMldNet scan of an NJ object from PSOBB, njaPatcher can parse these scans when it creates an NJA file, and can bind it with the loaded model, e.g, cube. All models stay within the domain of the old model node structure. This kind of appearance is how models are loaded for NJ with nodes, a skeleton structure is created, and it draws model data (3D objects) at important points of the skeleton, e.g, head, legs, arms.

Not every node structure builds correctly so far, Dragon for example seems to have too high of a node count, or is formatted in a way that the scan parser reads it wrong.


egg yolk

Today I started writing a rigging system for player models, unfortunately certain chars will require unique rigging systems since each char has a different node structure. For instance, FOmarl's arm, uses a different node ID to HUcasts arm. The same thing goes for any enemies in the game, they will require unique rigs to mod.

The rigging system currently implemented supports HUcast for now, still unsure if other models like RAcast use roughly the same rig. The rig works by assigning a model to each part of the player model. It looks something like this in code:

rig.leftHand = "left_hand.obj"
rig.leftElbow = "left_elbow.obj"

While this works there are some issues with 'up' and 'forward' facing direction for models, since each model in a node structure has a different 'up' and 'forward' direction. Can be seen in the image below, where blue represents the 'up' facing direction, green represents the 'forward' facing direction, and red represents the 'right' facing direction of each model (cube). The labelled numbers are also in the order of models that are loaded for HUcast:


It may be possible to hardcode facing direction by reading how each model is rotated through the node structure, and then winding back the rotation so it's as if the object was never rotated. The real problem with facing direction is that it's even awkward to configure in Blender, when each part of an object has to be rotated to a specific angle before exporting, it can be quite confusing and hard to keep track of what you're doing.

It is possible to get a neat outcome though if you follow the structure properly - this is a model that I have started working on to build the armature system today. I'm not saying it's a good model, but it can be seen how the armature system is modified:

Last edited:

egg yolk

HUcast rig is mostly complete and will be available for the next release, to finish it up I spent the day figuring out how to make all nodes have the same orientation. In the previous post, the orientation/face direction problem was described, and I have now solved it for HUcast at least, as solving this is not an autonomous implementation. It's unique for each character and enemy as it's part of the rigging object. The difference between the image below and the one in the previous post, is the facing direction of each node:

Having solved this, it should now be possible to box model a complete character in Blender with reference to a character rig, and when the model is finished in Blender, each part that is a node just needs to be separated into it's own object with a defined origin. Being able to box model the whole character is what this new implementation allows, since previously you would have to mess with facing direction per node on export, which is a lot of extra work! To explain better how this works, each node object still needs to be exported from Blender as a separate OBJ, but it doesn't need to be modified in terms of it's orientation or location. I will make a video on how to use njaPatcher's rigging tools at another time.

I will still need to test this with some different 3D models before I confirm everything works, but it seems good so far, one thing I have noticed is that certain parts of the player model allow less memory than others, e.g., complex models on certain nodes (HUcast shoulder shield thing) will cause PSOBB to crash as the model loads and sometimes it will just load extremely warped (reducing vert count fixes this). Something cool that I've found is that section ID badge also seems to be it's own model, which is a pretty neat custom object since it's texture is based on section ID.

egg yolk

There is a new version of njaPatcher up with the previously mentioned node structures implemented. There are some bug regressions with this version of njaPatcher, mostly relating to making NJA files without textures, but it is nothing major.

This version only converts node structures to NJA at the moment, although with this version released I have started to study how node structures are implemented into NJ files. So far it has been a quite difficult to figure out, this is due to the amount of different outcomes that require testing for node structures, since there can be more than one model in the node structure version of NJ and also nodes that don't use model data. This means that the new NJ conversion should be able to detect abstract model sizes and adjust variables accordingly, fortunately what I had learned making the single OBJ to NJ converter has helped me out a lot so far, and I actually think I have figured out the hardest part of node based NJ today. I believe what I figured out today was sibling pointers, although I can't say for sure, at least it is the same as njaconv.exe output anyway...

Node structure to NJ will take a long time to finish, since it seems vastly more confusing than anything else I've programmed so far, but I do believe I can do it if I take my time and write stuff down.

I am planning to make a video pretty soon, to go over the current version of njaPatcher, but if I don't make a video the next post will probably be when I have finished node based NJ or have hit a roadblock with it.


Seems like there's a geometry issue with a specific vertex, does it open correctly in Noesis?

EDIT: Just read description, it were a direction test :)
Last edited: