15 #include "assimpLoader.h" 19 #include "geomVertexWriter.h" 20 #include "geomPoints.h" 21 #include "geomLines.h" 22 #include "geomTriangles.h" 23 #include "pnmFileTypeRegistry.h" 25 #include "materialAttrib.h" 26 #include "textureAttrib.h" 27 #include "cullFaceAttrib.h" 28 #include "lightNode.h" 29 #include "ambientLight.h" 30 #include "directionalLight.h" 31 #include "spotlight.h" 32 #include "pointLight.h" 34 #include "texturePool.h" 36 #include "pandaIOSystem.h" 37 #include "pandaLogger.h" 39 #include "aiPostProcess.h" 62 _importer.FreeScene();
74 _importer.GetExtensionList(aexts);
77 char *sub = strtok(aexts.data,
";");
80 sub = strtok(NULL,
";");
99 _scene = _importer.ReadFile(_filename.c_str(), aiProcess_Triangulate | aiProcess_GenUVCoords | aiProcess_FlipWindingOrder);
100 if (_scene == NULL) {
117 nassertv(_scene != NULL);
126 _textures =
new PT(
Texture)[_scene->mNumTextures];
127 for (
size_t i = 0; i < _scene->mNumTextures; ++i) {
132 _mat_states =
new CPT(
RenderState)[_scene->mNumMaterials];
133 for (
size_t i = 0; i < _scene->mNumMaterials; ++i) {
138 _geoms =
new PT(
Geom)[_scene->mNumMeshes];
139 _geom_matindices =
new unsigned int[_scene->mNumMeshes];
140 for (
size_t i = 0; i < _scene->mNumMeshes; ++i) {
145 if (_scene->mRootNode != NULL) {
146 load_node(*_scene->mRootNode, _root);
150 for (
size_t i = 0; i < _scene->mNumLights; ++i) {
151 load_light(*_scene->mLights[i]);
155 delete[] _mat_states;
157 delete[] _geom_matindices;
166 load_texture(
size_t index) {
167 const aiTexture &tex = *_scene->mTextures[index];
171 if (tex.mHeight == 0) {
174 <<
"Reading embedded compressed texture with format " << tex.achFormatHint <<
" and size " << tex.mWidth <<
"\n";
176 str.write((
char*) tex.pcData, tex.mWidth);
178 if (strncmp(tex.achFormatHint,
"dds", 3) == 0) {
187 if (strncmp(tex.achFormatHint,
"jp\0", 3) == 0) {
193 if (img.
read(str,
"", ftype)) {
201 <<
"Reading embedded raw texture with size " << tex.mWidth <<
"x" << tex.mHeight <<
"\n";
203 ptex->setup_2d_texture(tex.mWidth, tex.mHeight, Texture::T_unsigned_byte, Texture::F_rgba);
204 PTA_uchar data = ptex->modify_ram_image();
207 for (
size_t i = 0; i < tex.mWidth * tex.mHeight; ++i) {
208 const aiTexel &texel = tex.pcData[i];
220 _textures[index] = ptex;
230 load_texture_stage(
const aiMaterial &mat,
const aiTextureType &ttype, CPT(
TextureAttrib) &tattr) {
232 aiTextureMapping mapping;
233 unsigned int uvindex;
236 aiTextureMapMode mapmode;
238 for (
size_t i = 0; i < mat.GetTextureCount(ttype); ++i) {
239 mat.GetTexture(ttype, i, &path, &mapping, NULL, &blend, &op, &mapmode);
241 if (AI_SUCCESS != mat.Get(AI_MATKEY_UVWSRC(ttype, i), uvindex)) {
259 if (path.data[0] ==
'*') {
260 long num = strtol(path.data + 1, NULL, 10);
261 ptex = _textures[num];
263 }
else if (path.length > 0) {
294 tattr = DCAST(
TextureAttrib, tattr->add_on_stage(stage, ptex));
305 load_material(
size_t index) {
306 const aiMaterial &mat = *_scene->mMaterials[index];
308 CPT(
RenderState) state = RenderState::make_empty();
320 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_DIFFUSE, col)) {
324 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_SPECULAR, col)) {
325 if (AI_SUCCESS == mat.Get(AI_MATKEY_SHININESS_STRENGTH, fval)) {
326 pmat->set_specular(
LColor(col.r * fval, col.g * fval, col.b * fval, 1));
328 pmat->set_specular(
LColor(col.r, col.g, col.b, 1));
332 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_AMBIENT, col)) {
333 pmat->set_specular(
LColor(col.r, col.g, col.b, 1));
336 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_EMISSIVE, col)) {
337 pmat->set_emission(
LColor(col.r, col.g, col.b, 1));
340 if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_TRANSPARENT, col)) {
343 if (AI_SUCCESS == mat.Get(AI_MATKEY_SHININESS, fval)) {
344 pmat->set_shininess(fval);
348 state = state->add_attrib(MaterialAttrib::make(pmat));
352 if (AI_SUCCESS == mat.Get(AI_MATKEY_ENABLE_WIREFRAME, ival)) {
354 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe));
356 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled));
362 if (AI_SUCCESS == mat.Get(AI_MATKEY_TWOSIDED, ival)) {
364 state = state->add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
366 state = state->add_attrib(CullFaceAttrib::make_default());
372 load_texture_stage(mat, aiTextureType_DIFFUSE, tattr);
373 load_texture_stage(mat, aiTextureType_LIGHTMAP, tattr);
375 state = state->add_attrib(tattr);
378 _mat_states[index] = state;
387 load_mesh(
size_t index) {
388 const aiMesh &mesh = *_scene->mMeshes[index];
391 PT(GeomVertexArrayFormat) aformat =
new GeomVertexArrayFormat;
392 aformat->add_column(InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point);
393 if (mesh.HasNormals()) {
394 aformat->add_column(InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_vector);
396 if (mesh.HasVertexColors(0)) {
397 aformat->add_column(InternalName::get_color(), 4, Geom::NT_stdfloat, Geom::C_color);
399 unsigned int num_uvs = mesh.GetNumUVChannels();
402 aformat->add_column(InternalName::get_texcoord(), 3, Geom::NT_stdfloat, Geom::C_texcoord);
403 for (
unsigned int u = 1; u < num_uvs; ++u) {
406 aformat->add_column(InternalName::get_texcoord_name(out.str()), 3, Geom::NT_stdfloat, Geom::C_texcoord);
411 PT(GeomVertexFormat) format =
new GeomVertexFormat;
412 format->add_array(aformat);
415 string name (mesh.mName.data, mesh.mName.length);
417 vdata->unclean_set_num_rows(mesh.mNumVertices);
421 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
422 const aiVector3D &vec = mesh.mVertices[i];
427 if (mesh.HasNormals()) {
429 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
430 const aiVector3D &vec = mesh.mNormals[i];
436 if (mesh.HasVertexColors(0)) {
438 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
439 const aiColor4D &col = mesh.mColors[0][i];
440 color.
add_data4(col.r, col.g, col.b, col.a);
448 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
449 const aiVector3D &vec = mesh.mTextureCoords[0][i];
450 texcoord0.
add_data3(vec.x, vec.y, vec.z);
452 for (
unsigned int u = 1; u < num_uvs; ++u) {
455 GeomVertexWriter texcoord (vdata, InternalName::get_texcoord_name(out.str()));
456 for (
size_t i = 0; i < mesh.mNumVertices; ++i) {
457 const aiVector3D &vec = mesh.mTextureCoords[u][i];
471 for (
size_t i = 0; i < mesh.mNumFaces; ++i) {
472 const aiFace &face = mesh.mFaces[i];
474 if (face.mNumIndices == 0) {
477 }
else if (face.mNumIndices == 1) {
478 points->add_vertex(face.mIndices[0]);
479 points->close_primitive();
480 }
else if (face.mNumIndices == 2) {
481 lines->add_vertices(face.mIndices[0], face.mIndices[1]);
482 lines->close_primitive();
483 }
else if (face.mNumIndices == 3) {
484 triangles->add_vertices(face.mIndices[0], face.mIndices[1], face.mIndices[2]);
485 triangles->close_primitive();
487 nassertd(
false)
continue;
493 if (points->get_num_primitives() > 0) {
494 geom->add_primitive(points);
496 if (lines->get_num_primitives() > 0) {
497 geom->add_primitive(lines);
499 if (triangles->get_num_primitives() > 0) {
500 geom->add_primitive(triangles);
503 _geoms[index] = geom;
504 _geom_matindices[index] = mesh.mMaterialIndex;
513 load_node(
const aiNode &node,
PandaNode *parent) {
517 string name (node.mName.data, node.mName.length);
518 if (node.mNumMeshes > 0) {
523 parent->add_child(pnode);
526 const aiMatrix4x4 &t = node.mTransformation;
527 if (!t.IsIdentity()) {
528 LMatrix4 mat(t.a1, t.b1, t.c1, t.d1,
529 t.a2, t.b2, t.c2, t.d2,
530 t.a3, t.b3, t.c3, t.d3,
531 t.a4, t.b4, t.c4, t.d4);
532 pnode->set_transform(TransformState::make_mat(mat));
535 for (
size_t i = 0; i < node.mNumChildren; ++i) {
536 load_node(*node.mChildren[i], pnode);
539 if (node.mNumMeshes > 0) {
545 if (node.mNumMeshes == 1) {
546 meshIndex = node.mMeshes[0];
547 gnode->add_geom(_geoms[meshIndex]);
548 gnode->set_state(_mat_states[_geom_matindices[meshIndex]]);
551 for (
size_t i = 0; i < node.mNumMeshes; ++i) {
552 meshIndex = node.mMeshes[i];
553 gnode->add_geom(_geoms[node.mMeshes[i]],
554 _mat_states[_geom_matindices[meshIndex]]);
566 load_light(
const aiLight &light) {
567 string name (light.mName.data, light.mName.length);
568 assimp_cat.debug() <<
"Found light '" << name <<
"'\n";
575 switch (light.mType) {
576 case aiLightSource_DIRECTIONAL: {
580 col = light.mColorSpecular;
581 dlight->set_specular_color(
LColor(col.r, col.g, col.b, 1));
583 vec = light.mPosition;
584 dlight->set_point(
LPoint3(vec.x, vec.y, vec.z));
586 vec = light.mDirection;
587 dlight->set_direction(
LVector3(vec.x, vec.y, vec.z));
590 case aiLightSource_POINT: {
594 col = light.mColorSpecular;
595 plight->set_specular_color(
LColor(col.r, col.g, col.b, 1));
597 vec = light.mPosition;
598 plight->set_point(
LPoint3(vec.x, vec.y, vec.z));
600 plight->set_attenuation(
LVecBase3(light.mAttenuationConstant,
601 light.mAttenuationLinear,
602 light.mAttenuationQuadratic));
605 case aiLightSource_SPOT: {
609 col = light.mColorSpecular;
610 plight->set_specular_color(
LColor(col.r, col.g, col.b, 1));
612 plight->set_attenuation(
LVecBase3(light.mAttenuationConstant,
613 light.mAttenuationLinear,
614 light.mAttenuationQuadratic));
616 plight->get_lens()->set_fov(light.mAngleOuterCone);
620 vec = light.mDirection;
621 LPoint3 pos (light.mPosition.x, light.mPosition.y, light.mPosition.z);
624 plight->set_transform(TransformState::make_pos_quat_scale(pos, quat,
LVecBase3(1, 1, 1)));
628 assimp_cat.warning() <<
"Light '" << name <<
"' has an unknown type!\n";
633 LVecBase4 ambient (col.r, col.g, col.b, 0);
636 col = light.mColorAmbient;
637 alight->set_color(ambient);
638 _root->add_child(alight);
641 _root->add_child(lnode);
642 col = light.mColorDiffuse;
643 lnode->set_color(
LColor(col.r, col.g, col.b, 1));
A node of this type is created automatically at the root of each model file that is loaded...
bool read(const Filename &filename)
Reads from the indicated file.
string get_dirname() const
Returns the directory part of the filename.
A light shining from infinitely far away in a particular direction, like sunlight.
string get_basename() const
Returns the basename part of the filename.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
This is the base class for all three-component vectors and points.
void set_diffuse(const LColor &color)
Specifies the diffuse color setting of the material.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Defines a series of disconnected points.
A derivative of Light and of PandaNode.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
void build_graph()
Converts scene graph structures into a Panda3D scene graph, with _root being the root node...
bool read(const Filename &filename, PNMFileType *type=NULL, bool report_unknown_type=true)
Reads the indicated image filename.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
This is the base class of a family of classes that represent particular image file types that PNMImag...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
A light source that seems to illuminate all points in space at once.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
void add_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w)
Sets the write row to a particular 4-component value, and advances the write row. ...
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
The name of a file, such as a texture file or an Egg file.
This is a 4-by-4 transform matrix.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
A container for geometry primitives.
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row. ...
A light originating from a single point in space, and shining in a particular direction, with a cone-shaped falloff.
static Texture * load_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads the given filename up into a texture, if it has not already been loaded, and returns the new te...
PNMFileType * get_type_from_extension(const string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
Defines the way an object appears in the presence of lighting.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Defines a series of disconnected line segments.
This is the base class for all three-component vectors and points.
This class maintains the set of all known PNMFileTypes in the universe.
This is the base quaternion class.
bool is_regular_file(const Filename &filename) const
Convenience function; returns true if the named file exists and is a regular file.
Defines a series of disconnected triangles.
void set_texcoord_name(InternalName *name)
Indicate which set of UV's this texture stage will use.
int get_num_on_stages() const
Returns the number of stages that are turned on by the attribute.
Defines the properties of a named stage of the multitexture pipeline.
static void set_default()
Makes sure there's a global PandaLogger object and makes sure that it is Assimp's default logger...
void get_extensions(string &ext) const
Returns a space-separated list of extensions that Assimp can load, without the leading dots...
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
Custom implementation of Assimp::IOSystem.
A light originating from a single point in space, and shining in all directions.
A node that holds Geom objects, renderable pieces of geometry.
static const LVecBase4f & zero()
Returns a zero-length vector.
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).