jmquigs / ModelMod

A system for modifying art in games.
GNU Lesser General Public License v2.1
80 stars 11 forks source link

Porting the IO scripts to the 3.0+ Blender API #35

Open Frosferes2 opened 1 year ago

Frosferes2 commented 1 year ago

I've taken an interest in this project again since I've been considering getting back into GW2 recently. I'm in the process of porting the IO scripts to the 3.0+ API so that they're usable in modern versions of Blender.

Most of the API changes I've encountered so far have been minor syntax or function changes, but there is a more difficult problem in that the 2.8+ API cannot access Blender's internal rendering engine. This completely breaks any mmobj functionality related to materials.

I wanted to ask, what exactly are the differences between the stock obj IO and mmobj? If I knew the specific differences it would probably be easier to copy the majority of the code (specifically the material handling classes) over from the current obj scripts and tweak them for mmobj.

jmquigs commented 1 year ago

Its been a long time since I worked on that stuff so I don't remember all the specific differences. I do recall not really doing much with materials though, so it may not matter than blender doesn't support that. Texture overrides for instance are specified in the .yaml file for the mod, not in the blender material.

Every "extension" to obj was implemented as commented out line, like "#vbld" and such. Although in the default "ref" weighting mode, that was mostly required for the ref snapshot, not exported from blender. This was because at runtime the code uses a nearest vert algorithm to copy that information back from the ref's snapshot. Another thing that was important was the named vertex groups which are used to transform the mod back into the game's space and also implement inclusion/exclusion groups.

There was a late change I made to how blender exports verts, MM requires a specific order so that the game's animations still work. Default obj scripts were doing a "cleanup" operation on that which broke the order, which I had to disable because it also broke animation.

I do recall commenting things as I went so if you go back and look at the history on those python files, it might be helpful.

Thanks for considering to look at this, I strongly dislike just working in python generally so I hardly touch that code. Really wish blender didn't break that API all the time, maybe they have stopped in recent versions. I should advise you at this time I have not yet finished the DX11 port for gw2 (snapshotting in particular isn't fully working) but I don't recall there being any changes required to mmobj so far for it.

Frosferes2 commented 1 year ago

Most of this project is much too advanced for me to know where to start, but I've gotten some Python experience since the last time I looked here as a result of my studies and Blender tinkering. I've been hopeful that development would continue on this since I'm not aware of another project like it, hence why I want to help with the Python stuff. I know FF14 has some mod that allows custom client-side asset injection, but I'm not sure exactly how it works and it's not built for anything other than that game. Being able to do this for any DX multiplayer game and especially MMOs has a lot of appeal to me.

Were the mmobj scripts based on the 2.58.0 version of the obj scripts, as implied in the init script? I am comparing them to the 2.79 obj scripts and am seeing a lot of random differences. I can't be sure which of these were your edits or as a result of the obj scripts being altered over time. If I can isolate your changes then I can implement them into the modern obj scripts. If materials are not a concern then I will copy those classes wholesale.

Whilst I'm here, I could see if I can find out where tangent spaces are handled in the obj, since this seemed to be an issue with the exported mmobj models.

Also out of curiosity, can I ask why you elected to use obj instead of fbx for the basis of MM? I ask since fbx has more easilly accessible vertex weight and has skeleton support.

jmquigs commented 1 year ago

There's probably no other project like this because its kind of insane. It does work for some games but there are some (and probably many more recent games which use advanced mesh-splicing techniques for optimal performance) where it could never work. For MMOs I never tried to make it work for anything other than GW1 and 2. Once DX11 is finished (its mostly done now but the snapshotting needs some tweeks) ports for games that use that could be attempted, but I have limited motivation to work on those (indeed I haven't even finished dx11 yet)

Re obj scripts, unfortunately I don't recall what version I based the scripts on. Definitely any changes I made would have been specific to what MM wants, I didn't go refactoring or anything. I don't care about obj materials, so any changes they made related to that can be disregarded for MM's purposes.

I'm still not quite sure what is going on with the tangents/lighting. For DX11 I experimented with the DirectX mesh library's ability to generate binormals and bitangents from normals. But the lighting in GW2 didn't seem much improved and in some cases was worse (possibly a result of the mesh not being very clean in the first place). Its possible that there is some normalization or vector-component/compression issue with these vectors that I haven't figured out.

I used OBJ instead of anything else because its a really simple format, and since it needs to be produced by the snapshotter i was trying to minimize how much code would be needed there (its also faster I think to write out sequential text files than a tree-structured format). Besides MM doesn't really work with anything resembling traditional animation data, there are no skeletons, bone transforms, etc. So FBX or another format would be overkill and probably not provide much value.

Frosferes2 commented 1 year ago

I went through the obj addon commit history on the Blender repo and found an iteration which was suitable to compare against. I used this comparison as a guide to figure out what you edited and incorporated these changes into the most recent version of the obj addon. I will note that this Python version of the obj IO is now listed as deprecated and likely won't be updated again since Blender is migrating to an internal C++ obj IO for improved performance.

You mention in import_mmobj.py the hacky way that the transformation data for the object and UV is stored as a vertex group name. It is possible to append arbitrary variables like strings to the data of a Blender object using custom properties. I have altered the import protocol so that it does this instead of using the vertex group list. I assume that I will have to append this data back on to the exported mmobj?

I am in the process of testing the new scripts and so far they appear to be working as intended. I'm not yet sure if this will fix the normal space issue, but I will get to that once I do a test in-game. Also, when I export an mmobj and re-import it, your mesh split vertex count mismatch exception is triggering: Exception: split changed vertex count and thus blend weights are invalid: retry with mesh split options disabled (orig vert count: 1972, new count: 1980). I'm not entirely sure why since I have not edited the mesh at all and I assume it is already UV ripped. I'm sure I will figure it out tomorrow or so, but I thought I'd post it here in case you'd seen anything similar before.

I wonder what the theoretical limits are with MM's technique. I assume it can't extract or modify animation data like skeletons or the animations themselves, right? What about vfx or sfx? Also I'm curious why the mesh splicing you mentioned would prevent MM from working.