initial camera-orientation; multiple materials in a single element; default material used from IfcGeom; improved triangle node data generation for OSG

This commit is contained in:
dushyant basson
2023-09-14 12:36:45 +05:30
committed by Thomas Krijnen
parent e4ce53d548
commit 832618b84a
4 changed files with 167 additions and 150 deletions
+103 -109
View File
@@ -6,6 +6,7 @@
#include "osg/Material"
#include "osg/PrimitiveSet"
#include "osg/StateAttribute"
#include "osg/StateSet"
#include "osg/Vec4"
#include "osg/ref_ptr"
#include <OpenGL/OpenGL.h>
@@ -28,6 +29,7 @@ bool ParseIfcFile::Parse(
IfcGeom::IteratorSettings settings;
settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false);
settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true);
IfcGeom::Iterator* it = new IfcGeom::Iterator(settings, &file);
if (!it->initialize()) {
@@ -39,137 +41,129 @@ bool ParseIfcFile::Parse(
do {
//const IfcGeom::BRepElement* bRepElem = it->get_native();
const IfcGeom::TriangulationElement* triElem = static_cast<const IfcGeom::TriangulationElement*>(it->get());
MessageLogger::log(triElem->type() + ": " + triElem->name());
// Print element info
std::string elemInfo = triElem->type();
elemInfo += triElem->name() == "" ? "" : ": " + triElem->name();
MessageLogger::log(elemInfo);
// Transformation Matrix
const std::vector<double>& matrixData = triElem->transformation().matrix().data();
std::string matrixStr = "";
int di = 0;
for (auto d : matrixData) {
if (di == 4) {
matrixStr += "\n";
di = 0;
}
matrixStr += std::to_string(d) + " ";
di++;
}
//MessageLogger::log(matrixStr); // Print matrix data
//MessageLogger::log(triElem->geometry().id());
const boost::shared_ptr<IfcGeom::Representation::Triangulation>& triElemGeom = triElem->geometry_pointer();
const std::vector<int>& elemFaces = triElemGeom->faces();
const std::vector<double>& elemVertices = triElemGeom->verts();
const std::vector<double>& elemNormals = triElemGeom->normals();
std::vector<Triangle> triangles = this->createTriangles(elemFaces, elemVertices, elemNormals);
osg::ref_ptr<osg::Vec3Array> osgVertices = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> osgNormals = new osg::Vec3Array;
// Combine the triangles from the vector into a single Vec3Array
for (const auto& triangle : triangles) {
osgVertices->push_back(triangle.vn1.vertex);
osgVertices->push_back(triangle.vn2.vertex);
osgVertices->push_back(triangle.vn3.vertex);
osgNormals->push_back(triangle.vn1.normal);
osgNormals->push_back(triangle.vn2.normal);
osgNormals->push_back(triangle.vn3.normal);
}
osg::ref_ptr<osg::Geometry> elemGeom = new osg::Geometry;
elemGeom->setVertexArray(osgVertices);
elemGeom->setNormalArray(osgNormals);
elemGeom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
osg::ref_ptr<osg::DrawArrays> drawArrays = new osg::DrawArrays(
osg::PrimitiveSet::TRIANGLES, 0, osgVertices->size());
elemGeom->addPrimitiveSet(drawArrays);
// materials
const std::vector<IfcGeom::Material>& elemMats = triElemGeom->materials();
std::vector<osg::ref_ptr<osg::Material>> elemOsgMats;
for (const IfcGeom::Material& mat : elemMats) {
//MessageLogger::log(" " + mat.original_name());
elemOsgMats.push_back(getOsgMaterial(mat));
}
if (elemOsgMats.size()) {
// Todo: set respective material for each part of the element
elemGeom->getOrCreateStateSet()->setAttributeAndModes(elemOsgMats[0].get());
} else { // sometimes material values are not available (like for IfcOpeningElement)
osg::ref_ptr<osg::Material> osgMaterial = new osg::Material;
osgMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, this->getDefaultOsgDiffuseColor());
elemGeom->getOrCreateStateSet()->setAttributeAndModes(osgMaterial.get());
const std::vector<int>& elemMatIds = triElemGeom->material_ids();
std::map<int, osg::ref_ptr<osg::Material>> uniqueMaterials;
std::map<int, std::vector<int>> elemFaces_grouped;
auto fit = elemFaces.begin();
for (const int& matId : elemMatIds) {
for (int i = 0; i < 3; ++i) {
elemFaces_grouped[matId].push_back(*fit++);
}
}
geometries.push_back(elemGeom);
if (fit != elemFaces.end())
MessageLogger::log("** Failed to map the faces to material IDs!");
for (const auto& group : elemFaces_grouped) {
int matId = group.first;
const std::vector<int>& fVertIds = group.second;
osg::ref_ptr<osg::Vec3Array> osgVertices = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> osgNormals = new osg::Vec3Array;
for (size_t i = 0; i < fVertIds.size(); i += 3) {
buildTriangleNodes(
fVertIds, elemVertices, elemNormals, i,
osgVertices, osgNormals
);
}
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setVertexArray(osgVertices);
geometry->setNormalArray(osgNormals);
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
osg::ref_ptr<osg::DrawArrays> drawArrays = new osg::DrawArrays(
osg::PrimitiveSet::TRIANGLES, 0, osgVertices->size());
geometry->addPrimitiveSet(drawArrays);
osg::ref_ptr<osg::Material> osgMaterial = getOsgMaterial(elemMats[matId]);
geometry->getOrCreateStateSet()->setAttributeAndModes(osgMaterial.get());
geometries.push_back(geometry);
}
} while (it->next());
return true;
}
std::vector<Triangle> ParseIfcFile::createTriangles(
const std::vector<int>& elemFaces,
const std::vector<double>& elemVertices,
const std::vector<double>& elemNormals
) {
std::vector<Triangle> triangles;
for (size_t i = 0; i < elemFaces.size(); i += 3) {
auto createVertexWithNormal = [elemFaces, elemVertices, elemNormals](size_t fi) {
VertexWithNormal vn;
size_t initVertIndex = 3 * elemFaces[fi];
size_t x_vertIndex = initVertIndex;
size_t y_vertIndex = initVertIndex + 1;
size_t z_vertIndex = initVertIndex + 2;
vn.vertex = osg::Vec3 (
elemVertices[x_vertIndex],
elemVertices[y_vertIndex],
elemVertices[z_vertIndex]
);
vn.normal = osg::Vec3 (
elemNormals[x_vertIndex],
elemNormals[y_vertIndex],
elemNormals[z_vertIndex]
);
return vn;
};
auto createTriangle = [createVertexWithNormal, i]() {
Triangle triangle;
triangle.vn1 = createVertexWithNormal(i);
triangle.vn2 = createVertexWithNormal(i + 1);
triangle.vn3 = createVertexWithNormal(i + 2);
return triangle;
};
triangles.push_back(createTriangle());
}
return triangles;
}
osg::Vec4 ParseIfcFile::getDefaultOsgDiffuseColor()
void ParseIfcFile::buildTriangleNodes(
const std::vector<int>& fVertIds,
const std::vector<double>& elemVertices,
const std::vector<double>& elemNormals,
size_t index,
osg::ref_ptr<osg::Vec3Array> osgVertices,
osg::ref_ptr<osg::Vec3Array> osgNormals)
{
osg::Vec4 osgDiffuseColor(0.4f, 0.4f, 0.8f, 1.0f);
return osgDiffuseColor;
auto addVertexAndNormal = [fVertIds, elemVertices, elemNormals, osgVertices, osgNormals](size_t i) {
size_t initVertIndex = 3 * fVertIds[i];
size_t x_vertIndex = initVertIndex;
size_t y_vertIndex = initVertIndex + 1;
size_t z_vertIndex = initVertIndex + 2;
osgVertices->push_back(osg::Vec3 (
elemVertices[x_vertIndex],
elemVertices[y_vertIndex],
elemVertices[z_vertIndex]
));
osgNormals->push_back(osg::Vec3 (
elemNormals[x_vertIndex],
elemNormals[y_vertIndex],
elemNormals[z_vertIndex]
));
};
addVertexAndNormal(index);
addVertexAndNormal(index + 1);
addVertexAndNormal(index + 2);
}
osg::ref_ptr<osg::Material> ParseIfcFile::getOsgMaterial(const IfcGeom::Material& material)
{
osg::Vec4 osgDiffuseColor = getDefaultOsgDiffuseColor();
if(material.hasDiffuse()) {
const double* diffuseColor = material.diffuse();
osg::Vec4 matOsgDiffuseColor(
diffuseColor[0],
diffuseColor[1],
diffuseColor[2],
material.transparency()
);
osgDiffuseColor = matOsgDiffuseColor;
}
const double* diffuseColor = material.diffuse();
osg::Vec4 matOsgDiffuseColor(
diffuseColor[0],
diffuseColor[1],
diffuseColor[2],
material.transparency()
);
osg::ref_ptr<osg::Material> osgMaterial = new osg::Material;
osgMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osgDiffuseColor);
osgMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, matOsgDiffuseColor);
return osgMaterial;
}