implement fast mesh rendering for Qt5 port (7x faster)
This commit is contained in:
@@ -130,6 +130,7 @@ PyMOD_INIT_FUNC(MeshGui)
|
||||
MeshGui::SoFCMeshObjectShape ::initClass();
|
||||
MeshGui::SoFCMeshSegmentShape ::initClass();
|
||||
MeshGui::SoFCMeshObjectBoundary ::initClass();
|
||||
MeshGui::SoFCMaterialEngine ::initClass();
|
||||
MeshGui::SoFCIndexedFaceSet ::initClass();
|
||||
MeshGui::SoFCMeshPickNode ::initClass();
|
||||
MeshGui::SoFCMeshGridNode ::initClass();
|
||||
|
||||
@@ -450,6 +450,7 @@ void CmdMeshExport::activated(int)
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.ast)").arg(QObject::tr("ASCII STL")), "AST");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.bms)").arg(QObject::tr("Binary Mesh")), "BMS");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.obj)").arg(QObject::tr("Alias Mesh")), "OBJ");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.smf)").arg(QObject::tr("Simple Model Format")), "SMF");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.off)").arg(QObject::tr("Object File Format")), "OFF");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.iv)").arg(QObject::tr("Inventor V2.1 ascii")), "IV");
|
||||
ext << qMakePair<QString, QByteArray>(QString::fromLatin1("%1 (*.x3d)").arg(QObject::tr("X3D Extensible 3D")), "X3D");
|
||||
|
||||
@@ -329,21 +329,7 @@ void MeshSelection::invertSelection()
|
||||
{
|
||||
std::list<ViewProviderMesh*> views = getViewProviders();
|
||||
for (std::list<ViewProviderMesh*>::iterator it = views.begin(); it != views.end(); ++it) {
|
||||
Mesh::Feature* mf = static_cast<Mesh::Feature*>((*it)->getObject());
|
||||
const Mesh::MeshObject* mo = mf->Mesh.getValuePtr();
|
||||
const MeshCore::MeshFacetArray& faces = mo->getKernel().GetFacets();
|
||||
unsigned long num_notsel = std::count_if(faces.begin(), faces.end(),
|
||||
std::bind2nd(MeshCore::MeshIsNotFlag<MeshCore::MeshFacet>(),
|
||||
MeshCore::MeshFacet::SELECTED));
|
||||
std::vector<unsigned long> notselect;
|
||||
notselect.reserve(num_notsel);
|
||||
MeshCore::MeshFacetArray::_TConstIterator beg = faces.begin();
|
||||
MeshCore::MeshFacetArray::_TConstIterator end = faces.end();
|
||||
for (MeshCore::MeshFacetArray::_TConstIterator jt = beg; jt != end; ++jt) {
|
||||
if (!jt->IsFlag(MeshCore::MeshFacet::SELECTED))
|
||||
notselect.push_back(jt-beg);
|
||||
}
|
||||
(*it)->setSelection(notselect);
|
||||
(*it)->invertSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,12 @@
|
||||
# include <Inventor/bundles/SoMaterialBundle.h>
|
||||
# include <Inventor/elements/SoCoordinateElement.h>
|
||||
# include <Inventor/elements/SoGLCoordinateElement.h>
|
||||
# include <Inventor/elements/SoGLLazyElement.h>
|
||||
# include <Inventor/elements/SoMaterialBindingElement.h>
|
||||
# include <Inventor/elements/SoNormalBindingElement.h>
|
||||
# include <Inventor/elements/SoProjectionMatrixElement.h>
|
||||
# include <Inventor/elements/SoViewingMatrixElement.h>
|
||||
# include <Inventor/errors/SoDebugError.h>
|
||||
#endif
|
||||
|
||||
#include <Inventor/C/glue/gl.h>
|
||||
@@ -49,11 +51,332 @@
|
||||
#include <Gui/SoFCInteractiveElement.h>
|
||||
#include <Gui/SoFCSelectionAction.h>
|
||||
#include "SoFCIndexedFaceSet.h"
|
||||
#include <QtOpenGL.h>
|
||||
|
||||
#ifdef HAVE_QT5_OPENGL
|
||||
#define RENDER_GL_VAO
|
||||
#endif
|
||||
//#define RENDER_GLARRAYS
|
||||
|
||||
#ifdef RENDER_GL_VAO
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLFunctions>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
using namespace MeshGui;
|
||||
|
||||
#if defined RENDER_GL_VAO
|
||||
class MeshRenderer::Private : protected QOpenGLFunctions {
|
||||
public:
|
||||
QOpenGLBuffer vertices;
|
||||
QOpenGLBuffer indices;
|
||||
const SbColor * pcolors;
|
||||
SoMaterialBindingElement::Binding matbinding;
|
||||
|
||||
//#define RENDER_GLARRAYS
|
||||
Private();
|
||||
void generateGLArrays(SoMaterialBindingElement::Binding matbind,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index);
|
||||
void renderFacesGLArray(SoGLRenderAction*);
|
||||
void renderCoordsGLArray(SoGLRenderAction *action);
|
||||
};
|
||||
|
||||
MeshRenderer::Private::Private()
|
||||
: vertices(QOpenGLBuffer::VertexBuffer)
|
||||
, indices(QOpenGLBuffer::IndexBuffer)
|
||||
, pcolors(0)
|
||||
, matbinding(SoMaterialBindingElement::OVERALL)
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
vertices.create();
|
||||
indices.create();
|
||||
|
||||
vertices.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
indices.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
}
|
||||
|
||||
void MeshRenderer::Private::generateGLArrays(SoMaterialBindingElement::Binding matbind,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index)
|
||||
{
|
||||
if (vertex.empty() || index.empty())
|
||||
return;
|
||||
vertices.bind();
|
||||
vertices.allocate(&(vertex[0]),
|
||||
vertex.size() * sizeof(float));
|
||||
vertices.release();
|
||||
|
||||
indices.bind();
|
||||
indices.allocate(&(index[0]),
|
||||
index.size() * sizeof(int32_t));
|
||||
indices.release();
|
||||
this->matbinding = matbind;
|
||||
}
|
||||
|
||||
void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction *)
|
||||
{
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
vertices.bind();
|
||||
indices.bind();
|
||||
|
||||
if (matbinding != SoMaterialBindingElement::OVERALL)
|
||||
glInterleavedArrays(GL_C4F_N3F_V3F, 0, 0);
|
||||
else
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, 0);
|
||||
glDrawElements(GL_TRIANGLES, indices.size() / sizeof(uint32_t),
|
||||
GL_UNSIGNED_INT, NULL);
|
||||
|
||||
vertices.release();
|
||||
indices.release();
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
|
||||
void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction *)
|
||||
{
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
vertices.bind();
|
||||
indices.bind();
|
||||
|
||||
if (matbinding != SoMaterialBindingElement::OVERALL)
|
||||
glInterleavedArrays(GL_C4F_N3F_V3F, 0, 0);
|
||||
else
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, 0);
|
||||
glDrawElements(GL_POINTS, indices.size() / sizeof(uint32_t),
|
||||
GL_UNSIGNED_INT, NULL);
|
||||
|
||||
vertices.release();
|
||||
indices.release();
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
#elif defined RENDER_GLARRAYS
|
||||
class MeshRenderer::Private {
|
||||
public:
|
||||
std::vector<int32_t> index_array;
|
||||
std::vector<float> vertex_array;
|
||||
const SbColor * pcolors;
|
||||
SoMaterialBindingElement::Binding matbinding;
|
||||
|
||||
Private()
|
||||
: pcolors(0)
|
||||
, matbinding(SoMaterialBindingElement::OVERALL)
|
||||
{
|
||||
}
|
||||
|
||||
void generateGLArrays(SoMaterialBindingElement::Binding matbind,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index);
|
||||
void renderFacesGLArray(SoGLRenderAction *action);
|
||||
void renderCoordsGLArray(SoGLRenderAction *action);
|
||||
};
|
||||
|
||||
void MeshRenderer::Private::generateGLArrays(SoMaterialBindingElement::Binding matbind,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index)
|
||||
{
|
||||
if (vertex.empty() || index.empty())
|
||||
return;
|
||||
|
||||
this->index_array.resize(0);
|
||||
this->vertex_array.resize(0);
|
||||
|
||||
this->index_array.swap(index);
|
||||
this->vertex_array.swap(vertex);
|
||||
this->matbinding = matbind;
|
||||
}
|
||||
|
||||
void MeshRenderer::Private::renderFacesGLArray(SoGLRenderAction *action)
|
||||
{
|
||||
#if 0 // use Inventor's coordIndex saves memory but the rendering is very slow then
|
||||
const cc_glglue * glue = cc_glglue_instance(action->getCacheContext());
|
||||
PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)
|
||||
cc_glglue_getprocaddress(glue, "glPrimitiveRestartIndex");
|
||||
|
||||
int cnt = coordIndex.getNum();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// https://www.opengl.org/discussion_boards/archive/index.php/t-180767.html
|
||||
// https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
//glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, coordIndex.getValues(0));
|
||||
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
//glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
#else // Needs more memory but makes it very fast
|
||||
(void)action;
|
||||
int cnt = index_array.size();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (matbinding != SoMaterialBindingElement::OVERALL)
|
||||
glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0]));
|
||||
else
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0]));
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MeshRenderer::Private::renderCoordsGLArray(SoGLRenderAction *)
|
||||
{
|
||||
int cnt = index_array.size();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (matbinding != SoMaterialBindingElement::OVERALL)
|
||||
glInterleavedArrays(GL_C4F_N3F_V3F, 0, &(vertex_array[0]));
|
||||
else
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_POINTS, cnt, GL_UNSIGNED_INT, &(index_array[0]));
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
#else
|
||||
class MeshRenderer::Private {
|
||||
public:
|
||||
const SbColor * pcolors;
|
||||
SoMaterialBindingElement::Binding matbinding;
|
||||
|
||||
Private()
|
||||
: pcolors(0)
|
||||
, matbinding(SoMaterialBindingElement::OVERALL)
|
||||
{
|
||||
}
|
||||
|
||||
void generateGLArrays(SoMaterialBindingElement::Binding,
|
||||
std::vector<float>&, std::vector<int32_t>&)
|
||||
{
|
||||
}
|
||||
void renderFacesGLArray(SoGLRenderAction *)
|
||||
{
|
||||
}
|
||||
void renderCoordsGLArray(SoGLRenderAction *)
|
||||
{
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
MeshRenderer::MeshRenderer()
|
||||
: p(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
MeshRenderer::~MeshRenderer()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
void MeshRenderer::generateGLArrays(SoState* state, SoMaterialBindingElement::Binding matbind,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index)
|
||||
{
|
||||
SoGLLazyElement* gl = SoGLLazyElement::getInstance(state);
|
||||
if (gl) {
|
||||
p->pcolors = gl->getDiffusePointer();
|
||||
}
|
||||
p->generateGLArrays(matbind, vertex, index);
|
||||
}
|
||||
|
||||
// Implementation | FPS
|
||||
// ================================================
|
||||
// drawCoords (every 4th vertex) | 20.0
|
||||
// renderCoordsGLArray (all vertexes) | 20.0
|
||||
//
|
||||
void MeshRenderer::renderCoordsGLArray(SoGLRenderAction *action)
|
||||
{
|
||||
p->renderCoordsGLArray(action);
|
||||
}
|
||||
|
||||
//****************************************************************************
|
||||
// renderFacesGLArray: normal and coord from vertex_array;
|
||||
// no texture, color, highlight or selection but highest possible speed;
|
||||
// all vertices written in one go!
|
||||
//
|
||||
// Benchmark tests with an 256 MB STL file:
|
||||
//
|
||||
// Implementation | FPS
|
||||
// ================================================
|
||||
// OpenInventor (SoIndexedFaceSet) | 3.0
|
||||
// Custom OpenInventor (SoFCMeshObjectShape) | 8.5
|
||||
// With GL_PRIMITIVE_RESTART | 0.9
|
||||
// With GL_PRIMITIVE_RESTART_FIXED_INDEX | 0.9
|
||||
// Without GL_PRIMITIVE_RESTART | 8.5
|
||||
// Vertex-Array-Object (RENDER_GL_VAO) | 60.0
|
||||
void MeshRenderer::renderFacesGLArray(SoGLRenderAction *action)
|
||||
{
|
||||
p->renderFacesGLArray(action);
|
||||
}
|
||||
|
||||
bool MeshRenderer::matchMaterial(SoState* state) const
|
||||
{
|
||||
SoMaterialBindingElement::Binding matbind =
|
||||
SoMaterialBindingElement::get(state);
|
||||
const SbColor * pcolors = 0;
|
||||
SoGLLazyElement* gl = SoGLLazyElement::getInstance(state);
|
||||
if (gl) {
|
||||
pcolors = gl->getDiffusePointer();
|
||||
}
|
||||
return p->matbinding == matbind && p->pcolors == pcolors;
|
||||
}
|
||||
|
||||
bool MeshRenderer::shouldRenderDirectly(bool direct)
|
||||
{
|
||||
#ifdef RENDER_GL_VAO
|
||||
Q_UNUSED(direct);
|
||||
return false;
|
||||
#else
|
||||
return direct;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SO_ENGINE_SOURCE(SoFCMaterialEngine);
|
||||
|
||||
SoFCMaterialEngine::SoFCMaterialEngine()
|
||||
{
|
||||
SO_ENGINE_CONSTRUCTOR(SoFCMaterialEngine);
|
||||
|
||||
SO_ENGINE_ADD_INPUT(diffuseColor, (SbColor(0.0, 0.0, 0.0)));
|
||||
SO_ENGINE_ADD_OUTPUT(trigger, SoSFBool);
|
||||
}
|
||||
|
||||
SoFCMaterialEngine::~SoFCMaterialEngine()
|
||||
{
|
||||
}
|
||||
|
||||
void SoFCMaterialEngine::initClass()
|
||||
{
|
||||
SO_ENGINE_INIT_CLASS(SoFCMaterialEngine, SoEngine, "Engine");
|
||||
}
|
||||
|
||||
void SoFCMaterialEngine::inputChanged(SoField *)
|
||||
{
|
||||
SO_ENGINE_OUTPUT(trigger, SoSFBool, setValue(true));
|
||||
}
|
||||
|
||||
void SoFCMaterialEngine::evaluate()
|
||||
{
|
||||
// do nothing here
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
SO_NODE_SOURCE(SoFCIndexedFaceSet);
|
||||
|
||||
@@ -62,9 +385,13 @@ void SoFCIndexedFaceSet::initClass()
|
||||
SO_NODE_INIT_CLASS(SoFCIndexedFaceSet, SoIndexedFaceSet, "IndexedFaceSet");
|
||||
}
|
||||
|
||||
SoFCIndexedFaceSet::SoFCIndexedFaceSet() : renderTriangleLimit(100000), updateGLArray(false), selectBuf(0)
|
||||
SoFCIndexedFaceSet::SoFCIndexedFaceSet()
|
||||
: renderTriangleLimit(100000)
|
||||
, selectBuf(0)
|
||||
{
|
||||
SO_NODE_CONSTRUCTOR(SoFCIndexedFaceSet);
|
||||
SO_NODE_ADD_FIELD(updateGLArray, (false));
|
||||
updateGLArray.setFieldType(SoField::EVENTOUT_FIELD);
|
||||
setName(SoFCIndexedFaceSet::getClassTypeId().getName());
|
||||
}
|
||||
|
||||
@@ -90,9 +417,15 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action)
|
||||
SoState * state = action->getState();
|
||||
SbBool mode = Gui::SoFCInteractiveElement::get(state);
|
||||
|
||||
#if defined(RENDER_GL_VAO)
|
||||
if (mode == false || render.matchMaterial(state)) {
|
||||
#else
|
||||
unsigned int num = this->coordIndex.getNum()/4;
|
||||
if (mode == false || num <= this->renderTriangleLimit) {
|
||||
#ifdef RENDER_GLARRAYS
|
||||
#endif
|
||||
#if defined (RENDER_GLARRAYS) || defined(RENDER_GL_VAO)
|
||||
|
||||
#if 0
|
||||
SoMaterialBindingElement::Binding matbind =
|
||||
SoMaterialBindingElement::get(state);
|
||||
|
||||
@@ -103,11 +436,26 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action)
|
||||
updateGLArray = false;
|
||||
generateGLArrays(state);
|
||||
}
|
||||
renderFacesGLArray(action);
|
||||
render.renderFacesGLArray(action);
|
||||
}
|
||||
else {
|
||||
inherited::GLRender(action);
|
||||
}
|
||||
#else
|
||||
if (updateGLArray.getValue()) {
|
||||
updateGLArray = false;
|
||||
generateGLArrays(state);
|
||||
}
|
||||
|
||||
if (render.matchMaterial(state)) {
|
||||
SoMaterialBundle mb(action);
|
||||
mb.sendFirst();
|
||||
render.renderFacesGLArray(action);
|
||||
}
|
||||
else {
|
||||
inherited::GLRender(action);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
inherited::GLRender(action);
|
||||
#endif
|
||||
@@ -116,7 +464,7 @@ void SoFCIndexedFaceSet::GLRender(SoGLRenderAction *action)
|
||||
#if 0 && defined (RENDER_GLARRAYS)
|
||||
SoMaterialBundle mb(action);
|
||||
mb.sendFirst();
|
||||
renderCoordsGLArray(action);
|
||||
render.renderCoordsGLArray(action);
|
||||
#else
|
||||
SoMaterialBindingElement::Binding matbind =
|
||||
SoMaterialBindingElement::get(state);
|
||||
@@ -235,13 +583,12 @@ void SoFCIndexedFaceSet::invalidate()
|
||||
|
||||
void SoFCIndexedFaceSet::generateGLArrays(SoState * state)
|
||||
{
|
||||
this->index_array.resize(0);
|
||||
this->vertex_array.resize(0);
|
||||
|
||||
const SoCoordinateElement * coords;
|
||||
const SbVec3f * normals;
|
||||
const int32_t * cindices;
|
||||
int numindices;
|
||||
const SbColor * pcolors = 0;
|
||||
const float * transp = 0;
|
||||
int numindices, numcolors = 0, numtransp = 0;
|
||||
const int32_t * nindices;
|
||||
const int32_t * tindices;
|
||||
const int32_t * mindices;
|
||||
@@ -255,115 +602,166 @@ void SoFCIndexedFaceSet::generateGLArrays(SoState * state)
|
||||
|
||||
const SbVec3f * points = coords->getArrayPtr3();
|
||||
|
||||
SoMaterialBindingElement::Binding matbind =
|
||||
SoMaterialBindingElement::get(state);
|
||||
SoGLLazyElement* gl = SoGLLazyElement::getInstance(state);
|
||||
if (gl) {
|
||||
pcolors = gl->getDiffusePointer();
|
||||
numcolors = gl->getNumDiffuse();
|
||||
transp = gl->getTransparencyPointer();
|
||||
numtransp = gl->getNumTransparencies();
|
||||
Q_UNUSED(numtransp);
|
||||
}
|
||||
|
||||
std::vector<float> face_vertices;
|
||||
std::vector<int32_t> face_indices;
|
||||
|
||||
std::size_t numTria = numindices / 4;
|
||||
|
||||
if (!mindices && matbind == SoMaterialBindingElement::PER_VERTEX_INDEXED) {
|
||||
mindices = cindices;
|
||||
}
|
||||
|
||||
SoNormalBindingElement::Binding normbind = SoNormalBindingElement::get(state);
|
||||
if (normbind == SoNormalBindingElement::PER_VERTEX_INDEXED) {
|
||||
face_vertices.reserve(3 * numTria * 6); // duplicate each vertex
|
||||
face_indices.resize(3 * numTria);
|
||||
if (matbind == SoMaterialBindingElement::PER_FACE) {
|
||||
face_vertices.reserve(3 * numTria * 10); // duplicate each vertex (rgba, normal, vertex)
|
||||
face_indices.resize(3 * numTria);
|
||||
|
||||
if (numcolors != static_cast<int>(numTria)) {
|
||||
SoDebugError::postWarning("SoFCIndexedFaceSet::generateGLArrays",
|
||||
"The number of faces (%d) doesn't match with the number of colors (%d).", numTria, numcolors);
|
||||
}
|
||||
|
||||
// the nindices must have the length of numindices
|
||||
int32_t vertex = 0;
|
||||
int index = 0;
|
||||
float t = transp[0];
|
||||
for (std::size_t i=0; i<numTria; i++) {
|
||||
const SbColor& c = pcolors[i];
|
||||
for (int j=0; j<3; j++) {
|
||||
face_vertices.push_back(c[0]);
|
||||
face_vertices.push_back(c[1]);
|
||||
face_vertices.push_back(c[2]);
|
||||
face_vertices.push_back(t);
|
||||
|
||||
const SbVec3f& n = normals[nindices[index]];
|
||||
face_vertices.push_back(n[0]);
|
||||
face_vertices.push_back(n[1]);
|
||||
face_vertices.push_back(n[2]);
|
||||
|
||||
const SbVec3f& p = points[cindices[index]];
|
||||
face_vertices.push_back(p[0]);
|
||||
face_vertices.push_back(p[1]);
|
||||
face_vertices.push_back(p[2]);
|
||||
|
||||
face_indices[vertex] = vertex;
|
||||
vertex++;
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else if (matbind == SoMaterialBindingElement::PER_VERTEX_INDEXED) {
|
||||
face_vertices.reserve(3 * numTria * 10); // duplicate each vertex (rgba, normal, vertex)
|
||||
face_indices.resize(3 * numTria);
|
||||
|
||||
if (numcolors != coords->getNum()) {
|
||||
SoDebugError::postWarning("SoFCIndexedFaceSet::generateGLArrays",
|
||||
"The number of points (%d) doesn't match with the number of colors (%d).", coords->getNum(), numcolors);
|
||||
}
|
||||
|
||||
// the nindices must have the length of numindices
|
||||
int32_t vertex = 0;
|
||||
int index = 0;
|
||||
float t = transp[0];
|
||||
for (std::size_t i=0; i<numTria; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
const SbColor& c = pcolors[mindices[index]];
|
||||
face_vertices.push_back(c[0]);
|
||||
face_vertices.push_back(c[1]);
|
||||
face_vertices.push_back(c[2]);
|
||||
face_vertices.push_back(t);
|
||||
|
||||
const SbVec3f& n = normals[nindices[index]];
|
||||
face_vertices.push_back(n[0]);
|
||||
face_vertices.push_back(n[1]);
|
||||
face_vertices.push_back(n[2]);
|
||||
|
||||
const SbVec3f& p = points[cindices[index]];
|
||||
face_vertices.push_back(p[0]);
|
||||
face_vertices.push_back(p[1]);
|
||||
face_vertices.push_back(p[2]);
|
||||
|
||||
face_indices[vertex] = vertex;
|
||||
vertex++;
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// only an overall material
|
||||
matbind = SoMaterialBindingElement::OVERALL;
|
||||
|
||||
face_vertices.reserve(3 * numTria * 6); // duplicate each vertex (normal, vertex)
|
||||
face_indices.resize(3 * numTria);
|
||||
|
||||
// the nindices must have the length of numindices
|
||||
int32_t vertex = 0;
|
||||
int index = 0;
|
||||
for (std::size_t i=0; i<numTria; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
const SbVec3f& n = normals[nindices[index]];
|
||||
face_vertices.push_back(n[0]);
|
||||
face_vertices.push_back(n[1]);
|
||||
face_vertices.push_back(n[2]);
|
||||
|
||||
const SbVec3f& p = points[cindices[index]];
|
||||
face_vertices.push_back(p[0]);
|
||||
face_vertices.push_back(p[1]);
|
||||
face_vertices.push_back(p[2]);
|
||||
|
||||
face_indices[vertex] = vertex;
|
||||
vertex++;
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (normbind == SoNormalBindingElement::PER_VERTEX) {
|
||||
// only an overall material
|
||||
matbind = SoMaterialBindingElement::OVERALL;
|
||||
|
||||
std::size_t numPts = coords->getNum();
|
||||
face_vertices.reserve(6 * numPts);
|
||||
for (std::size_t i=0; i<numPts; i++) {
|
||||
const SbVec3f& n = normals[i];
|
||||
face_vertices.push_back(n[0]);
|
||||
face_vertices.push_back(n[1]);
|
||||
face_vertices.push_back(n[2]);
|
||||
|
||||
const SbVec3f& p = coords->get3(i);
|
||||
face_vertices.push_back(p[0]);
|
||||
face_vertices.push_back(p[1]);
|
||||
face_vertices.push_back(p[2]);
|
||||
|
||||
}
|
||||
|
||||
face_indices.reserve(3 * numTria);
|
||||
|
||||
// the nindices must have the length of numindices
|
||||
int32_t vertex = 0;
|
||||
int index = 0;
|
||||
for (std::size_t i=0; i<numTria; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
const SbVec3f& n = normals[nindices[index]];
|
||||
face_vertices.push_back(n[0]);
|
||||
face_vertices.push_back(n[1]);
|
||||
face_vertices.push_back(n[2]);
|
||||
|
||||
const SbVec3f& p = points[cindices[index]];
|
||||
face_vertices.push_back(p[0]);
|
||||
face_vertices.push_back(p[1]);
|
||||
face_vertices.push_back(p[2]);
|
||||
|
||||
face_indices[vertex] = vertex;
|
||||
vertex++;
|
||||
face_indices.push_back(cindices[index]);
|
||||
index++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
this->index_array.swap(face_indices);
|
||||
this->vertex_array.swap(face_vertices);
|
||||
}
|
||||
|
||||
//****************************************************************************
|
||||
// renderFacesGLArray: normal and coord from vertex_array;
|
||||
// no texture, color, highlight or selection but highest possible speed;
|
||||
// all vertices written in one go!
|
||||
//
|
||||
// Benchmark tests with an 256 MB STL file:
|
||||
//
|
||||
// Implementation | FPS
|
||||
// ================================================
|
||||
// OpenInventor | 3.5
|
||||
// With GL_PRIMITIVE_RESTART | 0.9
|
||||
// With GL_PRIMITIVE_RESTART_FIXED_INDEX | 0.9
|
||||
// Without GL_PRIMITIVE_RESTART | 12.5
|
||||
//
|
||||
void SoFCIndexedFaceSet::renderFacesGLArray(SoGLRenderAction *action)
|
||||
{
|
||||
#if 0 // use Inventor's coordIndex saves memory but the rendering is very slow then
|
||||
const cc_glglue * glue = cc_glglue_instance(action->getCacheContext());
|
||||
PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)
|
||||
cc_glglue_getprocaddress(glue, "glPrimitiveRestartIndex");
|
||||
|
||||
int cnt = coordIndex.getNum();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// https://www.opengl.org/discussion_boards/archive/index.php/t-180767.html
|
||||
// https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
//glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, coordIndex.getValues(0));
|
||||
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
//glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
#else // Needs more memory but makes it very fast
|
||||
(void)action;
|
||||
int cnt = index_array.size();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_TRIANGLES, cnt, GL_UNSIGNED_INT, &(index_array[0]));
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implementation | FPS
|
||||
// ================================================
|
||||
// drawCoords (every 4th vertex) | 20.0
|
||||
// renderCoordsGLArray (all vertexes) | 20.0
|
||||
//
|
||||
void SoFCIndexedFaceSet::renderCoordsGLArray(SoGLRenderAction *action)
|
||||
{
|
||||
(void)action;
|
||||
int cnt = index_array.size();
|
||||
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glInterleavedArrays(GL_N3F_V3F, 0, &(vertex_array[0]));
|
||||
glDrawElements(GL_POINTS, cnt, GL_UNSIGNED_INT, &(index_array[0]));
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
render.generateGLArrays(state, matbind, face_vertices, face_indices);
|
||||
}
|
||||
|
||||
void SoFCIndexedFaceSet::doAction(SoAction * action)
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
#define MESHGUI_SOFCINDEXEDFACESET_H
|
||||
|
||||
#include <Inventor/nodes/SoIndexedFaceSet.h>
|
||||
#include <Inventor/elements/SoMaterialBindingElement.h>
|
||||
#include <Inventor/engines/SoSubEngine.h>
|
||||
#include <Inventor/fields/SoSFBool.h>
|
||||
#include <Inventor/fields/SoMFColor.h>
|
||||
|
||||
class SoGLCoordinateElement;
|
||||
class SoTextureCoordinateBundle;
|
||||
@@ -34,6 +38,47 @@ typedef float GLfloat;
|
||||
|
||||
namespace MeshGui {
|
||||
|
||||
class MeshRenderer
|
||||
{
|
||||
public:
|
||||
MeshRenderer();
|
||||
~MeshRenderer();
|
||||
void generateGLArrays(SoState*, SoMaterialBindingElement::Binding binding,
|
||||
std::vector<float>& vertex, std::vector<int32_t>& index);
|
||||
void renderFacesGLArray(SoGLRenderAction *action);
|
||||
void renderCoordsGLArray(SoGLRenderAction *action);
|
||||
bool matchMaterial(SoState*) const;
|
||||
static bool shouldRenderDirectly(bool);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* p;
|
||||
};
|
||||
|
||||
/**
|
||||
* class SoFCMaterialEngine
|
||||
* \brief The SoFCMaterialEngine class is used to notify an
|
||||
* SoFCIndexedFaceSet node about material changes.
|
||||
*
|
||||
* @author Werner Mayer
|
||||
*/
|
||||
class MeshGuiExport SoFCMaterialEngine : public SoEngine
|
||||
{
|
||||
SO_ENGINE_HEADER(SoFCMaterialEngine);
|
||||
|
||||
public:
|
||||
SoFCMaterialEngine();
|
||||
static void initClass();
|
||||
|
||||
SoMFColor diffuseColor;
|
||||
SoEngineOutput trigger;
|
||||
|
||||
private:
|
||||
virtual ~SoFCMaterialEngine();
|
||||
virtual void evaluate();
|
||||
virtual void inputChanged(SoField *);
|
||||
};
|
||||
|
||||
/**
|
||||
* class SoFCIndexedFaceSet
|
||||
* \brief The SoFCIndexedFaceSet class is designed to optimize redrawing a mesh
|
||||
@@ -50,6 +95,7 @@ public:
|
||||
static void initClass();
|
||||
SoFCIndexedFaceSet();
|
||||
|
||||
SoSFBool updateGLArray;
|
||||
unsigned int renderTriangleLimit;
|
||||
|
||||
void invalidate();
|
||||
@@ -80,13 +126,9 @@ private:
|
||||
void renderVisibleFaces(const SbVec3f *);
|
||||
|
||||
void generateGLArrays(SoState * state);
|
||||
void renderFacesGLArray(SoGLRenderAction *action);
|
||||
void renderCoordsGLArray(SoGLRenderAction *action);
|
||||
|
||||
private:
|
||||
std::vector<int32_t> index_array;
|
||||
std::vector<float> vertex_array;
|
||||
SbBool updateGLArray;
|
||||
MeshRenderer render;
|
||||
GLuint *selectBuf;
|
||||
};
|
||||
|
||||
|
||||
@@ -1823,6 +1823,14 @@ void ViewProviderMesh::deleteSelection()
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderMesh::hasSelection() const
|
||||
{
|
||||
std::vector<unsigned long> indices;
|
||||
Mesh::PropertyMeshKernel& meshProp = static_cast<Mesh::Feature*>(pcObject)->Mesh;
|
||||
const Mesh::MeshObject& rMesh = meshProp.getValue();
|
||||
return rMesh.hasSelectedFacets();
|
||||
}
|
||||
|
||||
void ViewProviderMesh::selectArea(short x, short y, short w, short h,
|
||||
const SbViewportRegion& region,
|
||||
SoCamera* camera)
|
||||
|
||||
@@ -151,6 +151,7 @@ public:
|
||||
void invertSelection();
|
||||
void clearSelection();
|
||||
void deleteSelection();
|
||||
bool hasSelection() const;
|
||||
void getFacetsFromPolygon(const std::vector<SbVec2f>& picked,
|
||||
const Base::ViewProjMethod& proj, SbBool inner,
|
||||
std::vector<unsigned long>& indices) const;
|
||||
|
||||
@@ -100,6 +100,12 @@ ViewProviderMeshFaceSet::ViewProviderMeshFaceSet()
|
||||
pcMeshCoord->ref();
|
||||
pcMeshFaces = new SoFCIndexedFaceSet;
|
||||
pcMeshFaces->ref();
|
||||
|
||||
// setup engine to notify 'pcMeshFaces' node about material changes.
|
||||
// When the affected nodes are deleted the engine will be deleted, too.
|
||||
SoFCMaterialEngine* engine = new SoFCMaterialEngine();
|
||||
engine->diffuseColor.connectFrom(&pcShapeMaterial->diffuseColor);
|
||||
pcMeshFaces->updateGLArray.connectFrom(&engine->trigger);
|
||||
}
|
||||
|
||||
ViewProviderMeshFaceSet::~ViewProviderMeshFaceSet()
|
||||
@@ -132,7 +138,7 @@ void ViewProviderMeshFaceSet::updateData(const App::Property* prop)
|
||||
if (prop->getTypeId() == Mesh::PropertyMeshKernel::getClassTypeId()) {
|
||||
const Mesh::MeshObject* mesh = static_cast<const Mesh::PropertyMeshKernel*>(prop)->getValuePtr();
|
||||
|
||||
bool direct = (mesh->countFacets() > this->triangleCount);
|
||||
bool direct = MeshRenderer::shouldRenderDirectly(mesh->countFacets() > this->triangleCount);
|
||||
if (direct) {
|
||||
this->pcMeshNode->mesh.setValue(mesh);
|
||||
// Needs to update internal bounding box caches
|
||||
|
||||
Reference in New Issue
Block a user