filename bug

This commit is contained in:
D4ve-R
2023-05-15 11:52:36 +02:00
parent fca79ddb6c
commit b9f2dbb0b3
2 changed files with 132 additions and 113 deletions
+122 -101
View File
@@ -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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifdef WITH_USD #ifdef WITH_USD
#include "USDSerializer.h" #include "USDSerializer.h"
#include "pxr/base/tf/token.h"
#include "pxr/base/gf/vec3f.h" #include "pxr/base/gf/vec3f.h"
#include "pxr/base/gf/rotation.h"
#include "pxr/usd/usdGeom/xform.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/usdGeom/scope.h"
#include "pxr/usd/usdLux/distantLight.h" #include "pxr/usd/usdLux/distantLight.h"
#include "pxr/usd/usdShade/shader.h" #include "pxr/usd/usdShade/shader.h"
#include "pxr/usd/usdShade/tokens.h"
#include "pxr/usd/usdShade/materialBindingAPI.h" #include "pxr/usd/usdShade/materialBindingAPI.h"
#include "pxr/usd/usdShade/connectableAPI.h"
USDSerializer::USDSerializer(const std::string& out_filename, const SerializerSettings& settings): USDSerializer::USDSerializer(const std::string& out_filename, const SerializerSettings& settings):
WriteOnlyGeometrySerializer(settings), WriteOnlyGeometrySerializer(settings),
filename_(out_filename) filename_(out_filename)
{ {
// create a new stage // why does this not work with just the filename ???
stage_ = pxr::UsdStage::CreateNew(filename_ + ".usda"); stage_ = pxr::UsdStage::CreateNew(filename_ + ".usda");
pxr::UsdGeomXform::Define(stage_, pxr::SdfPath("/World")); if(!stage_)
pxr::UsdGeomScope::Define(stage_, pxr::SdfPath("/Looks")); throw std::runtime_error("Could not create USD stage");
createLighting();
ready_ = true; 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() { USDSerializer::~USDSerializer() {
@@ -33,118 +50,122 @@ USDSerializer::~USDSerializer() {
} }
void USDSerializer::createLighting() { void USDSerializer::createLighting() {
// create a distant light const std::string& light_path = "/World/defaultLight";
const std::string& light_path = "/World/defaultLight"; pxr::UsdLuxDistantLight::Define(stage_, pxr::SdfPath(light_path));
pxr::UsdLuxDistantLight::Define(stage_, pxr::SdfPath(light_path)); pxr::UsdGeomXform xform(stage_->GetPrimAtPath(pxr::SdfPath(light_path)));
// set the light's orientation pxr::GfVec3f light_direction(0.0f, 0.0f, -1.0f);
pxr::UsdGeomXform xform(stage_->GetPrimAtPath(pxr::SdfPath(light_path))); pxr::UsdLuxDistantLight light(stage_->GetPrimAtPath(pxr::SdfPath(light_path)));
pxr::GfVec3f light_direction(0.0f, 0.0f, -1.0f); light.CreateIntensityAttr().Set(1000.0f);
//xform.AddRotateOp(pxr::UsdGeomXformOp::PrecisionFloat, pxr::UsdGeomXformOp::TypeRotateXYZ).Set(pxr::GfRotation(pxr::GfVec3f(0.0f, 1.0f, 0.0f), light_direction).GetQuaternion()); light.CreateColorAttr().Set(pxr::GfVec3f(1.0f, 1.0f, 1.0f));
// 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));
} }
std::vector<pxr::UsdShadeMaterial> USDSerializer::createMaterials(const pxr::UsdGeomMesh& mesh, std::vector<pxr::UsdShadeMaterial> USDSerializer::createMaterials(const std::vector<IfcGeom::Material>& styles)
const std::vector<IfcGeom::Material>& styles)
{ {
std::vector<pxr::UsdShadeMaterial> materials {}; if(styles.empty())
throw std::runtime_error("No styles to create materials from");
for(auto style : styles) { std::vector<pxr::UsdShadeMaterial> materials {};
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"));
float rgba[4] { 0.18f, 0.18f, 0.18f, 1.0f }; for(auto style : styles) {
if (style.hasDiffuse()) std::string material_path(style.original_name());
for (int i = 0; i < 3; ++i) usd_utils::toPath(material_path);
rgba[i] = static_cast<float>(style.diffuse()[i]);
shader.CreateInput(pxr::TfToken("diffuseColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2]));
if(style.hasTransparency()) if(materials_.find(material_path) != materials_.end()) {
rgba[3] -= style.transparency(); materials.push_back(materials_[material_path]);
shader.CreateInput(pxr::TfToken("opacity"), pxr::SdfValueTypeNames->Float).Set(rgba[3]); continue;
}
if(style.hasSpecular()) { const std::string path("/Looks/" + material_path);
for (int i = 0; i < 3; ++i) auto material = pxr::UsdShadeMaterial::Define(stage_, pxr::SdfPath(path));
rgba[i] = static_cast<float>(style.specular()[i]); auto shader = pxr::UsdShadeShader::Define(stage_, pxr::SdfPath(path + "/Shader"));
shader.CreateInput(pxr::TfToken("useSpecularWorkflow"), pxr::SdfValueTypeNames->Int).Set(1); shader.CreateIdAttr().Set(pxr::TfToken("UsdPreviewSurface"));
} 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")); float rgba[4] { 0.18f, 0.18f, 0.18f, 1.0f };
materials.push_back(material); if (style.hasDiffuse())
} for (int i = 0; i < 3; ++i)
return materials; rgba[i] = static_cast<float>(style.diffuse()[i]);
} shader.CreateInput(pxr::TfToken("diffuseColor"), pxr::SdfValueTypeNames->Color3f).Set(pxr::GfVec3f(rgba[0], rgba[1], rgba[2]));
bool USDSerializer::ready() { if(style.hasTransparency())
return ready_; 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<float>(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() { 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) { void USDSerializer::write(const IfcGeom::TriangulationElement* o) {
const IfcGeom::Representation::Triangulation& mesh = o->geometry(); const IfcGeom::Representation::Triangulation& mesh = o->geometry();
auto verts = mesh.verts(); const auto verts = mesh.verts();
auto faces = mesh.faces(); const auto faces = mesh.faces();
const std::vector<double>& m = o->transformation().matrix().data(); const auto material_ids = mesh.material_ids();
const std::vector<double>& m = o->transformation().matrix().data();
if ( mesh.material_ids().empty() || verts.empty() || faces.empty() ) if (material_ids.empty() || verts.empty() || faces.empty())
return; 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; usd_mesh.AddTranslateOp().Set(pxr::GfVec3d(m[9], m[10], m[11]));
for(std::size_t i = 0; i < verts.size(); i+=3) {
points.push_back(pxr::GfVec3f(static_cast<float>(verts[i] * m[0] + verts[i+1] * m[3] + verts[i+2] * m[6]),
static_cast<float>(verts[i] * m[1] + verts[i+1] * m[4] + verts[i+2] * m[7]),
static_cast<float>(verts[i] * m[2] + verts[i+1] * m[5] + verts[i+2] * m[8])));
}
usd_mesh.CreatePointsAttr().Set(points);
usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_utils::toVtArray(faces)); pxr::VtVec3fArray points;
usd_mesh.CreateFaceVertexCountsAttr().Set(pxr::VtArray<int>((int) faces.size() / 3, 3)); for(std::size_t i = 0; i < verts.size(); i+=3) {
points.push_back(pxr::GfVec3f(static_cast<float>(verts[i] * m[0] + verts[i+1] * m[3] + verts[i+2] * m[6]),
static_cast<float>(verts[i] * m[1] + verts[i+1] * m[4] + verts[i+2] * m[7]),
static_cast<float>(verts[i] * m[2] + verts[i+1] * m[5] + verts[i+2] * m[8])));
}
usd_mesh.CreatePointsAttr().Set(points);
pxr::VtVec3fArray normals; usd_mesh.CreateFaceVertexIndicesAttr().Set(usd_utils::toVtArray(faces));
for (std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end();) usd_mesh.CreateFaceVertexCountsAttr().Set(pxr::VtArray<int>((int) faces.size() / 3, 3));
normals.push_back(pxr::GfVec3f(static_cast<float>(*(it++)), static_cast<float>(*(it++)), static_cast<float>(*(it++))));
usd_mesh.CreateNormalsAttr().Set(normals);
auto materials = createMaterials(usd_mesh, mesh.materials()); pxr::VtVec3fArray normals;
pxr::UsdShadeMaterialBindingAPI material_api(usd_mesh); for (std::vector<double>::const_iterator it = mesh.normals().begin(); it != mesh.normals().end();)
if(materials.size() > 1) { normals.push_back(pxr::GfVec3f(static_cast<float>(*(it++)), static_cast<float>(*(it++)), static_cast<float>(*(it++))));
auto material_ids = mesh.material_ids(); usd_mesh.CreateNormalsAttr().Set(normals);
std::vector<pxr::VtArray<int>> subsets(materials.size());
for(int i = 0; i < material_ids.size(); ++i) { auto materials = createMaterials(mesh.materials());
subsets[material_ids[i]].push_back(i); pxr::UsdShadeMaterialBindingAPI material_api(usd_mesh);
} if(materials.size() > 1) {
for(std::size_t i = 0; i < subsets.size(); ++i){ std::vector<pxr::VtArray<int>> subsets(materials.size());
auto subset = material_api.CreateMaterialBindSubset(pxr::TfToken("subset_" + std::to_string(i)), subsets[i]); for(int i = 0; i < material_ids.size(); ++i)
pxr::UsdShadeMaterialBindingAPI(subset).Bind(materials[i]); subsets[material_ids[i]].push_back(i);
}
} else { for(std::size_t i = 0; i < subsets.size(); ++i){
material_api.Bind(materials[0]); 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() { void USDSerializer::finalize() {
stage_->Save(); stage_->Save();
} }
#endif // WITH_USD #endif // WITH_USD
+10 -12
View File
@@ -41,6 +41,13 @@
#include <map> #include <map>
namespace usd_utils { 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<typename T> template<typename T>
pxr::VtArray<T> toVtArray(const std::vector<T>& vec) { pxr::VtArray<T> toVtArray(const std::vector<T>& vec) {
auto array = pxr::VtArray<T>(vec.size()); auto array = pxr::VtArray<T>(vec.size());
@@ -52,26 +59,17 @@ namespace usd_utils {
class SERIALIZERS_API USDSerializer : public WriteOnlyGeometrySerializer { class SERIALIZERS_API USDSerializer : public WriteOnlyGeometrySerializer {
private: private:
std::string filename_;
bool ready_ = false; bool ready_ = false;
const std::string filename_;
pxr::UsdStageRefPtr stage_; pxr::UsdStageRefPtr stage_;
std::size_t unnamed_count_ = 0;
std::map<std::string, pxr::UsdGeomMesh> meshes_;
std::map<std::string, pxr::UsdShadeMaterial> materials_; std::map<std::string, pxr::UsdShadeMaterial> materials_;
inline std::string sanitize(std::string s) { std::vector<pxr::UsdShadeMaterial> createMaterials(const std::vector<IfcGeom::Material>&);
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<pxr::UsdShadeMaterial> createMaterials(const pxr::UsdGeomMesh&, const std::vector<IfcGeom::Material>&);
void createLighting(); void createLighting();
public: public:
USDSerializer(const std::string&, const SerializerSettings&); USDSerializer(const std::string&, const SerializerSettings&);
virtual ~USDSerializer(); virtual ~USDSerializer();
bool ready(); bool ready() { return ready_; }
void writeHeader(); void writeHeader();
void write(const IfcGeom::TriangulationElement*); void write(const IfcGeom::TriangulationElement*);
void write(const IfcGeom::BRepElement*) {} void write(const IfcGeom::BRepElement*) {}