Skip to content

Commit

Permalink
Assimp: new smarter transparent polygon sorter algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
jlblancoc committed Sep 21, 2024
1 parent fb7ec66 commit 605ca3c
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 24 deletions.
53 changes: 32 additions & 21 deletions apps/SceneViewer3D/_DSceneViewerMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,32 +891,43 @@ void _DSceneViewerFrame::OntimLoadFileCmdLineTrigger(wxTimerEvent&)
{
timLoadFileCmdLine.Stop(); // One shot only.
// Open file if passed by the command line:
if (!global_fileToOpen.empty())
if (global_fileToOpen.empty()) return;

if (mrpt::system::strCmpI(
"3Dscene", mrpt::system::extractFileExtension(global_fileToOpen, true /*ignore .gz*/)))
{
if (mrpt::system::strCmpI(
"3Dscene", mrpt::system::extractFileExtension(global_fileToOpen, true /*ignore .gz*/)))
loadFromFile(global_fileToOpen);
}
else
{
std::cout << "Filename extension does not match `3Dscene`, "
"importing as an ASSIMP model...\n";
try
{
loadFromFile(global_fileToOpen);
auto obj3D = mrpt::opengl::CAssimpModel::Create();
obj3D->loadScene(global_fileToOpen);
// obj3D->setPose(mrpt::math::TPose3D(0, 0, 0, .0_deg,
// 0._deg, 90.0_deg));
m_canvas->getOpenGLSceneRef()->insert(obj3D);

// TODO: make optional?
obj3D->split_triangles_rendering_bbox(0.25);

m_canvas->Refresh();
}
else
catch (const std::exception& e)
{
std::cout << "Filename extension does not match `3Dscene`, "
"importing as an ASSIMP model...\n";
try
{
auto obj3D = mrpt::opengl::CAssimpModel::Create();
obj3D->loadScene(global_fileToOpen);
// obj3D->setPose(mrpt::math::TPose3D(0, 0, 0, .0_deg,
// 0._deg, 90.0_deg));
m_canvas->getOpenGLSceneRef()->insert(obj3D);
std::cerr << mrpt::exception_to_str(e) << std::endl;
wxMessageBox(mrpt::exception_to_str(e), _("Exception"), wxOK, this);
}
}

m_canvas->Refresh();
}
catch (const std::exception& e)
{
std::cerr << mrpt::exception_to_str(e) << std::endl;
wxMessageBox(mrpt::exception_to_str(e), _("Exception"), wxOK, this);
}
// Enable shadows?
if (0)
{
if (auto vw = m_canvas->getOpenGLSceneRef()->getViewport(); vw)
{
vw->enableShadowCasting();
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion doc/source/doxygen-docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
\page changelog Change Log

# Version 2.14.1: UNRELEASED
(None yet)
- Changes in libraries:
- \ref mrpt_opengl_grp:
- New method mrpt::opengl::CAssimpModel::split_triangles_rendering_bbox() to enable a new feature in Assimp 3D models: splitting into smaller triangle sets for correct z-ordering of semitransparent objects; e.g. required for trees with masked leaves.

# Version 2.14.0: Released Sep 15th, 2024
- Changes in libraries:
Expand Down
11 changes: 11 additions & 0 deletions libs/opengl/include/mrpt/opengl/CAssimpModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ class CAssimpModel :

mrpt::math::TBoundingBoxf internalBoundingBoxLocal() const override;

/** Enable (or disable if set to .0f) a feature in which textured triangles
* are split into different renderizable smaller objects.
* This is required only for semitransparent objects with overlaping regions.
*/
void split_triangles_rendering_bbox(const float bbox_size);
[[nodiscard]] float split_triangles_rendering_bbox() const
{
return m_split_triangles_rendering_bbox;
}

struct TInfoPerTexture
{
// indices in \a m_texturedObjects. string::npos for non-initialized
Expand Down Expand Up @@ -152,6 +162,7 @@ class CAssimpModel :
mutable std::vector<CSetOfTexturedTriangles::Ptr> m_texturedObjects;
bool m_verboseLoad = false;
bool m_ignoreMaterialColor = false;
float m_split_triangles_rendering_bbox = .0f;

void recursive_render(
const aiScene* sc,
Expand Down
74 changes: 72 additions & 2 deletions libs/opengl/src/CAssimpModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#endif

#include <mrpt/core/lock_helper.h>
#include <mrpt/core/round.h>
#include <mrpt/opengl/opengl_api.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/filesystem.h>
Expand Down Expand Up @@ -273,8 +274,65 @@ void CAssimpModel::onUpdateBuffers_all()

process_textures(m_assimp_scene->scene);

// Model -> 3D primitives:
const auto transf = mrpt::poses::CPose3D();
recursive_render(m_assimp_scene->scene, m_assimp_scene->scene->mRootNode, transf, re);

// Handle split:
if (m_split_triangles_rendering_bbox > .0f)
{
const float voxel = m_split_triangles_rendering_bbox;

ASSERT_EQUAL_(m_texturedObjects.size(), m_textureIdMap.size());
const std::vector<CSetOfTexturedTriangles::Ptr> origTexturedObjects = m_texturedObjects;
m_texturedObjects.clear();

std::unordered_map<int64_t, std::map<size_t /*textId*/, CSetOfTexturedTriangles::Ptr>>
newTextObjs;

for (size_t textId = 0; textId < m_textureIdMap.size(); textId++)
{
const auto& glTris = origTexturedObjects.at(textId);
const std::vector<mrpt::opengl::TTriangle>& iTris = glTris->shaderTexturedTrianglesBuffer();
for (const auto& t : iTris)
{
const auto midPt = 0.333f * (t.vertices[0].xyzrgba.pt + t.vertices[1].xyzrgba.pt +
t.vertices[2].xyzrgba.pt);
// hash for "voxels":
const int64_t vxlCoord = mrpt::round(midPt.x / voxel) + //
mrpt::round(midPt.y / voxel) * 10'000 + //
mrpt::round(midPt.z / voxel) * 100'000'000;

auto& trgObj = newTextObjs[vxlCoord][textId];
if (!trgObj)
{
// Create
trgObj = CSetOfTexturedTriangles::Create();

// Set representative point: the MOST FUNDAMENTAL property
// to ensure proper z ordering for transparent rendering:
trgObj->setLocalRepresentativePoint(midPt);

// copy texture
const auto& texRGB = glTris->getTextureImage();
const auto& texAlpha = glTris->getTextureAlphaImage();
if (!texAlpha.isEmpty())
trgObj->assignImage(texRGB, texAlpha);
else
trgObj->assignImage(texRGB);
}
// Add triangle:
trgObj->insertTriangle(t);
}
}

// replace list of objects:
m_texturedObjects.clear();
for (const auto& m : newTextObjs)
for (const auto& [k, v] : m.second) //
m_texturedObjects.push_back(v);
} // end: split into subobjects:

#endif
}

Expand All @@ -297,14 +355,15 @@ void CAssimpModel::enqueueForRenderRecursive(
mrpt::opengl::enqueueForRendering(lst, state, rq, wholeInView, is1stShadowMapPass);
}

uint8_t CAssimpModel::serializeGetVersion() const { return 2; }
uint8_t CAssimpModel::serializeGetVersion() const { return 3; }
void CAssimpModel::serializeTo(mrpt::serialization::CArchive& out) const
{
writeToStreamRender(out);
#if (MRPT_HAS_OPENGL_GLUT || MRPT_HAS_EGL) && MRPT_HAS_ASSIMP
const bool empty = m_assimp_scene->scene == nullptr;
out << empty;
out << m_modelPath; // v2
out << m_modelPath; // v2
out << m_split_triangles_rendering_bbox; // v3
if (!empty)
{
#if 0
Expand Down Expand Up @@ -348,6 +407,8 @@ void CAssimpModel::serializeFrom(mrpt::serialization::CArchive& in, uint8_t vers
{
const bool empty = in.ReadAs<bool>();
in >> m_modelPath;
if (version >= 3) in >> m_split_triangles_rendering_bbox;

if (!empty)
{
const auto blobSize = in.ReadAs<uint32_t>();
Expand Down Expand Up @@ -439,6 +500,7 @@ void CAssimpModel::after_load_model()
// Evaluate overall bbox:
{
aiVector3D scene_min, scene_max;
ASSERT_(m_assimp_scene->scene);
get_bounding_box(m_assimp_scene->scene, &scene_min, &scene_max);
m_bbox_min.x = scene_min.x;
m_bbox_min.y = scene_min.y;
Expand All @@ -460,6 +522,14 @@ auto CAssimpModel::internalBoundingBoxLocal() const -> mrpt::math::TBoundingBoxf
return mrpt::math::TBoundingBoxf::FromUnsortedPoints(m_bbox_min, m_bbox_max);
}

void CAssimpModel::split_triangles_rendering_bbox(const float bbox_size)
{
m_split_triangles_rendering_bbox = bbox_size;

CRenderizable::notifyChange();
if (m_assimp_scene->scene) after_load_model();
}

bool CAssimpModel::traceRay(
[[maybe_unused]] const mrpt::poses::CPose3D& o, [[maybe_unused]] double& dist) const
{
Expand Down

0 comments on commit 605ca3c

Please sign in to comment.