Notice: If you are member of any public project or group, please make sure that your GitLab username is not the same as the LRZ identifier/Kennung (see https://gitlab.lrz.de/profile/account). Please change your username if necessary. For more information see the section "Public projects / Öffentliche Projekte" at https://doku.lrz.de/display/PUBLIC/GitLab . Thank you!

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

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);
}
......
......@@ -39,9 +39,9 @@ namespace campvis {
MultiIndexedGeometry::MultiIndexedGeometry(
const std::vector<cgt::vec3>& vertices,
const std::vector<cgt::vec3>& textureCoordinates /*= std::vector<cgt::vec3>()*/,
const std::vector<cgt::vec4>& colors /*= std::vector<cgt::vec4>()*/,
const std::vector<cgt::vec3>& vertices,
const std::vector<cgt::vec3>& textureCoordinates /*= std::vector<cgt::vec3>()*/,
const std::vector<cgt::vec4>& colors /*= std::vector<cgt::vec4>()*/,
const std::vector<cgt::vec3>& normals /*= std::vector<cgt::vec3>() */)
: GeometryData()
, _vertices(vertices)
......@@ -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"
......@@ -36,14 +37,19 @@ namespace campvis {
/**
* Class for indexed geometry consisting of multiple primitives.
* Internally working with glMultiDrawElements(), every MultiIndexedGeometry consists of a
* Internally working with glMultiDrawElements(), every MultiIndexedGeometry consists of a
* stream of vertices, an index list defining the faces and a pair of arrays defining start
* indices and number of indices for each primitive to render.
*
*
* The internal OpenGL buffers are lazy-instantiated.
*/
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.
......@@ -56,8 +62,8 @@ namespace campvis {
const std::vector<cgt::vec3>& textureCoordinates = std::vector<cgt::vec3>(),
const std::vector<cgt::vec4>& colors = std::vector<cgt::vec4>(),
const std::vector<cgt::vec3>& normals = std::vector<cgt::vec3>()
);
);
/**
* Copy constructor
* \param rhs MultiIndexedGeometry to copy
......@@ -68,7 +74,7 @@ namespace campvis {
* Destructor, deletes VBOs/VAO if necessary. Hence, needs a valid OpenGL context
*/
virtual ~MultiIndexedGeometry();
/**
* Assignment operator.
* \param rhs MultiIndexedGeometry to assign to this.
......@@ -89,8 +95,8 @@ 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.
* \return _pickingInformation
......@@ -109,7 +115,7 @@ namespace campvis {
* \param mode OpenGL rendering mode for this mesh
*/
virtual void render(GLenum mode) const;
/**
* Renders multiple instances of this GeometryData.
* Must be called from a valid OpenGL context.
......@@ -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