Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 99a6b979 authored by Jakob Weiss's avatar Jakob Weiss
Browse files

MultiIndexedGeometry changes

* MultiIndexedGeometry index type is now 32 bit to allow for larger meshes
* MultiIndexedGeometry::generateVertexNormals() can now automatically generate normals for a GL_TRIANGLES topology
parent 675a3482
......@@ -74,11 +74,11 @@ namespace campvis {
auto result = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), normals);
// For each horizontal stripe, construct the indeces for triangle strips
// For each horizontal stripe, construct the indices for triangle strips
int verticesPerStrip = (xSegments + 1) * 2;
for (int y = 0; y < ySegments; ++y) {
std::vector<uint16_t> indices(verticesPerStrip);
for (uint16_t x = 0; x <= xSegments; ++x) {
std::vector<MultiIndexedGeometry::index_t> indices(verticesPerStrip);
for (MultiIndexedGeometry::index_t x = 0; x <= static_cast<MultiIndexedGeometry::index_t>(xSegments); ++x) {
indices[x*2 + 0] = (y + 0) * (xSegments + 1) + x;
indices[x*2 + 1] = (y + 1) * (xSegments + 1) + x;
}
......@@ -196,8 +196,8 @@ namespace campvis {
// convert indices and add primitives
int currentOffset = 0;
while (currentOffset < Teapot::num_teapot_indices) {
uint16_t count = Teapot::new_teapot_indicies[currentOffset];
toReturn->addPrimitive(std::vector<uint16_t>(Teapot::new_teapot_indicies + currentOffset + 1, Teapot::new_teapot_indicies + count + currentOffset + 1));
MultiIndexedGeometry::index_t count = Teapot::new_teapot_indicies[currentOffset];
toReturn->addPrimitive(std::vector<MultiIndexedGeometry::index_t>(Teapot::new_teapot_indicies + currentOffset + 1, Teapot::new_teapot_indicies + count + currentOffset + 1));
currentOffset += count + 1;
}
......@@ -244,8 +244,8 @@ namespace campvis {
// add indices for primitives to geometry:
{
// top stack:
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(0);
indices.push_back(j+1);
}
......@@ -256,11 +256,11 @@ namespace campvis {
}
{
// middle stacks:
std::vector<uint16_t> indices;
for (uint16_t i = 1; i < numStacks-1; ++i) {
uint16_t startIndex = 1 + (i-1) * numSlices;
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t i = 1; i < static_cast<MultiIndexedGeometry::index_t>(numStacks-1); ++i) {
MultiIndexedGeometry::index_t startIndex = 1 + (i-1) * numSlices;
for (uint16_t j = 0; j < numSlices; ++j) {
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(startIndex + j);
indices.push_back(startIndex + numSlices + j);
}
......@@ -272,10 +272,10 @@ namespace campvis {
}
{
// bottom stack:
std::vector<uint16_t> indices;
uint16_t endIndex = static_cast<uint16_t>(vertices.size() - 1);
std::vector<MultiIndexedGeometry::index_t> indices;
MultiIndexedGeometry::index_t endIndex = static_cast<MultiIndexedGeometry::index_t>(vertices.size() - 1);
for (uint16_t j = 0; j < numSlices; ++j) {
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(endIndex);
indices.push_back(endIndex - (j+1));
}
......@@ -347,8 +347,8 @@ namespace campvis {
// add indices for primitives to geometry:
{
// cylinder floor
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(0);
indices.push_back(j+1);
}
......@@ -359,8 +359,8 @@ namespace campvis {
}
{
// cylinder shaft
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices);
indices.push_back(j+1+numSlices*2);
}
......@@ -371,8 +371,8 @@ namespace campvis {
}
{
// arrow tip bottom area
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*3);
indices.push_back(j+1+numSlices*4);
}
......@@ -384,8 +384,8 @@ namespace campvis {
{
// arrow tip cone
uint16_t m = static_cast<uint16_t>(vertices.size() - 1);
std::vector<uint16_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) {
std::vector<MultiIndexedGeometry::index_t> indices;
for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*5);
indices.push_back(m);
}
......
......@@ -114,9 +114,9 @@ namespace campvis {
return GeometryData::getVideoMemoryFootprint() + (_indicesBuffer == 0 ? 0 : _indicesBuffer->getBufferSize());
}
void MultiIndexedGeometry::addPrimitive(const std::vector<uint16_t>& indices) {
if (! _indices.empty())
_indices.push_back(65535);
void MultiIndexedGeometry::addPrimitive(const std::vector<index_t>& indices) {
if (!_indices.empty())
_indices.push_back(static_cast<index_t>(-1));
_indices.insert(_indices.end(), indices.begin(), indices.end());
_buffersDirty = true;
......@@ -156,8 +156,8 @@ namespace campvis {
vao.bindIndexBuffer(_indicesBuffer);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535);
glDrawElements(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0);
glPrimitiveRestartIndex(static_cast<index_t>(-1));
glDrawElements(mode, static_cast<GLsizei>(_indices.size()), INDEX_BUFFER_GL_TYPE, 0);
glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR;
......@@ -187,13 +187,47 @@ namespace campvis {
vao.bindIndexBuffer(_indicesBuffer);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535);
glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0, count);
glPrimitiveRestartIndex(static_cast<index_t>(-1));
glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), INDEX_BUFFER_GL_TYPE, 0, count);
glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR;
}
void MultiIndexedGeometry::generateVertexNormals() {
if (_vertices.empty() || _indices.empty()) {
// empty meshes can happen commonly so we don't want to throw an assertion here...
LWARNING("Vertices and indices are required to calculate normals!");
return;
}
// note: for large meshes, this probably will be slow - an easy improvement would be multi-threaded processing --jw
_normals.resize(_vertices.size(), cgt::vec3(0.f));
std::vector<int> numFaces(_vertices.size(), 0);
for (size_t iIdx = 0; iIdx < _indices.size(); iIdx = iIdx + 3) {
index_t i0 = _indices[iIdx];
index_t i1 = _indices[iIdx + 1];
index_t i2 = _indices[iIdx + 2];
auto v0 = _vertices[i0];
auto v1 = _vertices[i1];
auto v2 = _vertices[i2];
cgt::vec3 normal = cgt::normalize(cgt::cross(v2 - v0, v1 - v0));
_normals[i0] += normal;
_normals[i1] += normal;
_normals[i2] += normal;
}
// normalize the accumulated normal
for (int i = 0; i < _normals.size(); i++) {
_normals[i] = cgt::normalize(_normals[i]);
}
_buffersDirty = true;
}
void MultiIndexedGeometry::createGLBuffers() const {
if (_buffersDirty) {
deleteBuffers();
......@@ -201,24 +235,24 @@ namespace campvis {
try {
_indicesBuffer = new cgt::BufferObject(cgt::BufferObject::ELEMENT_ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_indicesBuffer->data(&_indices.front(), _indices.size() * sizeof(uint16_t), cgt::BufferObject::UNSIGNED_SHORT, 1);
_indicesBuffer->data(&_indices.front(), _indices.size() * sizeof(index_t), INDEX_BUFFER_TYPE, 1);
_verticesBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_verticesBuffer->data(&_vertices.front(), _vertices.size() * sizeof(cgt::vec3), cgt::BufferObject::FLOAT, 3);
if (! _textureCoordinates.empty()) {
if (!_textureCoordinates.empty()) {
_texCoordsBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_texCoordsBuffer->data(&_textureCoordinates.front(), _textureCoordinates.size() * sizeof(cgt::vec3), cgt::BufferObject::FLOAT, 3);
}
if (! _colors.empty()) {
if (!_colors.empty()) {
_colorsBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_colorsBuffer->data(&_colors.front(), _colors.size() * sizeof(cgt::vec4), cgt::BufferObject::FLOAT, 4);
}
if (! _normals.empty()) {
if (!_normals.empty()) {
_normalsBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_normalsBuffer->data(&_normals.front(), _normals.size() * sizeof(cgt::vec3), cgt::BufferObject::FLOAT, 3);
}
if (! _pickingInformation.empty()) {
if (!_pickingInformation.empty()) {
_pickingBuffer = new cgt::BufferObject(cgt::BufferObject::ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW);
_pickingBuffer->data(&_pickingInformation.front(), _pickingInformation.size() * sizeof(cgt::col4), cgt::BufferObject::UNSIGNED_BYTE, 4);
}
......
......@@ -27,6 +27,7 @@
#include "cgt/bounds.h"
#include "cgt/vector.h"
#include "cgt/buffer.h"
#include "core/datastructures/geometrydata.h"
#include "core/datastructures/facegeometry.h"
......@@ -44,6 +45,11 @@ namespace campvis {
*/
class CAMPVIS_CORE_API MultiIndexedGeometry : public GeometryData {
public:
// these are defined so it is easy in the future to change to a larger or smaller index format
typedef uint32_t index_t; ///< the integer type used for indices
const cgt::BufferObject::BaseType INDEX_BUFFER_TYPE = cgt::BufferObject::UNSIGNED_INT; ///< buffer type matching \a index_t
const GLenum INDEX_BUFFER_GL_TYPE = GL_UNSIGNED_INT; ///< OpenGL buffer type matching \a index_t
/**
* Creates a new MultiIndexedGeometry using the given geometry. Indices are to be provided later.
* \param vertices The list of the vertex positions of the face.
......@@ -89,7 +95,7 @@ namespace campvis {
* Add a render primitive given by a list of indices.
* \param indices Index list defining the faces.
*/
void addPrimitive(const std::vector<uint16_t>& indices);
void addPrimitive(const std::vector<index_t>& indices);
/**
* The list of picking information colors, may be empty.
......@@ -127,6 +133,14 @@ namespace campvis {
/// \see GeometryData::applyTransformationToVertices
virtual void applyTransformationToVertices(const cgt::mat4& t);
/**
* Generates per-vertex normals from the adjacency data in the index buffer. This can be used
* to generate smoother normals on generated meshes. It assumes a triangle topology of GL_TRIANGLES
* and calculates the normal for each vertex by averaging the face normals of every adjacent triangle.
*/
void generateVertexNormals();
protected:
/**
* Creates the OpenGL VBOs and the VAO for this face's geometry.
......@@ -137,7 +151,7 @@ namespace campvis {
/// Deletes the OpenGL BufferObject for the indices.
void deleteIndicesBuffer() const;
std::vector<uint16_t> _indices; ///< Index list defining the faces
std::vector<index_t> _indices; ///< Index list defining the faces
std::vector<cgt::vec3> _vertices; ///< The list of the vertex positions of the face.
std::vector<cgt::vec3> _textureCoordinates; ///< The list of vertex texture coordinates, may be empty.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment