From b9f2dbb0b3cfb326f092349f267f174d370a437b Mon Sep 17 00:00:00 2001 From: D4ve-R Date: Mon, 15 May 2023 11:52:36 +0200 Subject: [PATCH] filename bug --- src/serializers/USDSerializer.cpp | 223 ++++++++++++++++-------------- src/serializers/USDSerializer.h | 22 ++- 2 files changed, 132 insertions(+), 113 deletions(-) diff --git a/src/serializers/USDSerializer.cpp b/src/serializers/USDSerializer.cpp index 6c81adc830..29fe543da2 100644 --- a/src/serializers/USDSerializer.cpp +++ b/src/serializers/USDSerializer.cpp @@ -1,31 +1,48 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + #ifdef WITH_USD #include "USDSerializer.h" -#include "pxr/base/tf/token.h" #include "pxr/base/gf/vec3f.h" -#include "pxr/base/gf/rotation.h" #include "pxr/usd/usdGeom/xform.h" -#include "pxr/usd/usdGeom/xformOp.h" -#include "pxr/usd/usdGeom/tokens.h" #include "pxr/usd/usdGeom/scope.h" #include "pxr/usd/usdLux/distantLight.h" #include "pxr/usd/usdShade/shader.h" -#include "pxr/usd/usdShade/tokens.h" #include "pxr/usd/usdShade/materialBindingAPI.h" -#include "pxr/usd/usdShade/connectableAPI.h" USDSerializer::USDSerializer(const std::string& out_filename, const SerializerSettings& settings): - WriteOnlyGeometrySerializer(settings), - filename_(out_filename) + WriteOnlyGeometrySerializer(settings), + filename_(out_filename) { - // create a new stage - stage_ = pxr::UsdStage::CreateNew(filename_ + ".usda"); + // why does this not work with just the filename ??? + stage_ = pxr::UsdStage::CreateNew(filename_ + ".usda"); - pxr::UsdGeomXform::Define(stage_, pxr::SdfPath("/World")); - pxr::UsdGeomScope::Define(stage_, pxr::SdfPath("/Looks")); - createLighting(); - ready_ = true; + if(!stage_) + throw std::runtime_error("Could not create USD stage"); + + auto world = pxr::UsdGeomXform::Define(stage_, pxr::SdfPath("/World")); + stage_->SetDefaultPrim(world.GetPrim()); + pxr::UsdGeomScope::Define(stage_, pxr::SdfPath("/Looks")); + createLighting(); + ready_ = true; } USDSerializer::~USDSerializer() { @@ -33,118 +50,122 @@ USDSerializer::~USDSerializer() { } void USDSerializer::createLighting() { - // create a distant light - const std::string& light_path = "/World/defaultLight"; - pxr::UsdLuxDistantLight::Define(stage_, pxr::SdfPath(light_path)); - // set the light's orientation - pxr::UsdGeomXform xform(stage_->GetPrimAtPath(pxr::SdfPath(light_path))); - pxr::GfVec3f light_direction(0.0f, 0.0f, -1.0f); - //xform.AddRotateOp(pxr::UsdGeomXformOp::PrecisionFloat, pxr::UsdGeomXformOp::TypeRotateXYZ).Set(pxr::GfRotation(pxr::GfVec3f(0.0f, 1.0f, 0.0f), light_direction).GetQuaternion()); - // set the light's color - pxr::UsdLuxDistantLight light(stage_->GetPrimAtPath(pxr::SdfPath(light_path))); - light.CreateIntensityAttr().Set(1000.0f); - light.CreateColorAttr().Set(pxr::GfVec3f(1.0f, 1.0f, 1.0f)); + const std::string& light_path = "/World/defaultLight"; + pxr::UsdLuxDistantLight::Define(stage_, pxr::SdfPath(light_path)); + pxr::UsdGeomXform xform(stage_->GetPrimAtPath(pxr::SdfPath(light_path))); + pxr::GfVec3f light_direction(0.0f, 0.0f, -1.0f); + pxr::UsdLuxDistantLight light(stage_->GetPrimAtPath(pxr::SdfPath(light_path))); + light.CreateIntensityAttr().Set(1000.0f); + light.CreateColorAttr().Set(pxr::GfVec3f(1.0f, 1.0f, 1.0f)); } -std::vector USDSerializer::createMaterials(const pxr::UsdGeomMesh& mesh, - const std::vector& styles) +std::vector USDSerializer::createMaterials(const std::vector& styles) { - std::vector materials {}; + if(styles.empty()) + throw std::runtime_error("No styles to create materials from"); - for(auto style : styles) { - std::string path("/Looks/" + sanitize(style.original_name())); - auto material = pxr::UsdShadeMaterial::Define(stage_, pxr::SdfPath(path)); - auto shader = pxr::UsdShadeShader::Define(stage_, pxr::SdfPath(path + "/Shader")); - shader.CreateIdAttr().Set(pxr::TfToken("UsdPreviewSurface")); + std::vector materials {}; - float rgba[4] { 0.18f, 0.18f, 0.18f, 1.0f }; - if (style.hasDiffuse()) - for (int i = 0; i < 3; ++i) - rgba[i] = static_cast(style.diffuse()[i]); - shader.CreateInput(pxr::TfToken("diffuseColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2])); + for(auto style : styles) { + std::string material_path(style.original_name()); + usd_utils::toPath(material_path); - if(style.hasTransparency()) - rgba[3] -= style.transparency(); - shader.CreateInput(pxr::TfToken("opacity"), pxr::SdfValueTypeNames->Float).Set(rgba[3]); + if(materials_.find(material_path) != materials_.end()) { + materials.push_back(materials_[material_path]); + continue; + } - if(style.hasSpecular()) { - for (int i = 0; i < 3; ++i) - rgba[i] = static_cast(style.specular()[i]); - shader.CreateInput(pxr::TfToken("useSpecularWorkflow"), pxr::SdfValueTypeNames->Int).Set(1); - } else { - shader.CreateInput(pxr::TfToken("useSpecularWorkflow"), pxr::SdfValueTypeNames->Int).Set(0); - } - shader.CreateInput(pxr::TfToken("specularColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2])); + const std::string path("/Looks/" + material_path); + auto material = pxr::UsdShadeMaterial::Define(stage_, pxr::SdfPath(path)); + auto shader = pxr::UsdShadeShader::Define(stage_, pxr::SdfPath(path + "/Shader")); + shader.CreateIdAttr().Set(pxr::TfToken("UsdPreviewSurface")); - material.CreateSurfaceOutput().ConnectToSource(shader.ConnectableAPI(), pxr::TfToken("surface")); - materials.push_back(material); - } - return materials; -} + float rgba[4] { 0.18f, 0.18f, 0.18f, 1.0f }; + if (style.hasDiffuse()) + for (int i = 0; i < 3; ++i) + rgba[i] = static_cast(style.diffuse()[i]); + shader.CreateInput(pxr::TfToken("diffuseColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2])); -bool USDSerializer::ready() { - return ready_; + if(style.hasTransparency()) + rgba[3] -= style.transparency(); + shader.CreateInput(pxr::TfToken("opacity"), pxr::SdfValueTypeNames->Float).Set(rgba[3]); + + if(style.hasSpecular()) { + for (int i = 0; i < 3; ++i) + rgba[i] = static_cast(style.specular()[i]); + shader.CreateInput(pxr::TfToken("useSpecularWorkflow"), pxr::SdfValueTypeNames->Int).Set(1); + } else { + shader.CreateInput(pxr::TfToken("useSpecularWorkflow"), pxr::SdfValueTypeNames->Int).Set(0); + } + shader.CreateInput(pxr::TfToken("specularColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2])); + + material.CreateSurfaceOutput().ConnectToSource(shader.ConnectableAPI(), pxr::TfToken("surface")); + materials.push_back(material); + materials_[material_path] = material; + } + + return materials; } void USDSerializer::writeHeader() { - stage_->GetRootLayer()->SetComment("File generated by IfcOpenShell " + std::string(IFCOPENSHELL_VERSION)); + stage_->GetRootLayer()->SetComment("File generated by IfcOpenShell " + std::string(IFCOPENSHELL_VERSION)); } void USDSerializer::write(const IfcGeom::TriangulationElement* o) { - const IfcGeom::Representation::Triangulation& mesh = o->geometry(); - auto verts = mesh.verts(); - auto faces = mesh.faces(); - const std::vector& m = o->transformation().matrix().data(); + const IfcGeom::Representation::Triangulation& mesh = o->geometry(); + const auto verts = mesh.verts(); + const auto faces = mesh.faces(); + const auto material_ids = mesh.material_ids(); + const std::vector& m = o->transformation().matrix().data(); - if ( mesh.material_ids().empty() || verts.empty() || faces.empty() ) + if (material_ids.empty() || verts.empty() || faces.empty()) return; - - std::string name = o->name(); - if(name.empty()) { - name = "Unnamed_" + std::to_string(unnamed_count_); - unnamed_count_++; - } else { - name = sanitize(name) + std::to_string(o->id()); - } - pxr::UsdGeomMesh usd_mesh = pxr::UsdGeomMesh::Define(stage_, pxr::SdfPath("/World/" + name)); - usd_mesh.AddTranslateOp().Set(pxr::GfVec3d(m[9], m[10], m[11])); + std::string name = o->name(); + if(name.empty()) { + name = "UnNamed"; + } else { + name = usd_utils::toPath(name); + } + name += "_" + std::to_string(o->id()); + auto usd_mesh = pxr::UsdGeomMesh::Define(stage_, pxr::SdfPath("/World/" + name)); - pxr::VtVec3fArray points; - for(std::size_t i = 0; i < verts.size(); i+=3) { - points.push_back(pxr::GfVec3f(static_cast(verts[i] * m[0] + verts[i+1] * m[3] + verts[i+2] * m[6]), - static_cast(verts[i] * m[1] + verts[i+1] * m[4] + verts[i+2] * m[7]), - static_cast(verts[i] * m[2] + verts[i+1] * m[5] + verts[i+2] * m[8]))); - } - usd_mesh.CreatePointsAttr().Set(points); + usd_mesh.AddTranslateOp().Set(pxr::GfVec3d(m[9], m[10], m[11])); - usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_utils::toVtArray(faces)); - usd_mesh.CreateFaceVertexCountsAttr().Set(pxr::VtArray((int) faces.size() / 3, 3)); + pxr::VtVec3fArray points; + for(std::size_t i = 0; i < verts.size(); i+=3) { + points.push_back(pxr::GfVec3f(static_cast(verts[i] * m[0] + verts[i+1] * m[3] + verts[i+2] * m[6]), + static_cast(verts[i] * m[1] + verts[i+1] * m[4] + verts[i+2] * m[7]), + static_cast(verts[i] * m[2] + verts[i+1] * m[5] + verts[i+2] * m[8]))); + } + usd_mesh.CreatePointsAttr().Set(points); - pxr::VtVec3fArray normals; - for (std::vector::const_iterator it = mesh.normals().begin(); it != mesh.normals().end();) - normals.push_back(pxr::GfVec3f(static_cast(*(it++)), static_cast(*(it++)), static_cast(*(it++)))); - usd_mesh.CreateNormalsAttr().Set(normals); + usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_utils::toVtArray(faces)); + usd_mesh.CreateFaceVertexCountsAttr().Set(pxr::VtArray((int) faces.size() / 3, 3)); - auto materials = createMaterials(usd_mesh, mesh.materials()); - pxr::UsdShadeMaterialBindingAPI material_api(usd_mesh); - if(materials.size() > 1) { - auto material_ids = mesh.material_ids(); - std::vector> subsets(materials.size()); - for(int i = 0; i < material_ids.size(); ++i) { - subsets[material_ids[i]].push_back(i); - } - for(std::size_t i = 0; i < subsets.size(); ++i){ - auto subset = material_api.CreateMaterialBindSubset(pxr::TfToken("subset_" + std::to_string(i)), subsets[i]); - pxr::UsdShadeMaterialBindingAPI(subset).Bind(materials[i]); - } - } else { - material_api.Bind(materials[0]); - } + pxr::VtVec3fArray normals; + for (std::vector::const_iterator it = mesh.normals().begin(); it != mesh.normals().end();) + normals.push_back(pxr::GfVec3f(static_cast(*(it++)), static_cast(*(it++)), static_cast(*(it++)))); + usd_mesh.CreateNormalsAttr().Set(normals); + + auto materials = createMaterials(mesh.materials()); + pxr::UsdShadeMaterialBindingAPI material_api(usd_mesh); + if(materials.size() > 1) { + std::vector> subsets(materials.size()); + for(int i = 0; i < material_ids.size(); ++i) + subsets[material_ids[i]].push_back(i); + + for(std::size_t i = 0; i < subsets.size(); ++i){ + auto subset = material_api.CreateMaterialBindSubset(pxr::TfToken("subset_" + std::to_string(i)), subsets[i]); + pxr::UsdShadeMaterialBindingAPI(subset).Bind(materials[i]); + } + } else { + material_api.Bind(materials[0]); + } } void USDSerializer::finalize() { - stage_->Save(); + stage_->Save(); } #endif // WITH_USD \ No newline at end of file diff --git a/src/serializers/USDSerializer.h b/src/serializers/USDSerializer.h index 2d09c303aa..ca950961f1 100644 --- a/src/serializers/USDSerializer.h +++ b/src/serializers/USDSerializer.h @@ -41,6 +41,13 @@ #include namespace usd_utils { + inline std::string toPath(std::string& s) { + std::replace_if(s.begin(), s.end(), + [](char c) { return c < 48 || (c < 65 && c > 57) || (c < 97 && c > 90) || c > 122; }, + '_'); + return s; + } + template pxr::VtArray toVtArray(const std::vector& vec) { auto array = pxr::VtArray(vec.size()); @@ -52,26 +59,17 @@ namespace usd_utils { class SERIALIZERS_API USDSerializer : public WriteOnlyGeometrySerializer { private: - std::string filename_; bool ready_ = false; + const std::string filename_; pxr::UsdStageRefPtr stage_; - std::size_t unnamed_count_ = 0; - std::map meshes_; std::map materials_; - inline std::string sanitize(std::string s) { - std::replace_if(s.begin(), s.end(), - [](char c) { return c > 122 || c < 48 || (c > 57 && c < 65) || (c > 90 && c < 97); }, - '_'); - return s; - } - - std::vector createMaterials(const pxr::UsdGeomMesh&, const std::vector&); + std::vector createMaterials(const std::vector&); void createLighting(); public: USDSerializer(const std::string&, const SerializerSettings&); virtual ~USDSerializer(); - bool ready(); + bool ready() { return ready_; } void writeHeader(); void write(const IfcGeom::TriangulationElement*); void write(const IfcGeom::BRepElement*) {}