From 99d93ef114e95cd79deb7daaaae0c40e10333a06 Mon Sep 17 00:00:00 2001 From: Paul Leroy Date: Tue, 19 Mar 2024 11:21:37 +0100 Subject: [PATCH] draw a sphere at a local maximum with the associated color --- include/ActionA.h | 6 + include/CMakeLists.txt | 1 + include/GrainsAsEllipsoids.h | 99 ++++++++++ shaders/DrawGrains.fs | 6 + shaders/DrawGrains.gs | 26 +++ shaders/DrawGrains.gs.old | 86 +++++++++ shaders/DrawGrains.vs | 17 ++ shaders/ellipsoid.fs | 42 ++++ shaders/ellipsoid.vs | 26 +++ src/ActionA.cpp | 11 ++ src/CMakeLists.txt | 1 + src/GrainsAsEllipsoids.cpp | 364 +++++++++++++++++++++++++++++++++++ 12 files changed, 685 insertions(+) create mode 100644 include/GrainsAsEllipsoids.h create mode 100644 shaders/DrawGrains.fs create mode 100644 shaders/DrawGrains.gs create mode 100644 shaders/DrawGrains.gs.old create mode 100644 shaders/DrawGrains.vs create mode 100644 shaders/ellipsoid.fs create mode 100644 shaders/ellipsoid.vs create mode 100644 src/GrainsAsEllipsoids.cpp diff --git a/include/ActionA.h b/include/ActionA.h index 1333d6c..8cbf563 100644 --- a/include/ActionA.h +++ b/include/ActionA.h @@ -8,6 +8,8 @@ #include +#include + #pragma once class ccMainAppInterface; @@ -84,6 +86,8 @@ private: Eigen::ArrayXi m_ndon; Eigen::ArrayXd m_area; + QSharedPointer m_grainColors; + std::vector> m_stacks; ccOctree::Shared m_octree; @@ -91,5 +95,7 @@ private: CCCoreLib::DgmOctree::NearestNeighboursSearchStruct m_nNSS; static G3PointAction* s_g3PointAction; + + GrainsAsEllipsoids* m_grainsAsEllipsoids; }; } diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 3fb9540..9f19a1f 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources( ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/ActionA.h ${CMAKE_CURRENT_LIST_DIR}/G3Point.h ${CMAKE_CURRENT_LIST_DIR}/G3PointDialog.h + ${CMAKE_CURRENT_LIST_DIR}/GrainsAsEllipsoids.h ) target_include_directories( ${PROJECT_NAME} diff --git a/include/GrainsAsEllipsoids.h b/include/GrainsAsEllipsoids.h new file mode 100644 index 0000000..ecce306 --- /dev/null +++ b/include/GrainsAsEllipsoids.h @@ -0,0 +1,99 @@ +#ifndef GRAINSASELLIPSOIDS_H +#define GRAINSASELLIPSOIDS_H + +#include "Eigen/Dense" +#include "ccAdvancedTypes.h" + +#include +#include + +#include +#include +#include +#include + +class ccPointCloud; + +class GrainsAsEllipsoids : public ccHObject +{ +public: + GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface* app); + + //! Set the path for shaders + void setShaderPath(const QString &path); + + //! Release shaders (if any) + /** Must be called before the OpenGL context is released. + **/ + void releaseShaders(); + + bool initProgram(QOpenGLContext* context); + + // + + void initSphereVertices(); + + void initSphereIndexes(); + + void buildInterleavedVertices(); + + bool drawSphere(CC_DRAW_CONTEXT &context, int colorIndex=0); + + void setGrainColorsTable(QSharedPointer colorTable); + + std::vector vertices; + std::vector normals; + std::vector texCoords; + std::vector interleavedVertices; + + std::vector indices; + std::vector lineIndices; + + int sectorCount{21}; + int stackCount{21}; + + int interleavedStride = 32; + + // + + void setUniformValueColor(const ccColor::Rgba &color); + + //! Draw grains as ellipsoids + void drawGrains(CC_DRAW_CONTEXT &context); + + void setLocalMaximumIndexes(const Eigen::ArrayXi &localMaximumIndexes); + + //! Colors of the normals when they are displayed + enum NormalLineColors{ + YELLOW, + RED, + GREEN, + BLUE, + BLACK + }; + + struct NormalLineParameters + { + float length = 1.0f; + ccColor::Rgba color = ccColor::yellow; + int colorIdx = YELLOW; + } m_normalLineParameters; + + ccPointCloud* m_cloud; + ccMainAppInterface* m_app; + Eigen::ArrayXi m_localMaximumIndexes; + QSharedPointer m_grainColors; + + std::vector m_ellipsoidInstance; + Eigen::ArrayX3f ellipsoidInstance; + + QSharedPointer m_program; + + // Default path to the shader files + QString m_shaderPath; + + // from ccHObject + void draw(CC_DRAW_CONTEXT& context); +}; + +#endif // GRAINSASELLIPSOIDS_H diff --git a/shaders/DrawGrains.fs b/shaders/DrawGrains.fs new file mode 100644 index 0000000..90d0b49 --- /dev/null +++ b/shaders/DrawGrains.fs @@ -0,0 +1,6 @@ +uniform vec4 color; + +void main(void) +{ + gl_FragColor = color; +} diff --git a/shaders/DrawGrains.gs b/shaders/DrawGrains.gs new file mode 100644 index 0000000..ad7ef93 --- /dev/null +++ b/shaders/DrawGrains.gs @@ -0,0 +1,26 @@ +#version 330 core +layout (points) in; +layout (line_strip, max_vertices = 2) out; + +in Vertex +{ + vec3 semiAxisLengths; +} vertex[]; + +uniform float normalLength; +uniform mat4 modelViewProjectionMatrix; + + +void main(void) +{ + vec3 P = gl_in[0].gl_Position.xyz; + vec3 N = vec3(0., 0., 1.); + + gl_Position = modelViewProjectionMatrix * vec4(P, 1.0); + EmitVertex(); + + gl_Position = modelViewProjectionMatrix * vec4(P + N * 1., 1); + EmitVertex(); + + EndPrimitive(); +} \ No newline at end of file diff --git a/shaders/DrawGrains.gs.old b/shaders/DrawGrains.gs.old new file mode 100644 index 0000000..be9014d --- /dev/null +++ b/shaders/DrawGrains.gs.old @@ -0,0 +1,86 @@ +#version 330 core +layout (points) in; +layout (line_strip, max_vertices = 200) out; + +in Vertex +{ + vec3 semiAxisLengths; +} vertex[]; + +uniform float normalLength; +uniform mat4 modelViewProjectionMatrix; + +uniform float cosTheta[21]; +uniform float sinTheta[21]; +uniform float cosPhi[21]; +uniform float sinPhi[21]; + + +void main(void) +{ + vec3 P = gl_in[0].gl_Position.xyz; + //vec3 semiAxisLengths = vertex[0].semiAxisLengths; + vec3 semiAxisLengths = vec3(0.1, 0.1, 0.1); + + float x; + float y; + float z; + + + + int count = 0; + + for (int phi_i = 0; phi_i < 21; phi_i++) + { + if (phi_i == 0) + { + x = P.x; + y = P.y; + z = P.z + semiAxisLengths.z; + gl_Position = modelViewProjectionMatrix * vec4(x, y, z, 1.0); + EmitVertex(); + count++; + if (count == 200) + { + EndPrimitive(); + count = 0; + } + } + else if (phi_i == 20) + { + x = P.x; + y = P.y; + z = P.z - 1.; + gl_Position = modelViewProjectionMatrix * vec4(x, y, z, 1.0); + EmitVertex(); + count++; + if (count == 200) + { + EndPrimitive(); + count = 0; + } + } + else + { + for (int theta_i = 0; theta_i < 21; theta_i++) + { + //x = P.x + semiAxisLengths.x * sinTheta[theta_i] * cosPhi[phi_i]; + //y = P.y + semiAxisLengths.y * sinTheta[theta_i] * sinPhi[phi_i]; + //z = P.z + semiAxisLengths.z * cosTheta[theta_i]; + x = P.x + semiAxisLengths.x * sinTheta[theta_i] * cosPhi[phi_i]; + y = P.y + semiAxisLengths.y * sinTheta[theta_i] * sinPhi[phi_i]; + z = P.z + semiAxisLengths.z * cosTheta[theta_i]; + gl_Position = modelViewProjectionMatrix * vec4(x, y, z, 1.0); + EmitVertex(); + count++; + if (count == 200) + { + EndPrimitive(); + count = 0; + } + } + } + } + + EndPrimitive(); +} \ No newline at end of file diff --git a/shaders/DrawGrains.vs b/shaders/DrawGrains.vs new file mode 100644 index 0000000..7f87732 --- /dev/null +++ b/shaders/DrawGrains.vs @@ -0,0 +1,17 @@ +attribute vec3 vertexIn; +attribute vec3 semiAxisLengths; + +/*out Vertex +{ + vec3 semiAxisLengths; +} vertex;*/ + +uniform mat4 modelViewProjectionMatrix; +uniform vec3 center; + +void main(void) +{ + gl_PointSize = 5; + gl_Position = modelViewProjectionMatrix * vec4(vertexIn + center, 1.0); + //vertex.semiAxisLengths = semiAxisLengths; +} diff --git a/shaders/ellipsoid.fs b/shaders/ellipsoid.fs new file mode 100644 index 0000000..838e185 --- /dev/null +++ b/shaders/ellipsoid.fs @@ -0,0 +1,42 @@ +#version 330 + +// uniforms +uniform vec4 lightPosition; // should be in the eye space +uniform vec4 lightAmbient; // light ambient color +uniform vec4 lightDiffuse; // light diffuse color +uniform vec4 lightSpecular; // light specular color +uniform vec4 materialAmbient; // material ambient color +uniform vec4 materialDiffuse; // material diffuse color +uniform vec4 materialSpecular; // material specular color +uniform float materialShininess; // material specular shininess + +// varyings (input) +in vec3 esVertex; +in vec3 esNormal; +in vec2 texCoord0; + +// output +out vec4 fragColor; + +void main() +{ + vec3 normal = normalize(esNormal); + vec3 light; + if(lightPosition.w == 0.0) + { + light = normalize(lightPosition.xyz); + } + else + { + light = normalize(lightPosition.xyz - esVertex); + } + vec3 view = normalize(-esVertex); + vec3 reflectVec = reflect(-light, normal); // 2 * N * (N dot L) - L + + vec3 color = lightAmbient.rgb * materialAmbient.rgb; // begin with ambient + float dotNL = max(dot(normal, light), 0.0); + color += lightDiffuse.rgb * materialDiffuse.rgb * dotNL; // add diffuse + float dotVR = max(dot(view, reflectVec), 0.0); + color += pow(dotVR, materialShininess) * lightSpecular.rgb * materialSpecular.rgb; // add specular + fragColor = vec4(color, materialDiffuse.a); // set frag color +} diff --git a/shaders/ellipsoid.vs b/shaders/ellipsoid.vs new file mode 100644 index 0000000..f0200a0 --- /dev/null +++ b/shaders/ellipsoid.vs @@ -0,0 +1,26 @@ +#version 330 + +// uniforms +uniform mat4 modelViewMatrix; +uniform mat4 normalMatrix; +uniform mat4 modelViewProjectionMatrix; +uniform vec3 center; + +// vertex attribs (input) +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; + +// varyings (output) +out vec3 esVertex; +out vec3 esNormal; +out vec2 texCoord0; + +void main() +{ + esVertex = vec3(modelViewMatrix * vec4(vertexPosition + center, 1.0)); + esNormal = vec3(normalMatrix * vec4(vertexNormal, 1.0)); + texCoord0 = vertexTexCoord; + gl_PointSize = 5; + gl_Position = modelViewProjectionMatrix * vec4(vertexPosition + center, 1.0); +} diff --git a/src/ActionA.cpp b/src/ActionA.cpp index 27a2b2c..7457a12 100644 --- a/src/ActionA.cpp +++ b/src/ActionA.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ #include #include +#include #include @@ -1638,6 +1640,14 @@ void G3PointAction::segment() m_app->dispToConsole( "[G3Point] initial segmentation: " + QString::number(nLabels) + " labels", ccMainAppInterface::STD_CONSOLE_MESSAGE ); + // plot display grains as ellipsoids + m_grainsAsEllipsoids = new GrainsAsEllipsoids(m_cloud, m_app); + m_grainsAsEllipsoids->setLocalMaximumIndexes(m_localMaximumIndexes); + m_grainColors.reset(new RGBAColorsTableType(getRandomColors(m_localMaximumIndexes.size()))); + m_grainsAsEllipsoids->setGrainColorsTable(m_grainColors); + m_grainsAsEllipsoids->setName("grains as ellipsoids"); + m_app->addToDB(m_grainsAsEllipsoids); + m_dlg->enableCluster(true); m_dlg->enableClean(true); } @@ -1794,4 +1804,5 @@ void G3PointAction::createAction(ccMainAppInterface *appInterface) GetG3PointAction(ccHObjectCaster::ToPointCloud(ent), appInterface); } + } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8bc06e5..6e75b65 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,4 +4,5 @@ target_sources( ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/ActionA.cpp ${CMAKE_CURRENT_LIST_DIR}/G3Point.cpp ${CMAKE_CURRENT_LIST_DIR}/G3PointDialog.cpp + ${CMAKE_CURRENT_LIST_DIR}/GrainsAsEllipsoids.cpp ) diff --git a/src/GrainsAsEllipsoids.cpp b/src/GrainsAsEllipsoids.cpp new file mode 100644 index 0000000..7d067ce --- /dev/null +++ b/src/GrainsAsEllipsoids.cpp @@ -0,0 +1,364 @@ +#include "GrainsAsEllipsoids.h" + +#include + +#include + +#include + +GrainsAsEllipsoids::GrainsAsEllipsoids(ccPointCloud *cloud, ccMainAppInterface *app) + : m_cloud(cloud) + , m_app(app) +{ + setShaderPath("C:/dev/CloudCompare/plugins/private/qG3POINT/shaders"); +} + +void GrainsAsEllipsoids::setShaderPath(const QString& path) +{ + m_shaderPath = path; +} + +void GrainsAsEllipsoids::releaseShaders() +{ + m_program.clear(); +} + +bool GrainsAsEllipsoids::initProgram(QOpenGLContext* context) +{ + if (m_program.isNull()) + { + QString error; + + if (!context) + { + assert(false); + return false; + } + + m_program.reset(new QOpenGLShaderProgram(context)); + + // create vertex shader +// QString vertexShaderFile(m_shaderPath + "/DrawGrains.vs"); + QString vertexShaderFile(m_shaderPath + "/ellipsoid.vs"); + if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, vertexShaderFile)) + { + error = m_program->log(); + ccLog::Error(error); + return false; + } + + // create geometry shader +// QString geometryShaderFile(m_shaderPath + "/DrawGrains.gs"); +// if (!m_program->addShaderFromSourceFile(QOpenGLShader::Geometry, geometryShaderFile)) +// { +// error = m_program->log(); +// ccLog::Error(error); +// return false; +// } + + // create fragment shader +// QString fragmentShaderFile(m_shaderPath + "/DrawGrains.fs"); + QString fragmentShaderFile(m_shaderPath + "/ellipsoid.fs"); + if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, fragmentShaderFile)) + { + error = m_program->log(); + ccLog::Error(error); + return false; + } + + if (!m_program->link()) + { + error = m_program->log(); + ccLog::Error(error); + return false; + } + + // initialize the ellipsoid instance + m_ellipsoidInstance.resize(401); + float stepTheta = M_PI / 21; + float stepPhi = 2 * M_PI / 21; + int count = 0; + CCVector3f center = *m_cloud->getPoint(m_localMaximumIndexes[0]); + m_ellipsoidInstance[count++] = CCVector3f(0, 0, 1); + for (int thetaI = 1; thetaI < 20; thetaI++) + { + for (int phiI = 0; phiI < 21; phiI++) + { + m_ellipsoidInstance[count++] = CCVector3f(center.x + sin(thetaI * stepTheta) * cos(phiI * stepPhi) * 1, + center.y + sin(thetaI * stepTheta) * sin(phiI * stepPhi) * 1, + center.z + cos(thetaI * stepTheta) * 1); + } + } + m_ellipsoidInstance[count++] = CCVector3f(0, 0, -1); + + // initialize sphere + initSphereVertices(); + initSphereIndexes(); + buildInterleavedVertices(); + } + + return true; +} + +void GrainsAsEllipsoids::initSphereVertices() +{ + float radius = 0.2; + + // clear memory of prev arrays + std::vector().swap(vertices); + std::vector().swap(normals); + std::vector().swap(texCoords); + + float x, y, z, xy; // vertex position + float nx, ny, nz, lengthInv = 1.0f / radius; // vertex normal + float s, t; // vertex texCoord + + float sectorStep = 2 * M_PI / sectorCount; + float stackStep = M_PI / stackCount; + float sectorAngle, stackAngle; + + for(int i = 0; i <= stackCount; ++i) + { + stackAngle = M_PI / 2 - i * stackStep; // starting from pi/2 to -pi/2 + xy = radius * cosf(stackAngle); // r * cos(u) + z = radius * sinf(stackAngle); // r * sin(u) + + // add (sectorCount+1) vertices per stack + // first and last vertices have same position and normal, but different tex coords + for(int j = 0; j <= sectorCount; ++j) + { + sectorAngle = j * sectorStep; // starting from 0 to 2pi + + // vertex position (x, y, z) + x = xy * cosf(sectorAngle); // r * cos(u) * cos(v) + y = xy * sinf(sectorAngle); // r * cos(u) * sin(v) + vertices.push_back(x); + vertices.push_back(y); + vertices.push_back(z); + + // normalized vertex normal (nx, ny, nz) + nx = x * lengthInv; + ny = y * lengthInv; + nz = z * lengthInv; + normals.push_back(nx); + normals.push_back(ny); + normals.push_back(nz); + + // vertex tex coord (s, t) range between [0, 1] + s = (float)j / sectorCount; + t = (float)i / stackCount; + texCoords.push_back(s); + texCoords.push_back(t); + } + } + ccLog::Print("vertices.size() " + QString::number(vertices.size())); +} + +void GrainsAsEllipsoids::initSphereIndexes() +{ + // generate CCW index list of sphere triangles + // k1--k1+1 + // | / | + // | / | + // k2--k2+1 + + int k1, k2; + for(int i = 0; i < stackCount; ++i) + { + k1 = i * (sectorCount + 1); // beginning of current stack + k2 = k1 + sectorCount + 1; // beginning of next stack + + for(int j = 0; j < sectorCount; ++j, ++k1, ++k2) + { + // 2 triangles per sector excluding first and last stacks + // k1 => k2 => k1+1 + if(i != 0) + { + indices.push_back(k1); + indices.push_back(k2); + indices.push_back(k1 + 1); + } + + // k1+1 => k2 => k2+1 + if(i != (stackCount-1)) + { + indices.push_back(k1 + 1); + indices.push_back(k2); + indices.push_back(k2 + 1); + } + + // store indices for lines + // vertical lines for all stacks, k1 => k2 + lineIndices.push_back(k1); + lineIndices.push_back(k2); + if(i != 0) // horizontal lines except 1st stack, k1 => k+1 + { + lineIndices.push_back(k1); + lineIndices.push_back(k1 + 1); + } + } + } +} + +void GrainsAsEllipsoids::buildInterleavedVertices() +{ + std::vector().swap(interleavedVertices); + + std::size_t i, j; + std::size_t count = vertices.size(); + for(i = 0, j = 0; i < count; i += 3, j += 2) + { + interleavedVertices.push_back(vertices[i]); + interleavedVertices.push_back(vertices[i+1]); + interleavedVertices.push_back(vertices[i+2]); + + interleavedVertices.push_back(normals[i]); + interleavedVertices.push_back(normals[i+1]); + interleavedVertices.push_back(normals[i+2]); + + interleavedVertices.push_back(texCoords[j]); + interleavedVertices.push_back(texCoords[j+1]); + } +} + +bool GrainsAsEllipsoids::drawSphere(CC_DRAW_CONTEXT& context, int colorIndex) +{ + QOpenGLFunctions_2_1* glFunc = context.glFunctions(); + assert(glFunc != nullptr); + + const CCVector3f* center = m_cloud->getPoint(m_localMaximumIndexes[0]); + ccColor::Rgba color; + if (colorIndex < m_grainColors->size()) + { + color = m_grainColors->data()[colorIndex]; + } + else + { + ccLog::Error("[GrainsAsEllipsoids::drawSphere] index is larger than the color table"); + return false; + } + + // set uniforms + m_program->setUniformValue("center", center->x, center->y, center->z); + QVector4D lightPosition(0, 0, 1, 0); + QVector4D lightAmbient(0.3f, 0.3f, 0.3f, 1); // grey + QVector4D lightDiffuse(0.7f, 0.7f, 0.7f, 1); // light grey + QVector4D lightSpecular(1.0f, 1.0f, 1.0f, 1); // RGB white +// QVector4D materialAmbient(0.5f, 0.5f, 0.5f, 1); + QVector4D materialDiffuse(0.7f, 0.7f, 0.7f, 1); + QVector4D materialSpecular(0.4f, 0.4f, 0.4f, 1); + QVector4D materialAmbient(static_cast(color.r) / ccColor::MAX, static_cast(color.g) / ccColor::MAX, static_cast(color.b) / ccColor::MAX, 1); +// QVector4D materialDiffuse(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1); +// QVector4D materialSpecular(color.r / ccColor::MAX, color.g / ccColor::MAX, color.b / ccColor::MAX, 1); + float materialShininess = 16; + + m_program->setUniformValue("lightPosition", lightPosition); + m_program->setUniformValue("lightAmbient", lightAmbient); + m_program->setUniformValue("lightDiffuse", lightDiffuse); + m_program->setUniformValue("lightSpecular", lightSpecular); + m_program->setUniformValue("materialAmbient", materialAmbient); + m_program->setUniformValue("materialDiffuse", materialDiffuse); + m_program->setUniformValue("materialSpecular", materialSpecular); + m_program->setUniformValue("materialShininess", materialShininess); + + m_program->setAttributeArray("vertexPosition", static_cast(vertices.data()), 3); + m_program->setAttributeArray("vertexNormal", static_cast(normals.data()), 3); + m_program->setAttributeArray("vertexTexCoord", static_cast(texCoords.data()), 2); + + m_program->enableAttributeArray("vertexPosition"); + m_program->enableAttributeArray("vertexNormal"); + m_program->enableAttributeArray("vertexTexCoord"); + + glFunc->glEnable(GL_PROGRAM_POINT_SIZE); + setUniformValueColor(ccColor::yellow); + glFunc->glDrawElements(GL_TRIANGLES, (unsigned int)indices.size(), GL_UNSIGNED_INT, indices.data()); + + m_program->disableAttributeArray("vertexPosition"); + m_program->disableAttributeArray("vertexNormal"); + m_program->disableAttributeArray("vertexTexCoord"); + + return true; +} + +void GrainsAsEllipsoids::setGrainColorsTable(QSharedPointer colorTable) +{ + m_grainColors = colorTable; +} + +void GrainsAsEllipsoids::setUniformValueColor(const ccColor::Rgba &color) +{ + m_program->setUniformValue("color", color.r, color.g, color.b, color.a); +} + +void GrainsAsEllipsoids::drawGrains(CC_DRAW_CONTEXT& context) +{ + if (!initProgram(context.qGLContext)) + { + ccLog::Warning("[GrainsAsEllipsoids::drawGrains] impossible to init shader program"); + return; + } + + QOpenGLFunctions_2_1* glFunc = context.glFunctions(); + assert(glFunc != nullptr); + + QMatrix4x4 projection; + QMatrix4x4 modelView; + glFunc->glGetFloatv(GL_PROJECTION_MATRIX, projection.data()); + glFunc->glGetFloatv(GL_MODELVIEW_MATRIX, modelView.data()); + QMatrix4x4 projectionModelView = projection * modelView; // QMatrix4x4 expects row major data + + m_program->bind(); + // set uniforms + m_program->setUniformValue("modelViewProjectionMatrix", projectionModelView); + m_program->setUniformValue("normalLength", GLfloat(m_normalLineParameters.length)); + + // get the coordinates of the local maxima + std::vector semiAxisLengths(m_localMaximumIndexes.size(), CCVector3(1, 1, 1)); + std::vector centers(m_localMaximumIndexes.size()); + + // initialize the vector containing the centers of the grains + for (int index = 0; index < m_localMaximumIndexes.size(); index++) + { + centers[index] = *m_cloud->getPoint(m_localMaximumIndexes[index]); + } + + if (false) + { + m_program->setAttributeArray("vertexIn", static_cast(vertices.data()), 3); + m_program->setAttributeArray("semiAxisLengths", static_cast(semiAxisLengths.front().u), 3); + + m_program->enableAttributeArray("vertexIn"); // enable the vertex locations array + m_program->enableAttributeArray("semiAxisLengths"); // enable the semi-axis lenghts array + + m_program->setUniformValue("center", centers[0].x, centers[0].y, centers[0].z); + + glFunc->glEnable(GL_PROGRAM_POINT_SIZE); + setUniformValueColor(ccColor::yellow); + glFunc->glDrawElements(GL_TRIANGLES, (unsigned int)indices.size(), GL_UNSIGNED_INT, indices.data()); + + m_program->disableAttributeArray("vertexIn"); + m_program->disableAttributeArray("semiAxesLengths"); + } + else + { + QMatrix4x4 matrixNormal = modelView; + matrixNormal.setColumn(3, QVector4D(0,0,0,1)); + m_program->setUniformValue("modelViewMatrix", modelView); + m_program->setUniformValue("normalMatrix", matrixNormal); + drawSphere(context, 0); + } + + m_program->release(); + + m_app->redrawAll(); +} + +void GrainsAsEllipsoids::setLocalMaximumIndexes(const Eigen::ArrayXi &localMaximumIndexes) +{ + m_localMaximumIndexes = localMaximumIndexes; +} + +void GrainsAsEllipsoids::draw(CC_DRAW_CONTEXT& context) +{ + drawGrains(context); +}