CGI/common/src/util/OpenMeshUtils.cpp
2018-09-06 14:35:43 +02:00

208 lines
No EOL
5.9 KiB
C++

#include "util/OpenMeshUtils.h"
#include <vector>
#include <gui/ShaderPool.h>
MeshRenderer::MeshRenderer(const HEMesh& mesh)
: mesh(mesh), indexCount(0),
positionBuffer(nse::gui::VertexBuffer), normalBuffer(nse::gui::VertexBuffer), colorBuffer(nse::gui::VertexBuffer), texCoordBuffer(nse::gui::VertexBuffer),
indexBuffer(nse::gui::IndexBuffer),
texCoordBuffer4D(nse::gui::VertexBuffer), indexBufferTexCoords(nse::gui::IndexBuffer)
{
vao.generate();
vaoTexCoords.generate();
Update();
}
//EmitVertexFunctor: void(const HEMesh::HalfedgeHandle[3]) //the to-vertices of the halfedges are the triangle corners
template <typename EmitTriangleFunctor>
void TriangulateMeshFace(HEMesh::FaceHandle f, const HEMesh& mesh, EmitTriangleFunctor&& emitTriangle)
{
OpenMesh::HalfedgeHandle base;
for (auto h : mesh.fh_range(f))
{
if (base.idx() == -1)
{
base = h;
continue;
}
auto nextH = mesh.next_halfedge_handle(h);
if (nextH == base)
break;
else
{
HEMesh::HalfedgeHandle triangle[3] = { base, h, nextH };
std::forward<EmitTriangleFunctor>(emitTriangle)(triangle);
}
}
}
void MeshRenderer::Update()
{
if (mesh.n_vertices() == 0)
return;
ShaderPool::Instance()->meshShader.bind();
vao.bind();
std::vector<Eigen::Vector4f> positions;
std::vector<Eigen::Vector4f> normals;
std::vector<Eigen::Vector2f> uvs;
positions.reserve(mesh.n_vertices());
normals.reserve(mesh.n_vertices());
if(mesh.has_vertex_texcoords2D())
uvs.reserve(mesh.n_vertices());
for (auto v : mesh.vertices())
{
positions.push_back(ToEigenVector4(mesh.point(v)));
OpenMesh::Vec3f n;
mesh.calc_vertex_normal_correct(v, n);
normals.push_back(ToEigenVector4(n, 0));
if (mesh.has_vertex_texcoords2D())
uvs.push_back(ToEigenVector(mesh.texcoord2D(v)));
}
positionBuffer.uploadData(positions).bindToAttribute("position");
normalBuffer.uploadData(normals).bindToAttribute("normal");
if (mesh.has_vertex_texcoords2D())
texCoordBuffer.uploadData(uvs).bindToAttribute("texCoords");
std::vector<uint32_t> indices;
indices.reserve(mesh.n_faces() * 3);
for (auto f : mesh.faces())
{
TriangulateMeshFace(f, mesh, [&](const HEMesh::HalfedgeHandle h[3])
{
indices.push_back(mesh.to_vertex_handle(h[0]).idx());
indices.push_back(mesh.to_vertex_handle(h[1]).idx());
indices.push_back(mesh.to_vertex_handle(h[2]).idx());
});
}
indexBuffer.uploadData(sizeof(uint32_t) * (uint32_t)indices.size(), indices.data());
indexCount = (unsigned int)indices.size();
vao.unbind();
hasColor = false;
UpdateTextureMapBuffers();
}
void MeshRenderer::UpdateWithPerFaceColor(OpenMesh::FPropHandleT<Eigen::Vector4f> colorProperty)
{
if (mesh.n_vertices() == 0)
return;
ShaderPool::Instance()->meshShader.bind();
vao.bind();
std::vector<Eigen::Vector4f> positions;
std::vector<Eigen::Vector4f> normals;
std::vector<Eigen::Vector4f> colors;
std::vector<Eigen::Vector2f> uvs;
positions.reserve(3 * mesh.n_faces());
normals.reserve(3 * mesh.n_faces());
colors.reserve(3 * mesh.n_faces());
if (mesh.has_vertex_texcoords2D())
uvs.reserve(3 * mesh.n_faces());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
for (auto f : mesh.faces())
{
TriangulateMeshFace(f, mesh, [&](const HEMesh::HalfedgeHandle h[3])
{
for (int i = 0; i < 3; ++i)
{
auto v = mesh.to_vertex_handle(h[i]);
positions.push_back(ToEigenVector4(mesh.point(v)));
OpenMesh::Vec3f n;
mesh.calc_vertex_normal_correct(v, n);
normals.push_back(ToEigenVector4(n, 0));
colors.push_back(mesh.property(colorProperty, f));
if (mesh.has_vertex_texcoords2D())
uvs.push_back(ToEigenVector(mesh.texcoord2D(v)));
}
});
}
positionBuffer.uploadData(positions).bindToAttribute("position");
normalBuffer.uploadData(normals).bindToAttribute("normal");
colorBuffer.uploadData(colors).bindToAttribute("color");
if (mesh.has_vertex_texcoords2D())
texCoordBuffer.uploadData(uvs).bindToAttribute("texCoords");
indexCount = (unsigned int)positions.size();
vao.unbind();
hasColor = true;
UpdateTextureMapBuffers();
}
void MeshRenderer::UpdateTextureMapBuffers()
{
if (!mesh.has_vertex_texcoords2D())
return;
ShaderPool::Instance()->simpleShader.bind();
vaoTexCoords.bind();
std::vector<Eigen::Vector4f> positions;
positions.reserve(mesh.n_vertices());
for (auto v : mesh.vertices())
positions.push_back(ToEigenVector4(mesh.texcoord2D(v)));
texCoordBuffer4D.uploadData(positions).bindToAttribute("position");
std::vector<uint32_t> indices;
indices.reserve(mesh.n_edges() * 2);
for (auto e : mesh.edges())
{
auto h = mesh.halfedge_handle(e, 0);
indices.push_back(mesh.from_vertex_handle(h).idx());
indices.push_back(mesh.to_vertex_handle(h).idx());
}
indexBufferTexCoords.uploadData(sizeof(uint32_t) * (uint32_t)indices.size(), indices.data());
indexCountTexCoords = (unsigned int)indices.size();
vaoTexCoords.unbind();
}
void MeshRenderer::Render(const Eigen::Matrix4f& view, const Eigen::Matrix4f& projection, bool flatShading, bool withTexCoords, const Eigen::Vector4f& color) const
{
if (indexCount == 0)
return;
auto& shader = ShaderPool::Instance()->meshShader;
shader.bind();
shader.setUniform("view", view);
shader.setUniform("proj", projection);
shader.setUniform("flatShading", flatShading ? 1 : 0);
shader.setUniform("perVertexColor", hasColor ? 1 : 0);
shader.setUniform("visualizeTexCoords", withTexCoords ? 1 : 0);
shader.setUniform("color", color);
vao.bind();
if (hasColor)
glDrawArrays(GL_TRIANGLES, 0, indexCount);
else
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
vao.unbind();
}
void MeshRenderer::RenderTextureMap(const Eigen::Matrix4f& projection, const Eigen::Vector4f& color) const
{
if (indexCountTexCoords == 0)
return;
auto& shader = ShaderPool::Instance()->simpleShader;
shader.bind();
shader.setUniform("mvp", projection);
shader.setUniform("color", color);
vaoTexCoords.bind();
glDrawElements(GL_LINES, indexCountTexCoords, GL_UNSIGNED_INT, 0);
vaoTexCoords.unbind();
}