/*! SLAssimpImporter::loadMesh creates a new SLMesh an copies the meshs vertex data and triangle face indices. Normals & tangents are not loaded. They are calculated in SLMesh. */ SLMesh* SLAssimpImporter::loadMesh(aiMesh *mesh) { // Count first the NO. of triangles in the mesh SLuint numTriangles = 0; for(unsigned int i = 0; i < mesh->mNumFaces; ++i) if(mesh->mFaces[i].mNumIndices == 3) numTriangles++; // We only load meshes that contain triangles if (numTriangles==0 || mesh->mNumVertices==0) return nullptr; // create a new mesh. // The mesh pointer is added automatically to the SLScene::meshes vector. SLstring name = mesh->mName.data; SLMesh *m = new SLMesh(name.empty() ? "Imported Mesh" : name); // create position & normal vector m->P.clear(); m->P.resize(mesh->mNumVertices); // create normal vector if (mesh->HasNormals()) { m->N.clear(); m->N.resize(m->P.size()); } // allocate texCoord vector if needed if (mesh->HasTextureCoords(0)) { m->Tc.clear(); m->Tc.resize(m->P.size()); } // copy vertex positions & texCoord for(SLuint i = 0; i < m->P.size(); ++i) { m->P[i].set(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); if (m->N.size()) m->N[i].set(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); if (m->Tc.size()) m->Tc[i].set(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y); } // create face index vector if (m->P.size() < 65536) { m->I16.clear(); m->I16.resize(mesh->mNumFaces * 3); // load face triangle indices only SLuint j = 0; for(SLuint i = 0; i < mesh->mNumFaces; ++i) { if(mesh->mFaces[i].mNumIndices == 3) { m->I16[j++] = mesh->mFaces[i].mIndices[0]; m->I16[j++] = mesh->mFaces[i].mIndices[1]; m->I16[j++] = mesh->mFaces[i].mIndices[2]; } } } else { m->I32.clear(); m->I32.resize(mesh->mNumFaces * 3); // load face triangle indices only SLuint j = 0; for(SLuint i = 0; i < mesh->mNumFaces; ++i) { if(mesh->mFaces[i].mNumIndices == 3) { m->I32[j++] = mesh->mFaces[i].mIndices[0]; m->I32[j++] = mesh->mFaces[i].mIndices[1]; m->I32[j++] = mesh->mFaces[i].mIndices[2]; } } } if (!m->N.size()) m->calcNormals(); // load joints if (mesh->HasBones()) { _skinnedMeshes.push_back(m); m->skeleton(_skeleton); m->Ji.resize(m->P.size()); m->Jw.resize(m->P.size()); // make sure to initialize the weights with 0 vectors std::fill(m->Ji.begin(), m->Ji.end(), SLVec4f(0, 0, 0, 0)); std::fill(m->Jw.begin(), m->Jw.end(), SLVec4f(0, 0, 0, 0)); for (SLuint i = 0; i < mesh->mNumBones; i++) { aiBone* joint = mesh->mBones[i]; SLJoint* slJoint = _skeleton->getJoint(joint->mName.C_Str()); // @todo On OSX it happens from time to time that slJoint is nullptr if (slJoint) { SLuint jointId = slJoint->id(); for (SLuint j = 0; j < joint->mNumWeights; j++) { // add the weight SLuint vertId = joint->mWeights[j].mVertexId; SLfloat weight = joint->mWeights[j].mWeight; m->addWeight(vertId, jointId, weight); // check if the bones max radius changed // @todo this is very specific to this loaded mesh, // when we add a skeleton instances class this radius // calculation has to be done on the instance! slJoint->calcMaxRadius(SLVec3f(mesh->mVertices[vertId].x, mesh->mVertices[vertId].y, mesh->mVertices[vertId].z)); } } else { SL_LOG("Failed to load joint of skeleton in SLAssimpImporter::loadMesh: %s\n", joint->mName.C_Str()); return nullptr; } } } return m; }
/*! SLAssimpImporter::loadMaterial loads the AssImp material an returns the SLMaterial. The materials and textures are added to the SLScene material and texture vectors. */ SLMaterial* SLAssimpImporter::loadMaterial(SLint index, aiMaterial *material, SLstring modelPath) { // Get the materials name aiString matName; material->Get(AI_MATKEY_NAME, matName); SLstring name = matName.data; if (name.empty()) name = "Import Material"; // Create SLMaterial instance. It is also added to the SLScene::_materials vector SLMaterial* mat = new SLMaterial(name.c_str()); // set the texture types to import into our material const SLint textureCount = 4; aiTextureType textureTypes[textureCount]; textureTypes[0] = aiTextureType_DIFFUSE; textureTypes[1] = aiTextureType_NORMALS; textureTypes[2] = aiTextureType_SPECULAR; textureTypes[3] = aiTextureType_HEIGHT; // load all the textures for this material and add it to the material vector for(SLint i = 0; i < textureCount; ++i) { if(material->GetTextureCount(textureTypes[i]) > 0) { aiString aipath; material->GetTexture(textureTypes[i], 0, &aipath, nullptr, nullptr, nullptr, nullptr, nullptr); SLTextureType texType = textureTypes[i]==aiTextureType_DIFFUSE ? TT_color : textureTypes[i]==aiTextureType_NORMALS ? TT_normal : textureTypes[i]==aiTextureType_SPECULAR ? TT_gloss : textureTypes[i]==aiTextureType_HEIGHT ? TT_height : TT_unknown; SLstring texFile = checkFilePath(modelPath, aipath.data); SLGLTexture* tex = loadTexture(texFile, texType); mat->textures().push_back(tex); } } // get color data aiColor3D ambient, diffuse, specular, emissive; SLfloat shininess, refracti, reflectivity, opacity; material->Get(AI_MATKEY_COLOR_AMBIENT, ambient); material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); material->Get(AI_MATKEY_COLOR_SPECULAR, specular); material->Get(AI_MATKEY_COLOR_EMISSIVE, emissive); material->Get(AI_MATKEY_SHININESS, shininess); material->Get(AI_MATKEY_REFRACTI, refracti); material->Get(AI_MATKEY_REFLECTIVITY, reflectivity); material->Get(AI_MATKEY_OPACITY, opacity); // increase shininess if specular color is not low. // The material will otherwise be to bright if (specular.r > 0.5f && specular.g > 0.5f && specular.b > 0.5f && shininess < 0.01f) shininess = 10.0f; // set color data mat->ambient(SLCol4f(ambient.r, ambient.g, ambient.b)); mat->diffuse(SLCol4f(diffuse.r, diffuse.g, diffuse.b)); mat->specular(SLCol4f(specular.r, specular.g, specular.b)); mat->emission(SLCol4f(emissive.r, emissive.g, emissive.b)); mat->shininess(shininess); //mat->kr(reflectivity); //mat->kt(1.0f-opacity); //mat->kn(refracti); return mat; }