Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map import collisions #316

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

jgooderham
Copy link
Contributor

@jgooderham jgooderham commented Jun 21, 2024

Hi there. I'm looking to add collisions to the map importer here. As well as a convenient way to mass export back to their container files. The map collisions are stored in a series of col files inside gta3.img but I just look for them in the dff extract folder. I think the commit comments explain it well enough but here are a few screen shots. Anyway I'm still new to collaboration on git so I just wanted to start a discussion on this while I worked on it.
Here's the shortcut to export all collisions back to their container.
Screenshot_1
And here's a map piece with its collision sitting on top of it (and z-fighting). The collisions are hidden on import, but you can edit them in-place this way.Screenshot_2
I'd also like to re-arrange each map section to a top-level collection named for the ipl file from which it came. That will organize the scene better. What do you think?

@jgooderham jgooderham mentioned this pull request Jun 23, 2024
@jgooderham
Copy link
Contributor Author

jgooderham commented Jun 23, 2024

Images which illustrate the fixes in the prior commit:
disregard_shadow
proper_center

Copy link
Owner

@Parik27 Parik27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for the contribution. This looks nice, I have a few comments that you can go through before merging.

ops/map_importer.py Outdated Show resolved Hide resolved
ops/map_importer.py Outdated Show resolved Hide resolved
ops/col_importer.py Outdated Show resolved Hide resolved
This first imports all collisions which share the current map section prefix, using the same folder where dff files are expected. Subsequent imports with the same section prefix will ignore already loaded collisions. All collisions are placed within a collection named for the .col file from which they came, and these collections are set to hidden so as not to obscure the map geometry. Then when importing the map geometry, each collision file is instanced, transformed, and linked to the collection of the map instance, and initially set to hidden again so as to not obscure the map geometry. This change enables easy in-place editing of an instance's collision geometry.
This adds a menu item and some minor implementation logic to allow exporting a collection from the Outliner as a collision container (.col) file. This change complements the map collision support as it allows changes to a .col file to be exported with the original neighboring collisions in the same container. Right-click on a collection (ie. lae2_1.col) in the Outliner to export its collisions in one file which could then be used to replace the original collision container in a mod.
This just makes the collision loading a little less unresponsive by updating the progress indicator while loading. Reading the collision files is still a heavy process and will appear to occasionally freeze, but this is better than it was.
This implements TBox support for collision import/export. The 'cubes' array in the col data structure was also renamed to 'boxes.' Minor detail but this naming is more consistent across the code/file format and these shapes are in fact non-uniform boxes, not uniform cubes
This fixes the incorrect bounds calculations for collisions on export. For one thing, the shadow mesh was incorrectly being considered for bounds (some shadow meshes are larger than the collision meshes), and secondly the geometric center of meshes was not being considered for the bounds calculation (an offset mesh still had an identity transform so the real center was off)
A few suggested cleanups. Also changed naming of collision sphere/boxes to 'ColSphere'/'ColBox' to match the naming of collision meshes as 'ColMesh'
This moves all loaded instances into a top-level collection named after the map section (the .ipl file) from which they came. This reduces scene clutter in the outliner, as well as better informing the user which sections have already been loaded into the scene. It also makes section removal easier, just delete the collection hierarchy. Section visibility can also be easily controlled by collection now.
@Calvin-rgb
Copy link

Good Job!

This replaces the previous method of collision loading by region prefix with a more accurate, comprehensive lookup off all instances, loading all .col files referenced by the objects in the .ide file. This change resulted in a number of performance considerations. Firstly, the .ide list is pruned (only for GTA:SA) to exclude IDE files obviously unrelated to the current IPL (might want to revisit this). Next, the originating .ide filename is inserted in the instance data so the correct .col file can later be found (because the .col file sets are named after the .ide of the instance). This changes a number of data structures in map_data. Finally, the timer-based loading had to be adjusted to favor loading larger batches of objects at a time. Unfortunately as the number of objects in the scene increases, the implicit scene updates that Blender performs begin to crush responsiveness and prolong loading considerably. Since we can't control Blender's scene updates the only option is to load more objects each timer pulse. This makes Blender appear to freeze but is significantly faster overall.
@jgooderham
Copy link
Contributor Author

jgooderham commented Jun 26, 2024

