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 { ...@@ -74,11 +74,11 @@ namespace campvis {
auto result = new MultiIndexedGeometry(vertices, textureCoordinates, std::vector<cgt::vec4>(), normals); 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; int verticesPerStrip = (xSegments + 1) * 2;
for (int y = 0; y < ySegments; ++y) { for (int y = 0; y < ySegments; ++y) {
std::vector<uint16_t> indices(verticesPerStrip); std::vector<MultiIndexedGeometry::index_t> indices(verticesPerStrip);
for (uint16_t x = 0; x <= xSegments; ++x) { 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 + 0] = (y + 0) * (xSegments + 1) + x;
indices[x*2 + 1] = (y + 1) * (xSegments + 1) + x; indices[x*2 + 1] = (y + 1) * (xSegments + 1) + x;
} }
...@@ -196,8 +196,8 @@ namespace campvis { ...@@ -196,8 +196,8 @@ namespace campvis {
// convert indices and add primitives // convert indices and add primitives
int currentOffset = 0; int currentOffset = 0;
while (currentOffset < Teapot::num_teapot_indices) { while (currentOffset < Teapot::num_teapot_indices) {
uint16_t count = Teapot::new_teapot_indicies[currentOffset]; MultiIndexedGeometry::index_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)); toReturn->addPrimitive(std::vector<MultiIndexedGeometry::index_t>(Teapot::new_teapot_indicies + currentOffset + 1, Teapot::new_teapot_indicies + count + currentOffset + 1));
currentOffset += count + 1; currentOffset += count + 1;
} }
...@@ -244,8 +244,8 @@ namespace campvis { ...@@ -244,8 +244,8 @@ namespace campvis {
// add indices for primitives to geometry: // add indices for primitives to geometry:
{ {
// top stack: // top stack:
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) { for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(0); indices.push_back(0);
indices.push_back(j+1); indices.push_back(j+1);
} }
...@@ -256,11 +256,11 @@ namespace campvis { ...@@ -256,11 +256,11 @@ namespace campvis {
} }
{ {
// middle stacks: // middle stacks:
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t i = 1; i < numStacks-1; ++i) { for (MultiIndexedGeometry::index_t i = 1; i < static_cast<MultiIndexedGeometry::index_t>(numStacks-1); ++i) {
uint16_t startIndex = 1 + (i-1) * numSlices; 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 + j);
indices.push_back(startIndex + numSlices + j); indices.push_back(startIndex + numSlices + j);
} }
...@@ -272,10 +272,10 @@ namespace campvis { ...@@ -272,10 +272,10 @@ namespace campvis {
} }
{ {
// bottom stack: // bottom stack:
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
uint16_t endIndex = static_cast<uint16_t>(vertices.size() - 1); 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);
indices.push_back(endIndex - (j+1)); indices.push_back(endIndex - (j+1));
} }
...@@ -347,8 +347,8 @@ namespace campvis { ...@@ -347,8 +347,8 @@ namespace campvis {
// add indices for primitives to geometry: // add indices for primitives to geometry:
{ {
// cylinder floor // cylinder floor
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) { for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(0); indices.push_back(0);
indices.push_back(j+1); indices.push_back(j+1);
} }
...@@ -359,8 +359,8 @@ namespace campvis { ...@@ -359,8 +359,8 @@ namespace campvis {
} }
{ {
// cylinder shaft // cylinder shaft
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) { for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices); indices.push_back(j+1+numSlices);
indices.push_back(j+1+numSlices*2); indices.push_back(j+1+numSlices*2);
} }
...@@ -371,8 +371,8 @@ namespace campvis { ...@@ -371,8 +371,8 @@ namespace campvis {
} }
{ {
// arrow tip bottom area // arrow tip bottom area
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) { for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*3); indices.push_back(j+1+numSlices*3);
indices.push_back(j+1+numSlices*4); indices.push_back(j+1+numSlices*4);
} }
...@@ -384,8 +384,8 @@ namespace campvis { ...@@ -384,8 +384,8 @@ namespace campvis {
{ {
// arrow tip cone // arrow tip cone
uint16_t m = static_cast<uint16_t>(vertices.size() - 1); uint16_t m = static_cast<uint16_t>(vertices.size() - 1);
std::vector<uint16_t> indices; std::vector<MultiIndexedGeometry::index_t> indices;
for (uint16_t j = 0; j < numSlices; ++j) { for (MultiIndexedGeometry::index_t j = 0; j < numSlices; ++j) {
indices.push_back(j+1+numSlices*5); indices.push_back(j+1+numSlices*5);
indices.push_back(m); indices.push_back(m);
} }
......
...@@ -39,9 +39,9 @@ namespace campvis { ...@@ -39,9 +39,9 @@ namespace campvis {
MultiIndexedGeometry::MultiIndexedGeometry( MultiIndexedGeometry::MultiIndexedGeometry(
const std::vector<cgt::vec3>& vertices, const std::vector<cgt::vec3>& vertices,
const std::vector<cgt::vec3>& textureCoordinates /*= std::vector<cgt::vec3>()*/, const std::vector<cgt::vec3>& textureCoordinates /*= std::vector<cgt::vec3>()*/,
const std::vector<cgt::vec4>& colors /*= std::vector<cgt::vec4>()*/, const std::vector<cgt::vec4>& colors /*= std::vector<cgt::vec4>()*/,
const std::vector<cgt::vec3>& normals /*= std::vector<cgt::vec3>() */) const std::vector<cgt::vec3>& normals /*= std::vector<cgt::vec3>() */)
: GeometryData() : GeometryData()
, _vertices(vertices) , _vertices(vertices)
...@@ -114,9 +114,9 @@ namespace campvis { ...@@ -114,9 +114,9 @@ namespace campvis {
return GeometryData::getVideoMemoryFootprint() + (_indicesBuffer == 0 ? 0 : _indicesBuffer->getBufferSize()); return GeometryData::getVideoMemoryFootprint() + (_indicesBuffer == 0 ? 0 : _indicesBuffer->getBufferSize());
} }
void MultiIndexedGeometry::addPrimitive(const std::vector<uint16_t>& indices) { void MultiIndexedGeometry::addPrimitive(const std::vector<index_t>& indices) {
if (! _indices.empty()) if (!_indices.empty())
_indices.push_back(65535); _indices.push_back(static_cast<index_t>(-1));
_indices.insert(_indices.end(), indices.begin(), indices.end()); _indices.insert(_indices.end(), indices.begin(), indices.end());
_buffersDirty = true; _buffersDirty = true;
...@@ -156,8 +156,8 @@ namespace campvis { ...@@ -156,8 +156,8 @@ namespace campvis {
vao.bindIndexBuffer(_indicesBuffer); vao.bindIndexBuffer(_indicesBuffer);
glEnable(GL_PRIMITIVE_RESTART); glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535); glPrimitiveRestartIndex(static_cast<index_t>(-1));
glDrawElements(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0); glDrawElements(mode, static_cast<GLsizei>(_indices.size()), INDEX_BUFFER_GL_TYPE, 0);
glDisable(GL_PRIMITIVE_RESTART); glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR; LGL_ERROR;
...@@ -187,13 +187,47 @@ namespace campvis { ...@@ -187,13 +187,47 @@ namespace campvis {
vao.bindIndexBuffer(_indicesBuffer); vao.bindIndexBuffer(_indicesBuffer);
glEnable(GL_PRIMITIVE_RESTART); glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535); glPrimitiveRestartIndex(static_cast<index_t>(-1));
glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0, count); glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), INDEX_BUFFER_GL_TYPE, 0, count);
glDisable(GL_PRIMITIVE_RESTART); glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR; 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 { void MultiIndexedGeometry::createGLBuffers() const {
if (_buffersDirty) { if (_buffersDirty) {
deleteBuffers(); deleteBuffers();
...@@ -201,24 +235,24 @@ namespace campvis { ...@@ -201,24 +235,24 @@ namespace campvis {
try { try {
_indicesBuffer = new cgt::BufferObject(cgt::BufferObject::ELEMENT_ARRAY_BUFFER, cgt::BufferObject::USAGE_STATIC_DRAW); _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 = 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); _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 = 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); _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 = 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); _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 = 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); _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 = 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); _pickingBuffer->data(&_pickingInformation.front(), _pickingInformation.size() * sizeof(cgt::col4), cgt::BufferObject::UNSIGNED_BYTE, 4);
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "cgt/bounds.h" #include "cgt/bounds.h"
#include "cgt/vector.h" #include "cgt/vector.h"
#include "cgt/buffer.h"
#include "core/datastructures/geometrydata.h" #include "core/datastructures/geometrydata.h"
#include "core/datastructures/facegeometry.h" #include "core/datastructures/facegeometry.h"
...@@ -36,14 +37,19 @@ namespace campvis { ...@@ -36,14 +37,19 @@ namespace campvis {
/** /**
* Class for indexed geometry consisting of multiple primitives. * 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 * 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. * indices and number of indices for each primitive to render.
* *
* The internal OpenGL buffers are lazy-instantiated. * The internal OpenGL buffers are lazy-instantiated.
*/ */
class CAMPVIS_CORE_API MultiIndexedGeometry : public GeometryData { class CAMPVIS_CORE_API MultiIndexedGeometry : public GeometryData {
public: 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. * 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. * \param vertices The list of the vertex positions of the face.
...@@ -56,8 +62,8 @@ namespace campvis { ...@@ -56,8 +62,8 @@ namespace campvis {
const std::vector<cgt::vec3>& textureCoordinates = std::vector<cgt::vec3>(), const std::vector<cgt::vec3>& textureCoordinates = std::vector<cgt::vec3>(),
const std::vector<cgt::vec4>& colors = std::vector<cgt::vec4>(), const std::vector<cgt::vec4>& colors = std::vector<cgt::vec4>(),
const std::vector<cgt::vec3>& normals = std::vector<cgt::vec3>() const std::vector<cgt::vec3>& normals = std::vector<cgt::vec3>()
); );
/** /**
* Copy constructor * Copy constructor
* \param rhs MultiIndexedGeometry to copy * \param rhs MultiIndexedGeometry to copy
...@@ -68,7 +74,7 @@ namespace campvis { ...@@ -68,7 +74,7 @@ namespace campvis {
* Destructor, deletes VBOs/VAO if necessary. Hence, needs a valid OpenGL context * Destructor, deletes VBOs/VAO if necessary. Hence, needs a valid OpenGL context
*/ */
virtual ~MultiIndexedGeometry(); virtual ~MultiIndexedGeometry();
/** /**
* Assignment operator. * Assignment operator.
* \param rhs MultiIndexedGeometry to assign to this. * \param rhs MultiIndexedGeometry to assign to this.
...@@ -89,8 +95,8 @@ namespace campvis { ...@@ -89,8 +95,8 @@ namespace campvis {
* Add a render primitive given by a list of indices. * Add a render primitive given by a list of indices.
* \param indices Index list defining the faces. * \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. * The list of picking information colors, may be empty.
* \return _pickingInformation * \return _pickingInformation
...@@ -109,7 +115,7 @@ namespace campvis { ...@@ -109,7 +115,7 @@ namespace campvis {
* \param mode OpenGL rendering mode for this mesh * \param mode OpenGL rendering mode for this mesh
*/ */
virtual void render(GLenum mode) const; virtual void render(GLenum mode) const;
/** /**
* Renders multiple instances of this GeometryData. * Renders multiple instances of this GeometryData.
* Must be called from a valid OpenGL context. * Must be called from a valid OpenGL context.
...@@ -127,6 +133,14 @@ namespace campvis { ...@@ -127,6 +133,14 @@ namespace campvis {
/// \see GeometryData::applyTransformationToVertices /// \see GeometryData::applyTransformationToVertices
virtual void applyTransformationToVertices(const cgt::mat4& t); 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: protected:
/** /**
* Creates the OpenGL VBOs and the VAO for this face's geometry. * Creates the OpenGL VBOs and the VAO for this face's geometry.
...@@ -137,7 +151,7 @@ namespace campvis { ...@@ -137,7 +151,7 @@ namespace campvis {
/// Deletes the OpenGL BufferObject for the indices. /// Deletes the OpenGL BufferObject for the indices.
void deleteIndicesBuffer() const; 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> _vertices; ///< The list of the vertex positions of the face.
std::vector<cgt::vec3> _textureCoordinates; ///< The list of vertex texture coordinates, may be empty. 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