mirror of https://github.com/AxioDL/metaforce.git
Add collision mesh cooking to BlenderConnection
This commit is contained in:
parent
73cb100174
commit
2b1e246ae9
|
@ -871,6 +871,54 @@ uint32_t BlenderConnection::DataStream::Mesh::SkinBanks::addSurface
|
|||
return uint32_t(-1);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::ColMesh::ColMesh(BlenderConnection& conn)
|
||||
: sceneXf(conn), aabbMin(conn), aabbMax(conn)
|
||||
{
|
||||
uint32_t matCount;
|
||||
conn._readBuf(&matCount, 4);
|
||||
materials.reserve(matCount);
|
||||
for (uint32_t i=0 ; i<matCount ; ++i)
|
||||
materials.emplace_back(conn);
|
||||
|
||||
uint32_t count;
|
||||
conn._readBuf(&count, 4);
|
||||
verts.reserve(count);
|
||||
for (uint32_t i=0 ; i<count ; ++i)
|
||||
verts.emplace_back(conn);
|
||||
|
||||
conn._readBuf(&count, 4);
|
||||
edges.reserve(count);
|
||||
for (uint32_t i=0 ; i<count ; ++i)
|
||||
edges.emplace_back(conn);
|
||||
|
||||
conn._readBuf(&count, 4);
|
||||
trianges.reserve(count);
|
||||
for (uint32_t i=0 ; i<count ; ++i)
|
||||
trianges.emplace_back(conn);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::ColMesh::Material::Material(BlenderConnection& conn)
|
||||
{
|
||||
uint32_t nameLen;
|
||||
conn._readBuf(&nameLen, 4);
|
||||
if (nameLen)
|
||||
{
|
||||
name.assign(nameLen, '\0');
|
||||
conn._readBuf(&name[0], nameLen);
|
||||
}
|
||||
conn._readBuf(&type, 5);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::ColMesh::Edge::Edge(BlenderConnection& conn)
|
||||
{
|
||||
conn._readBuf(this, 9);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::ColMesh::Triangle::Triangle(BlenderConnection& conn)
|
||||
{
|
||||
conn._readBuf(this, 16);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::Actor::Actor(BlenderConnection& conn)
|
||||
{
|
||||
uint32_t armCount;
|
||||
|
@ -1084,6 +1132,25 @@ BlenderConnection::DataStream::compileMesh(const std::string& name,
|
|||
return Mesh(*m_parent, topology, skinSlotCount, surfProg);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::ColMesh
|
||||
BlenderConnection::DataStream::compileColMesh(const std::string& name)
|
||||
{
|
||||
if (m_parent->m_loadedType != BlendType::Area)
|
||||
BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"),
|
||||
m_parent->m_loadedBlend.getAbsolutePath().c_str());
|
||||
|
||||
char req[128];
|
||||
snprintf(req, 128, "MESHCOMPILENAMECOLLISION %s", name.c_str());
|
||||
m_parent->_writeLine(req);
|
||||
|
||||
char readBuf[256];
|
||||
m_parent->_readLine(readBuf, 256);
|
||||
if (strcmp(readBuf, "OK"))
|
||||
BlenderLog.report(logvisor::Fatal, "unable to cook collision mesh '%s': %s", name.c_str(), readBuf);
|
||||
|
||||
return ColMesh(*m_parent);
|
||||
}
|
||||
|
||||
BlenderConnection::DataStream::Mesh
|
||||
BlenderConnection::DataStream::compileAllMeshes(HMDLTopology topology,
|
||||
int skinSlotCount,
|
||||
|
|
|
@ -371,6 +371,8 @@ public:
|
|||
operator const uint32_t&() const {return val;}
|
||||
};
|
||||
|
||||
static atVec3f MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec);
|
||||
|
||||
/** Intermediate mesh representation prepared by blender from a single mesh object */
|
||||
struct Mesh
|
||||
{
|
||||
|
@ -517,7 +519,48 @@ public:
|
|||
/** Prepares mesh representation for indexed access on modern APIs.
|
||||
* Mesh must remain resident for accessing reference members
|
||||
*/
|
||||
HMDLBuffers getHMDLBuffers() const;
|
||||
HMDLBuffers getHMDLBuffers(bool absoluteCoords) const;
|
||||
};
|
||||
|
||||
/** Intermediate collision mesh representation prepared by blender from a single mesh object */
|
||||
struct ColMesh
|
||||
{
|
||||
/* Object transform in scene */
|
||||
Matrix4f sceneXf;
|
||||
|
||||
/* Cumulative AABB */
|
||||
Vector3f aabbMin;
|
||||
Vector3f aabbMax;
|
||||
|
||||
/** HECL source and metadata of each material */
|
||||
struct Material
|
||||
{
|
||||
std::string name;
|
||||
uint32_t type;
|
||||
bool fireThrough;
|
||||
Material(BlenderConnection& conn);
|
||||
};
|
||||
std::vector<Material> materials;
|
||||
|
||||
std::vector<Vector3f> verts;
|
||||
|
||||
struct Edge
|
||||
{
|
||||
uint32_t verts[2];
|
||||
bool seam;
|
||||
Edge(BlenderConnection& conn);
|
||||
};
|
||||
std::vector<Edge> edges;
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
uint32_t edges[3];
|
||||
uint32_t matIdx;
|
||||
Triangle(BlenderConnection& conn);
|
||||
};
|
||||
std::vector<Triangle> trianges;
|
||||
|
||||
ColMesh(BlenderConnection& conn);
|
||||
};
|
||||
|
||||
|
||||
|
@ -536,6 +579,9 @@ public:
|
|||
Mesh compileMesh(const std::string& name, HMDLTopology topology, int skinSlotCount=10,
|
||||
Mesh::SurfProgFunc surfProg=[](int){});
|
||||
|
||||
/** Compile collision mesh by name (AREA blends only) */
|
||||
ColMesh compileColMesh(const std::string& name);
|
||||
|
||||
/** Compile all meshes into one (AREA blends only) */
|
||||
Mesh compileAllMeshes(HMDLTopology topology, int skinSlotCount=10, float maxOctantLength=5.0,
|
||||
Mesh::SurfProgFunc surfProg=[](int){});
|
||||
|
|
|
@ -3,7 +3,16 @@
|
|||
namespace hecl
|
||||
{
|
||||
|
||||
HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers() const
|
||||
atVec3f BlenderConnection::DataStream::MtxVecMul4RM(const Matrix4f& mtx, const Vector3f& vec)
|
||||
{
|
||||
atVec3f res;
|
||||
res.vec[0] = mtx[0].vec[0] * vec.val.vec[0] + mtx[0].vec[1] * vec.val.vec[1] + mtx[0].vec[2] * vec.val.vec[2] + mtx[0].vec[3];
|
||||
res.vec[1] = mtx[1].vec[0] * vec.val.vec[0] + mtx[1].vec[1] * vec.val.vec[1] + mtx[1].vec[2] * vec.val.vec[2] + mtx[1].vec[3];
|
||||
res.vec[2] = mtx[2].vec[0] * vec.val.vec[0] + mtx[2].vec[1] * vec.val.vec[1] + mtx[2].vec[2] * vec.val.vec[2] + mtx[2].vec[3];
|
||||
return res;
|
||||
}
|
||||
|
||||
HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers(bool absoluteCoords) const
|
||||
{
|
||||
/* If skinned, compute max weight vec count */
|
||||
size_t weightCount = 0;
|
||||
|
@ -75,7 +84,13 @@ HMDLBuffers BlenderConnection::DataStream::Mesh::getHMDLBuffers() const
|
|||
const Surface& s = *sv.first;
|
||||
const Surface::Vert& v = *sv.second;
|
||||
|
||||
vboW.writeVec3fLittle(pos[v.iPos]);
|
||||
if (absoluteCoords)
|
||||
{
|
||||
atVec3f preXfPos = MtxVecMul4RM(sceneXf, pos[v.iPos]);
|
||||
vboW.writeVec3fLittle(preXfPos);
|
||||
}
|
||||
else
|
||||
vboW.writeVec3fLittle(pos[v.iPos]);
|
||||
vboW.writeVec3fLittle(norm[v.iNorm]);
|
||||
|
||||
for (size_t i=0 ; i<colorLayerCount ; ++i)
|
||||
|
|
|
@ -26,8 +26,7 @@ def write_out_material(writebuf, mat, mesh_obj):
|
|||
writebuf(struct.pack('i', prop[1]))
|
||||
|
||||
# Takes a Blender 'Mesh' object (not the datablock)
|
||||
# and performs a one-shot conversion process to HMDL; packaging
|
||||
# into the HECL data-pipeline and returning a hash once complete
|
||||
# and performs a one-shot conversion process to HMDL
|
||||
def cook(writebuf, mesh_obj, output_mode, max_skin_banks, max_octant_length=None):
|
||||
if mesh_obj.type != 'MESH':
|
||||
raise RuntimeError("%s is not a mesh" % mesh_obj.name)
|
||||
|
@ -205,6 +204,76 @@ def cook(writebuf, mesh_obj, output_mode, max_skin_banks, max_octant_length=None
|
|||
bpy.data.objects.remove(copy_obj)
|
||||
bpy.data.meshes.remove(copy_mesh)
|
||||
|
||||
# Takes a Blender 'Mesh' object (not the datablock)
|
||||
# and performs a one-shot conversion process to collision geometry
|
||||
def cookcol(writebuf, mesh_obj):
|
||||
if mesh_obj.type != 'MESH':
|
||||
raise RuntimeError("%s is not a mesh" % mesh_obj.name)
|
||||
|
||||
# Copy mesh (and apply mesh modifiers with triangulation)
|
||||
copy_name = mesh_obj.name + "_hmdltri"
|
||||
copy_mesh = bpy.data.meshes.new(copy_name)
|
||||
copy_obj = bpy.data.objects.new(copy_name, copy_mesh)
|
||||
copy_obj.data = mesh_obj.to_mesh(bpy.context.scene, True, 'RENDER')
|
||||
copy_mesh = copy_obj.data
|
||||
copy_obj.scale = mesh_obj.scale
|
||||
bpy.context.scene.objects.link(copy_obj)
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.context.scene.objects.active = copy_obj
|
||||
copy_obj.select = True
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
bpy.ops.mesh.quads_convert_to_tris()
|
||||
bpy.ops.mesh.select_all(action='DESELECT')
|
||||
bpy.context.scene.update()
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
copy_mesh.calc_normals_split()
|
||||
rna_loops = copy_mesh.loops
|
||||
|
||||
# Send scene matrix
|
||||
wmtx = mesh_obj.matrix_world
|
||||
writebuf(struct.pack('ffffffffffffffff',
|
||||
wmtx[0][0], wmtx[0][1], wmtx[0][2], wmtx[0][3],
|
||||
wmtx[1][0], wmtx[1][1], wmtx[1][2], wmtx[1][3],
|
||||
wmtx[2][0], wmtx[2][1], wmtx[2][2], wmtx[2][3],
|
||||
wmtx[3][0], wmtx[3][1], wmtx[3][2], wmtx[3][3]))
|
||||
|
||||
# Filter out useless AABB points and send data
|
||||
pt = copy_obj.bound_box[0]
|
||||
writebuf(struct.pack('fff', pt[0], pt[1], pt[2]))
|
||||
pt = copy_obj.bound_box[6]
|
||||
writebuf(struct.pack('fff', pt[0], pt[1], pt[2]))
|
||||
|
||||
# Send materials
|
||||
writebuf(struct.pack('I', len(copy_mesh.materials)))
|
||||
for m in copy_mesh.materials:
|
||||
writebuf(struct.pack('I', len(m.name)))
|
||||
writebuf(m.name.encode())
|
||||
writebuf(struct.pack('Ib', m.retro_collision_type, m.retro_projectile_passthrough))
|
||||
|
||||
# Send verts
|
||||
writebuf(struct.pack('I', len(copy_mesh.vertices)))
|
||||
for v in copy_mesh.vertices:
|
||||
writebuf(struct.pack('fff', v.co[0], v.co[1], v.co[2]))
|
||||
|
||||
# Send edges
|
||||
writebuf(struct.pack('I', len(copy_mesh.edges)))
|
||||
for e in copy_mesh.edges:
|
||||
writebuf(struct.pack('IIb', e.vertices[0], e.vertices[1], e.use_seam))
|
||||
|
||||
# Send trianges
|
||||
writebuf(struct.pack('I', len(copy_mesh.polygons)))
|
||||
for p in copy_mesh.polygons:
|
||||
edge_idxs = []
|
||||
for ek in p.edge_keys:
|
||||
edge_idxs.append(copy_mesh.edge_keys.index(ek))
|
||||
writebuf(struct.pack('IIII', edge_idxs[0], edge_idxs[1], edge_idxs[2], p.material_index))
|
||||
|
||||
# Delete copied mesh from scene
|
||||
bpy.context.scene.objects.unlink(copy_obj)
|
||||
bpy.data.objects.remove(copy_obj)
|
||||
bpy.data.meshes.remove(copy_mesh)
|
||||
|
||||
|
||||
def draw(layout, context):
|
||||
layout.prop_search(context.scene, 'hecl_mesh_obj', context.scene, 'objects')
|
||||
|
|
|
@ -182,6 +182,16 @@ def dataout_loop():
|
|||
writepipeline(b'OK')
|
||||
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], cmdargs[2], maxSkinBanks)
|
||||
|
||||
elif cmdargs[0] == 'MESHCOMPILENAMECOLLISION':
|
||||
meshName = cmdargs[1]
|
||||
|
||||
if meshName not in bpy.data.objects:
|
||||
writepipeline(('mesh %s not found' % meshName).encode())
|
||||
continue
|
||||
|
||||
writepipeline(b'OK')
|
||||
hecl.hmdl.cookcol(writepipebuf, bpy.data.objects[meshName])
|
||||
|
||||
elif cmdargs[0] == 'MESHCOMPILEALL':
|
||||
maxSkinBanks = int(cmdargs[2])
|
||||
maxOctantLength = float(cmdargs[3])
|
||||
|
@ -238,7 +248,6 @@ def dataout_loop():
|
|||
for c in r:
|
||||
writepipebuf(struct.pack('f', c))
|
||||
|
||||
|
||||
# Main exception handling
|
||||
try:
|
||||
# Command loop
|
||||
|
|
Loading…
Reference in New Issue