This last commit was kind of a pain. So previously I was just loading the .col files that shared a prefix with the current region, but that left a lot of collisions out for anything generic or (I'm only assuming here) xref. So now it looks through all IPL instances and loads every referenced collision file first. This will have a heavy initial cost but subsequent loads for sections of the same region would obviously have their collision loaded already. Unfortunately with the way Blender performs scene updates around operators, as the number of scene objects grows the scene updates become increasingly expensive. To get around this I'm increasing the number of objects loaded at a time which comes at the cost of responsiveness, but significantly decreases overall load times. Obviously I'm open to any suggestions on how to improve this either on the Blender side or the GTA asset side. It might even be better to skip the timer altogether and just brute force load at the UX cost of an apparent (but not actual) total freeze while the import occurs.

Adds two top-level collections which contain and separate the geometry and collision imports. Also a small fix to the .ide pruning.
It's unnecessary (and wasteful) to continually write the bmesh back to the mesh datablock within the loop instead of at the end when all the faces have been built. This must have been an oversight.
This implements face groups for .col files by creating a face attribute on the collision mesh in Blender and storing the face group index there on import. For export, this attribute is looked for and if found all face vertices with the same index are used to build min/max bounding boxes which are then stored along with the beginning/ending face index as a face group block in the resulting .col file. There isn't yet a way to modify these groups or generate them inside Blender although that would be something to look into. This support is currently just so a subsequent export of a collision collection will maintain any face groups that were imported so this information isn't destroyed. However, if a collision mesh is modified in some way then this attribute should be deleted for that object before export as its face groups would obviously no longer be valid.
Small change to move collision items to a collection named for the container file they are imported from. This is more consistent with how map importer works, it better organizes the scene, and it makes it simpler to re-export back to the file from the context menu of the outliner. Also a small gui change to state that the importer works with .col as well as .dff files
This small change handles collisions which have no shapes/meshes but still define a bounds. Some .col files contain such collisions (ie. pigpen_props inside lae2_5.col). I'm actually not sure on whether these are even used by the game but this is an effort to keep as much of the original .col file intact on export as possible. The bounds are just stored in a custom property of the particular col's collection on import, and fetched from there on export.

There is also a small fix that prevents a script error when trying to export a mesh with face groups to a version 1 .col file which doesn't support that.  Which is probably an unintentional action, but script errors are still bad.
@jgooderham
Copy link
Contributor Author

Last few commits included changes to better support import/export of .col files with all of their features. By using Collision File Editor II and comparing stock .col files with versions exported with the addon, it appears they are similar enough that nothing is really lost now that face groups, empty collisions and bounds calculations are more accurate. There is no cone support, but CFEII doesn't seem to support that either? There will be differences in how bounds are calculated, and from what I've seen it appears a collision's overall bounds was being manually set in the stock files as some collisions have bounds that are not tightly fitted to the underlying objects. Collisions exported with the addon will be tightly fitted and I think that is probably better anyway.

Small change to ignore map collisions on DFF export. Map collisions are meant as a convenient way to edit the collisions of map objects in-place and then export them later as separate COL files. The way they're imported in the same collection as map geometry makes them get picked up by the DFF exporter which is likely unintended, so this just ignores them for DFF exports. It should not affect regular embedded collisions for DFF files because those are imported into their own nested collection.
There was a property called reset_positions which presumably resets an object's position to the origin on export, however it doesn't appear to be implemented. Also, the name and description were in conflict. This should resolve things.
Firstly, a small change was made to how collections are considered during an export so that the now more nested structure of collections created by the map importer can work with DFF exports.
Next, a shortcut was added to the Outliner context menu to allow for exporting just the active object as a .dff file. This would be most useful for making changes to a map object and wanting to quickly export just that object with good default settings (correct filename, no collision, position reset to origin).
Also renamed the previous collision collection shortcut func for consistency.
@jgooderham
Copy link
Contributor Author

@Parik27 Ok. I think this is pretty close if you'd like to give it a review. While I have ideas on how to expand the map importer more in the future it currently does what I need it to and these changes are pretty much focused on the original topic of map collisions. I would like to add some info to the wiki as well.

This just speeds up the initial region map import to be in line with what it was before this PR. Originally, 10 map objects are loaded at a time, but this needs to be increased as the overall scene object count grows due to background scene updates taking longer and longer. Still, at least 10 objects need to be loaded at a time when the object count is low, otherwise it takes like ~6x longer for the first import.
This enables a colored overlay of the active object's face groups, if they exist. Each face group is displayed in a unique color. This was implemented in anticipation of a way to generate new face groups.
@jgooderham
Copy link
Contributor Author

I'm working on the face groups feature for collision objects. I really don't know how important face group optimizations remain for running physics calculations on hardware that's 20 years newer than the release of the game, but as I'm intending to add lots of polygons to the map I think it might be useful. Here's a pic:
image
And here's another showing the unfortunate z-fighting that really starts to crop up when further away from the origin:
image
I'm not sure if it can be improved but any ideas are welcome. Seems from my own research to just be a consequence of Blender's handling of depth buffer precision. It's at least good enough to visualize the resulting face groups.

Because an object can be active but not selected, check for selection and skip face group display if false. Also, avoid trying to draw face groups with an empty attribute array.
This operator will generate face groups by bisecting the object bounds repeatedly along the longest axis until the number of polygons inside a sub-region is no more than 50. I'm not sure exactly how the original game tools created face groups, but I used the following information https://gtamods.com/wiki/Collision_File#endnote_1 as a guide.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants