Add terrain mesh extractor

This commit is contained in:
gsemaj 2023-07-13 16:18:09 -04:00
parent 7b750db9f9
commit 3aabb35f33
No known key found for this signature in database
GPG Key ID: 24B96BAA40497929
2 changed files with 93 additions and 0 deletions

View File

@ -0,0 +1,88 @@
from unitypackff.asset import Asset
from unitypackff.environment import UnityEnvironment
import bpy
import bmesh
import os
dongpath = r'C:\Users\gents\AppData\LocalLow\Unity\Web Player\Cache\Fusionfall'
env = UnityEnvironment(base_path=dongpath)
outpath = r'C:\Users\gents\3D Objects\FFTerrainMeshes'
def rip_terrain_mesh(f, outpath):
dong = Asset.from_file(f, environment=env)
for k, v in dong.objects.items():
if v.type == 'TerrainData':
terrainData = dong.objects[k].read()
terrain_width = terrainData['m_Heightmap']['m_Width'] - 1
terrain_height = terrainData['m_Heightmap']['m_Height'] - 1
# create the terrain
bpy.ops.mesh.primitive_grid_add(x_subdivisions=terrain_width, y_subdivisions=terrain_height, size=40, enter_editmode=True, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
context = bpy.context
grid = context.edit_object
# apply triangulate modifier
mod = grid.modifiers.new("Triangulate", 'TRIANGULATE')
mod.quad_method = 'FIXED' # triangle orientation
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.modifier_apply(modifier="Triangulate")
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(context.edit_object.data)
bm.verts.ensure_lookup_table()
for index, height in enumerate(terrainData['m_Heightmap']['m_Heights']):
height = height / terrainData['m_Heightmap']['m_Scale']['y']
bm.verts[index].co.z = height
indices = []
shift_amt = abs(bm.verts[0].co.x - bm.verts[1].co.x)
# gather m_Shifts positions
for shift in terrainData['m_Heightmap']['m_Shifts']:
shift_index = shift['y'] + shift['x'] * 129
indices.append(shift_index)
v = bm.verts[shift_index]
flags = shift['flags'] # bits: +X -X +Y -Y
if flags & 0b1000: # +X
v.co.x += shift_amt
if flags & 0b0100: # -X
v.co.x -= shift_amt
if flags & 0b0010: # +Y
v.co.y += shift_amt
if flags & 0b0001: # -Y
v.co.y -= shift_amt
# flip to correct orientation
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action='SELECT')
bpy.ops.transform.mirror(orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(False, True, False))
outfile = f"{k}.fbx"
bpy.ops.export_scene.fbx(filepath=os.path.join(outpath, outfile))
# select modified vertices
#bpy.ops.object.mode_set(mode="EDIT")
#bm = bmesh.from_edit_mesh(context.edit_object.data)
#bm.verts.ensure_lookup_table()
#for v in bm.verts:
# v.select = False
#for shift_index in indices:
# v = bm.verts[shift_index]
# v.select = True
# clear the scene
bpy.ops.object.mode_set(mode="OBJECT")
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
dongs = os.listdir(dongpath)
for dongname in dongs:
if not dongname.endswith("resourceFile"):
continue
assets = os.listdir(os.path.join(dongpath, dongname))
for assetname in assets:
if not assetname.startswith("CustomAssetBundle"):
continue
with open(os.path.join(dongpath, dongname, assetname), "rb") as f:
outdir = os.path.join(outpath, dongname, assetname)
os.makedirs(outdir, exist_ok=True)
rip_terrain_mesh(f, outdir)

View File

@ -0,0 +1,5 @@
# Terrain Mesh Extractor
Blender + UPFF script to import terrain data as a mesh into Blender, then apply the shifts property to applicable vertices.
- Exports as FBX
- The fbx filenames are the index of the TerrainData object within the asset file
- Folders for asset bundles that had no terrain objects will be empty