mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
Assimp: Add support for skinned meshes (no animations yet).
This commit is contained in:
parent
7f3f546cdd
commit
43958e820c
@ -31,12 +31,24 @@
|
|||||||
#include "pointLight.h"
|
#include "pointLight.h"
|
||||||
#include "look_at.h"
|
#include "look_at.h"
|
||||||
#include "texturePool.h"
|
#include "texturePool.h"
|
||||||
|
#include "character.h"
|
||||||
|
#include "pvector.h"
|
||||||
|
|
||||||
#include "pandaIOSystem.h"
|
#include "pandaIOSystem.h"
|
||||||
#include "pandaLogger.h"
|
#include "pandaLogger.h"
|
||||||
|
|
||||||
#include "assimp/postprocess.h"
|
#include "assimp/postprocess.h"
|
||||||
|
|
||||||
|
struct BoneWeight {
|
||||||
|
CPT(JointVertexTransform) joint_vertex_xform;
|
||||||
|
float weight;
|
||||||
|
|
||||||
|
BoneWeight(CPT(JointVertexTransform) joint_vertex_xform, float weight)
|
||||||
|
: joint_vertex_xform(joint_vertex_xform), weight(weight)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
typedef pvector<BoneWeight> BoneWeightList;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: AssimpLoader::Constructor
|
// Function: AssimpLoader::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -156,6 +168,29 @@ build_graph() {
|
|||||||
delete[] _geom_matindices;
|
delete[] _geom_matindices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AssimpLoader::find_ndoe
|
||||||
|
// Access: Private
|
||||||
|
// Description: Finds a node by name.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
const aiNode *AssimpLoader::
|
||||||
|
find_node(const aiNode &root, const aiString &name) {
|
||||||
|
const aiNode *node;
|
||||||
|
|
||||||
|
if (root.mName == name) {
|
||||||
|
return &root;
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < root.mNumChildren; ++i) {
|
||||||
|
node = find_node(*root.mChildren[i], name);
|
||||||
|
if (node) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: AssimpLoader::load_texture
|
// Function: AssimpLoader::load_texture
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -377,6 +412,28 @@ load_material(size_t index) {
|
|||||||
_mat_states[index] = state;
|
_mat_states[index] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: AssimpLoader::create_joint
|
||||||
|
// Access: Private
|
||||||
|
// Description: Creates a CharacterJoint from an aiNode
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void AssimpLoader::
|
||||||
|
create_joint(PT(Character) character, PT(CharacterJointBundle) bundle, PartGroup *parent, const aiNode &node)
|
||||||
|
{
|
||||||
|
const aiMatrix4x4 &t = node.mTransformation;
|
||||||
|
LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
|
||||||
|
t.a2, t.b2, t.c2, t.d2,
|
||||||
|
t.a3, t.b3, t.c3, t.d3,
|
||||||
|
t.a4, t.b4, t.c4, t.d4);
|
||||||
|
PT(CharacterJoint) joint = new CharacterJoint(character, bundle, parent, node.mName.C_Str(), mat);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < node.mNumChildren; ++i) {
|
||||||
|
if (_bonemap.find(node.mChildren[i]->mName.C_Str()) != _bonemap.end()) {
|
||||||
|
create_joint(character, bundle, joint, *node.mChildren[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: AssimpLoader::load_mesh
|
// Function: AssimpLoader::load_mesh
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -386,6 +443,48 @@ void AssimpLoader::
|
|||||||
load_mesh(size_t index) {
|
load_mesh(size_t index) {
|
||||||
const aiMesh &mesh = *_scene->mMeshes[index];
|
const aiMesh &mesh = *_scene->mMeshes[index];
|
||||||
|
|
||||||
|
// Check if we need to make a Character
|
||||||
|
PT(Character) character = NULL;
|
||||||
|
if (mesh.HasBones()) {
|
||||||
|
assimp_cat.debug()
|
||||||
|
<< "Creating character for " << mesh.mName.C_Str() << "\n";
|
||||||
|
|
||||||
|
// Find and add all bone nodes to the bone map
|
||||||
|
for (size_t i = 0; i < mesh.mNumBones; ++i) {
|
||||||
|
const aiBone &bone = *mesh.mBones[i];
|
||||||
|
const aiNode *node = find_node(*_scene->mRootNode, bone.mName);
|
||||||
|
_bonemap[bone.mName.C_Str()] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the root bone node
|
||||||
|
const aiNode *root = _bonemap[mesh.mBones[0]->mName.C_Str()];
|
||||||
|
while (root->mParent && _bonemap.find(root->mParent->mName.C_Str()) != _bonemap.end()) {
|
||||||
|
root = root->mParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now create a character from the bones
|
||||||
|
character = new Character(mesh.mName.C_Str());
|
||||||
|
PT(CharacterJointBundle) bundle = character->get_bundle(0);
|
||||||
|
PT(PartGroup) skeleton = new PartGroup(bundle, "<skeleton>");
|
||||||
|
create_joint(character, bundle, skeleton, *root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create transform blend table
|
||||||
|
PT(TransformBlendTable) tbtable = new TransformBlendTable;
|
||||||
|
pvector<BoneWeightList> bone_weights(mesh.mNumVertices);
|
||||||
|
if (character) {
|
||||||
|
for (size_t i = 0; i < mesh.mNumBones; ++i) {
|
||||||
|
const aiBone &bone = *mesh.mBones[i];
|
||||||
|
CPT(JointVertexTransform) jvt = new JointVertexTransform(character->find_joint(bone.mName.C_Str()));
|
||||||
|
|
||||||
|
for (size_t j = 0; j < bone.mNumWeights; ++j) {
|
||||||
|
const aiVertexWeight &weight = bone.mWeights[j];
|
||||||
|
|
||||||
|
bone_weights[weight.mVertexId].push_back(BoneWeight(jvt, weight.mWeight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the vertex format.
|
// Create the vertex format.
|
||||||
PT(GeomVertexArrayFormat) aformat = new GeomVertexArrayFormat;
|
PT(GeomVertexArrayFormat) aformat = new GeomVertexArrayFormat;
|
||||||
aformat->add_column(InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point);
|
aformat->add_column(InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point);
|
||||||
@ -405,14 +504,28 @@ load_mesh(size_t index) {
|
|||||||
aformat->add_column(InternalName::get_texcoord_name(out.str()), 3, Geom::NT_stdfloat, Geom::C_texcoord);
|
aformat->add_column(InternalName::get_texcoord_name(out.str()), 3, Geom::NT_stdfloat, Geom::C_texcoord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PT(GeomVertexArrayFormat) tb_aformat = new GeomVertexArrayFormat;
|
||||||
|
tb_aformat->add_column(InternalName::make("transform_blend"), 1, Geom::NT_uint16, Geom::C_index);
|
||||||
|
|
||||||
//TODO: if there is only one UV set, hackily iterate over the texture stages and clear the texcoord name things
|
//TODO: if there is only one UV set, hackily iterate over the texture stages and clear the texcoord name things
|
||||||
|
|
||||||
PT(GeomVertexFormat) format = new GeomVertexFormat;
|
PT(GeomVertexFormat) format = new GeomVertexFormat;
|
||||||
format->add_array(aformat);
|
format->add_array(aformat);
|
||||||
|
if (character) {
|
||||||
|
format->add_array(tb_aformat);
|
||||||
|
|
||||||
|
GeomVertexAnimationSpec aspec;
|
||||||
|
aspec.set_panda();
|
||||||
|
format->set_animation(aspec);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the GeomVertexData.
|
// Create the GeomVertexData.
|
||||||
string name (mesh.mName.data, mesh.mName.length);
|
string name (mesh.mName.data, mesh.mName.length);
|
||||||
PT(GeomVertexData) vdata = new GeomVertexData(name, GeomVertexFormat::register_format(format), Geom::UH_static);
|
PT(GeomVertexData) vdata = new GeomVertexData(name, GeomVertexFormat::register_format(format), Geom::UH_static);
|
||||||
|
if (character) {
|
||||||
|
vdata->set_transform_blend_table(tbtable);
|
||||||
|
}
|
||||||
vdata->unclean_set_num_rows(mesh.mNumVertices);
|
vdata->unclean_set_num_rows(mesh.mNumVertices);
|
||||||
|
|
||||||
// Read out the vertices.
|
// Read out the vertices.
|
||||||
@ -459,6 +572,22 @@ load_mesh(size_t index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now the transform blend table
|
||||||
|
if (character) {
|
||||||
|
GeomVertexWriter transform_blend (vdata, InternalName::get_transform_blend());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh.mNumVertices; ++i) {
|
||||||
|
TransformBlend tblend;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < bone_weights[i].size(); ++j) {
|
||||||
|
tblend.add_transform(bone_weights[i][j].joint_vertex_xform, bone_weights[i][j].weight);
|
||||||
|
}
|
||||||
|
transform_blend.add_data1i(tbtable->add_blend(tblend));
|
||||||
|
}
|
||||||
|
|
||||||
|
tbtable->set_rows(SparseArray::lower_on(vdata->get_num_rows()));
|
||||||
|
}
|
||||||
|
|
||||||
// Now read out the primitives.
|
// Now read out the primitives.
|
||||||
// Keep in mind that we called ReadFile with the aiProcess_Triangulate
|
// Keep in mind that we called ReadFile with the aiProcess_Triangulate
|
||||||
// flag earlier, so we don't have to worry about polygons.
|
// flag earlier, so we don't have to worry about polygons.
|
||||||
@ -501,6 +630,10 @@ load_mesh(size_t index) {
|
|||||||
|
|
||||||
_geoms[index] = geom;
|
_geoms[index] = geom;
|
||||||
_geom_matindices[index] = mesh.mMaterialIndex;
|
_geom_matindices[index] = mesh.mMaterialIndex;
|
||||||
|
|
||||||
|
if (character) {
|
||||||
|
_charmap[mesh.mName.C_Str()] = character;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -511,6 +644,12 @@ load_mesh(size_t index) {
|
|||||||
void AssimpLoader::
|
void AssimpLoader::
|
||||||
load_node(const aiNode &node, PandaNode *parent) {
|
load_node(const aiNode &node, PandaNode *parent) {
|
||||||
PT(PandaNode) pnode;
|
PT(PandaNode) pnode;
|
||||||
|
PT(Character) character;
|
||||||
|
|
||||||
|
// Skip nodes we've converted to joints
|
||||||
|
if (_bonemap.find(node.mName.C_Str()) != _bonemap.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the node and give it a name.
|
// Create the node and give it a name.
|
||||||
string name (node.mName.data, node.mName.length);
|
string name (node.mName.data, node.mName.length);
|
||||||
@ -519,7 +658,13 @@ load_node(const aiNode &node, PandaNode *parent) {
|
|||||||
} else {
|
} else {
|
||||||
pnode = new PandaNode(name);
|
pnode = new PandaNode(name);
|
||||||
}
|
}
|
||||||
parent->add_child(pnode);
|
|
||||||
|
if (_charmap.find(node.mName.C_Str()) != _charmap.end()) {
|
||||||
|
character = _charmap[node.mName.C_Str()];
|
||||||
|
parent->add_child(character);
|
||||||
|
} else {
|
||||||
|
parent->add_child(pnode);
|
||||||
|
}
|
||||||
|
|
||||||
// Load in the transformation matrix.
|
// Load in the transformation matrix.
|
||||||
const aiMatrix4x4 &t = node.mTransformation;
|
const aiMatrix4x4 &t = node.mTransformation;
|
||||||
@ -545,7 +690,6 @@ load_node(const aiNode &node, PandaNode *parent) {
|
|||||||
meshIndex = node.mMeshes[0];
|
meshIndex = node.mMeshes[0];
|
||||||
gnode->add_geom(_geoms[meshIndex]);
|
gnode->add_geom(_geoms[meshIndex]);
|
||||||
gnode->set_state(_mat_states[_geom_matindices[meshIndex]]);
|
gnode->set_state(_mat_states[_geom_matindices[meshIndex]]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < node.mNumMeshes; ++i) {
|
for (size_t i = 0; i < node.mNumMeshes; ++i) {
|
||||||
meshIndex = node.mMeshes[i];
|
meshIndex = node.mMeshes[i];
|
||||||
@ -553,6 +697,11 @@ load_node(const aiNode &node, PandaNode *parent) {
|
|||||||
_mat_states[_geom_matindices[meshIndex]]);
|
_mat_states[_geom_matindices[meshIndex]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (character) {
|
||||||
|
assimp_cat.debug() << "Adding char to geom\n";
|
||||||
|
character->add_child(gnode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +19,23 @@
|
|||||||
#include "filename.h"
|
#include "filename.h"
|
||||||
#include "modelRoot.h"
|
#include "modelRoot.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
#include "pmap.h"
|
||||||
|
|
||||||
#include "assimp/scene.h"
|
#include "assimp/scene.h"
|
||||||
#include "assimp/Importer.hpp"
|
#include "assimp/Importer.hpp"
|
||||||
|
|
||||||
|
class Character;
|
||||||
|
class CharacterJointBundle;
|
||||||
|
class PartGroup;
|
||||||
|
|
||||||
|
struct char_cmp {
|
||||||
|
bool operator () (const char *a, const char *b) const {
|
||||||
|
return strcmp(a,b) < 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef phash_map<const char *, const aiNode *, char_cmp> BoneMap;
|
||||||
|
typedef phash_map<const char *, PT(Character), char_cmp> CharacterMap;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : AssimpLoader
|
// Class : AssimpLoader
|
||||||
// Description : Class that interfaces with Assimp and builds Panda
|
// Description : Class that interfaces with Assimp and builds Panda
|
||||||
@ -54,10 +67,15 @@ private:
|
|||||||
CPT(RenderState) *_mat_states;
|
CPT(RenderState) *_mat_states;
|
||||||
PT(Geom) *_geoms;
|
PT(Geom) *_geoms;
|
||||||
unsigned int *_geom_matindices;
|
unsigned int *_geom_matindices;
|
||||||
|
BoneMap _bonemap;
|
||||||
|
CharacterMap _charmap;
|
||||||
|
|
||||||
|
const aiNode *find_node(const aiNode &root, const aiString &name);
|
||||||
|
|
||||||
void load_texture(size_t index);
|
void load_texture(size_t index);
|
||||||
void load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(TextureAttrib) &tattr);
|
void load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(TextureAttrib) &tattr);
|
||||||
void load_material(size_t index);
|
void load_material(size_t index);
|
||||||
|
void create_joint(PT(Character) character, PT(CharacterJointBundle) bundle, PartGroup *parent, const aiNode &node);
|
||||||
void load_mesh(size_t index);
|
void load_mesh(size_t index);
|
||||||
void load_node(const aiNode &node, PandaNode *parent);
|
void load_node(const aiNode &node, PandaNode *parent);
|
||||||
void load_light(const aiLight &light);
|
void load_light(const aiLight &light);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user