Support for surface styles, Multi/Sub-Object materials and material indices in the 3ds max importer

This commit is contained in:
Thomas Krijnen
2013-12-08 09:45:14 +00:00
parent 0f088f02b3
commit 30804b4232
2 changed files with 139 additions and 110 deletions
+139 -62
View File
@@ -22,9 +22,10 @@
#include <istdplug.h>
#include "../ifcmax/IfcMax.h"
#include "../ifcmax/MaxMaterials.h"
#include "../ifcgeom/IfcGeomObjects.h"
static const int NUM_MATERIAL_SLOTS = 24;
int controlsInit = false;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) {
@@ -101,6 +102,102 @@ void IFCImp::ShowAbout(HWND hWnd) {}
DWORD WINAPI fn(LPVOID arg) { return 0; }
#if MAX_RELEASE > 14000
# define S(x) (TSTR::FromCStr(x.c_str()))
#elif defined(_UNICODE)
# define S(x) (WStr(x.c_str()))
#else
# define S(x) (CStr(x.c_str()))
#endif
Mtl* FindMaterialByName(MtlBaseLib* library, const std::string& material_name) {
const int mat_index = library->FindMtlByName(S(material_name));
Mtl* m = 0;
if (mat_index != -1) {
m = static_cast<Mtl*>((*library)[mat_index]);
}
return m;
}
Mtl* FindOrCreateMaterial(MtlBaseLib* library, Interface* max_interface, int& slot, const IfcGeomObjects::Material& material) {
Mtl* m = FindMaterialByName(library, material.name());
if (m == 0) {
StdMat2* stdm = NewDefaultStdMat();
const TimeValue t = -1;
if (material.hasDiffuse()) {
const double* diffuse = material.diffuse();
stdm->SetDiffuse(Color(diffuse[0], diffuse[1], diffuse[2]),t);
}
if (material.hasSpecular()) {
const double* specular = material.specular();
stdm->SetSpecular(Color(specular[0], specular[1], specular[2]),t);
}
if (material.hasSpecularity()) {
stdm->SetShininess(material.specularity(), t);
}
if (material.hasTransparency()) {
stdm->SetOpacity(1.0 - material.transparency(), t);
}
m = stdm;
m->SetName(S(material.name()));
library->Add(m);
if (slot < NUM_MATERIAL_SLOTS) {
max_interface->PutMtlToMtlEditor(m,slot++);
}
}
return m;
}
Mtl* ComposeMultiMaterial(std::map<std::vector<std::string>, Mtl*>& multi_mats, MtlBaseLib* library, Interface* max_interface, int& slot, const std::vector<IfcGeomObjects::Material>& materials, const std::string& object_type, const std::vector<int>& material_ids) {
std::vector<std::string> material_names;
bool needs_default = std::find(material_ids.begin(), material_ids.end(), -1) != material_ids.end();
if (needs_default) {
material_names.push_back(object_type);
}
for (auto it = materials.begin(); it != materials.end(); ++it) {
material_names.push_back(it->name());
}
Mtl* default_material = 0;
if (needs_default) {
default_material = FindMaterialByName(library, object_type);
if (default_material == 0) {
default_material = NewDefaultStdMat();
default_material->SetName(S(object_type));
library->Add(default_material);
if (slot < NUM_MATERIAL_SLOTS) {
max_interface->PutMtlToMtlEditor(default_material, slot++);
}
}
}
if (material_names.size() == 1) {
if (needs_default) {
return default_material;
} else {
return FindOrCreateMaterial(library, max_interface, slot, *materials.begin());
}
}
std::map<std::vector<std::string>, Mtl*>::const_iterator i = multi_mats.find(material_names);
if (i != multi_mats.end()) {
return i->second;
}
MultiMtl* multi_mat = NewDefaultMultiMtl();
multi_mat->SetNumSubMtls(material_names.size());
int mtl_id = 0;
if (needs_default) {
multi_mat->SetSubMtlAndName(mtl_id ++, default_material, default_material->GetName());
}
for (auto it = materials.begin(); it != materials.end(); ++it) {
Mtl* mtl = FindOrCreateMaterial(library, max_interface, slot, *it);
multi_mat->SetSubMtl(mtl_id ++, mtl);
}
library->Add(multi_mat);
if (slot < NUM_MATERIAL_SLOTS) {
max_interface->PutMtlToMtlEditor(multi_mat,slot++);
}
multi_mats.insert(std::pair<std::vector<std::string>, Mtl*>(material_names, multi_mat));
return multi_mat;
}
int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc, BOOL suppressPrompts) {
IfcGeomObjects::Settings(IfcGeomObjects::USE_WORLD_COORDS,false);
@@ -119,79 +216,59 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
itfc->ProgressStart(_T("Importing file..."), TRUE, fn, NULL);
//std::map<int, TriObject*> dict;
MtlBaseLib* mats = itfc->GetSceneMtls();
int slot = mats->Count();
std::map<std::vector<std::string>, Mtl*> material_cache;
do{
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
#if MAX_RELEASE > 14000
TSTR o_type = TSTR::FromCStr(o->type.c_str());
TSTR o_guid = TSTR::FromCStr(o->guid.c_str());
#elif defined(_UNICODE)
TSTR o_type = WStr(o->type.c_str());
TSTR o_guid = WStr(o->guid.c_str());
#else
TSTR o_type = CStr(o->type.c_str());
TSTR o_guid = CStr(o->guid.c_str());
#endif
const IfcGeomObjects::IfcGeomObject* o = IfcGeomObjects::Get();
Mtl *m;
const int matIndex = mats->FindMtlByName(o_type);
if ( matIndex == -1 ) {
StdMat2* stdm = GetMaterial(o->type);
m = stdm;
m->SetName(o_type);
mats->Add(m);
itfc->PutMtlToMtlEditor(m,slot++);
} else {
m = static_cast<Mtl*>((*mats)[matIndex]);
}
// This mapping is useless for now, because this even in case
// meshes entities in IFC share the same representation elements
// they will never be given the same id.
// TODO: Fix this!
// std::map<int, TriObject*>::const_iterator it = dict.find(o->mesh->id);
TSTR o_type = S(o->type());
TSTR o_guid = S(o->guid());
TriObject* tri;
// if ( it == dict.end() ) {
tri = CreateNewTriObject();
const int numVerts = o->mesh->verts.size()/3;
tri->mesh.setNumVerts(numVerts);
for( int i = 0; i < numVerts; i ++ ) {
tri->mesh.setVert(i,o->mesh->verts[3*i+0],o->mesh->verts[3*i+1],o->mesh->verts[3*i+2]);
}
const int numFaces = o->mesh->faces.size()/3;
tri->mesh.setNumFaces(numFaces);
for( int i = 0; i < numFaces; i ++ ) {
tri->mesh.faces[i].setVerts(o->mesh->faces[3*i+0],o->mesh->faces[3*i+1],o->mesh->faces[3*i+2]);
tri->mesh.faces[i].setEdgeVisFlags(o->mesh->edges[3*i+0],o->mesh->edges[3*i+1],o->mesh->edges[3*i+2]);
}
Mtl *m = ComposeMultiMaterial(material_cache, mats, itfc, slot, o->mesh().materials(), o->type(), o->mesh().material_ids());
TriObject* tri = CreateNewTriObject();
const int numVerts = o->mesh().verts().size()/3;
tri->mesh.setNumVerts(numVerts);
for( int i = 0; i < numVerts; i ++ ) {
tri->mesh.setVert(i,o->mesh().verts()[3*i+0],o->mesh().verts()[3*i+1],o->mesh().verts()[3*i+2]);
}
const int numFaces = o->mesh().faces().size()/3;
tri->mesh.setNumFaces(numFaces);
bool needs_default = std::find(o->mesh().material_ids().begin(), o->mesh().material_ids().end(), -1) != o->mesh().material_ids().end();
for( int i = 0; i < numFaces; i ++ ) {
tri->mesh.faces[i].setVerts(o->mesh().faces()[3*i+0],o->mesh().faces()[3*i+1],o->mesh().faces()[3*i+2]);
tri->mesh.faces[i].setEdgeVisFlags(o->mesh().edges()[3*i+0],o->mesh().edges()[3*i+1],o->mesh().edges()[3*i+2]);
MtlID mtlid = o->mesh().material_ids()[i];
if (needs_default) mtlid ++;
tri->mesh.faces[i].setMatID(mtlid);
}
tri->mesh.buildNormals();
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
// properly oriented normals. Using only the line below will result in a consistent
// orientation of normals accross shells, but not always oriented towards the
// outside.
// tri->mesh.UnifyNormals(false);
tri->mesh.BuildStripsAndEdges();
tri->mesh.InvalidateTopologyCache();
tri->mesh.InvalidateGeomCache();
// dict[o->mesh->id] = tri;
// } else {
// tri = (*it).second;
// }
tri->mesh.buildNormals();
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
// properly oriented normals. Using only the line below will result in a consistent
// orientation of normals accross shells, but not always oriented towards the
// outside.
// tri->mesh.UnifyNormals(false);
tri->mesh.BuildStripsAndEdges();
tri->mesh.InvalidateTopologyCache();
tri->mesh.InvalidateGeomCache();
ImpNode* node = impitfc->CreateNode();
node->Reference(tri);
node->SetName(o_guid);
node->GetINode()->SetMtl(m);
node->SetTransform(0,Matrix3 ( Point3(o->matrix[0],o->matrix[1],o->matrix[2]),Point3(o->matrix[3],o->matrix[4],o->matrix[5]),
Point3(o->matrix[6],o->matrix[7],o->matrix[8]),Point3(o->matrix[9],o->matrix[10],o->matrix[11]) ));
node->GetINode()->Hide(o->type() == "IfcOpeningElement" || o->type() == "IfcSpace");
if (m) {
node->GetINode()->SetMtl(m);
}
node->SetTransform(0,Matrix3 ( Point3(o->matrix()[0],o->matrix()[1],o->matrix()[2]),Point3(o->matrix()[3],o->matrix()[4],o->matrix()[5]),
Point3(o->matrix()[6],o->matrix()[7],o->matrix()[8]),Point3(o->matrix()[9],o->matrix()[10],o->matrix()[11]) ));
impitfc->AddNodeToScene(node);
itfc->ProgressUpdate(IfcGeomObjects::Progress(),true,_T(""));
-48
View File
@@ -1,48 +0,0 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file defines materials for use in 3ds Max for several IFC datatypes *
* *
********************************************************************************/
#include <string>
#include "Max.h"
#include "stdmat.h"
StdMat2* GetMaterial(const std::string& s) {
StdMat2* mat = NewDefaultStdMat();
TimeValue t (-1);
mat->SetSpecular(Color(0.2f,0.2f,0.2f),t);
mat->SetAmbient(Color(0.1f,0.1f,0.1f),t);
mat->SetWire( s == "IfcSpace" || s == "IfcOpeningElement" );
if ( s == "IfcSite" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.65f),t); }
if ( s == "IfcSlab" ) { mat->SetDiffuse(Color(0.4f,0.4f,0.4f),t); }
if ( s == "IfcWallStandardCase" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
if ( s == "IfcWall" ) { mat->SetDiffuse(Color(0.9f,0.9f,0.9f),t); }
if ( s == "IfcWindow" ) { mat->SetDiffuse(Color(0.75f,0.8f,0.75f),t); mat->SetSpecular(Color(1.0f,1.0f,1.0f),t);
mat->SetAmbient(Color(0.0f,0.0f,0.0f),t); mat->SetShininess(500.0f,t); mat->SetOpacity(0.3f,t); }
if ( s == "IfcDoor" ) { mat->SetDiffuse(Color(0.55f,0.3f,0.15f),t); }
if ( s == "IfcBeam" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
if ( s == "IfcRailing" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
if ( s == "IfcMember" ) { mat->SetDiffuse(Color(0.75f,0.7f,0.7f),t); }
return mat;
}