Work on GPU decoding.

This commit is contained in:
David Williams 2014-05-29 19:29:15 +02:00
parent 8604d1209e
commit e40eb6d762
3 changed files with 24 additions and 17 deletions

View File

@ -1,6 +1,6 @@
#version 140
in vec4 position; // This will be the position of the vertex in model-space
in uvec4 position; // This will be the position of the vertex in model-space
// The usual matrices are provided
uniform mat4 cameraToClipMatrix;
@ -13,8 +13,11 @@ out vec4 worldPosition;
void main()
{
vec4 decodedPosition = position;
decodedPosition.xyz = decodedPosition.xyz * (1.0 / 256.0);
// Standard sequence of OpenGL transformations.
worldPosition = modelToWorldMatrix * position;
worldPosition = modelToWorldMatrix * decodedPosition;
vec4 cameraPosition = worldToCameraMatrix * worldPosition;
gl_Position = cameraToClipMatrix * cameraPosition;
}

View File

@ -66,7 +66,7 @@ void createSphereInVolume(SimpleVolume<uint8_t>& volData, float fRadius)
}
}
OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::Vertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
{
// Convienient access to the vertices and indices
const auto& vecIndices = surfaceMesh.getIndices();
@ -83,7 +83,7 @@ OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::Vertex< uint8_t
// The GL_ARRAY_BUFFER will contain the list of vertex positions
glGenBuffers(1, &(meshData.vertexBuffer));
glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(Vertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW);
// and GL_ELEMENT_ARRAY_BUFFER will contain the indices
glGenBuffers(1, &(meshData.indexBuffer));
@ -92,20 +92,20 @@ OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::Vertex< uint8_t
// Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out
glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex< uint8_t >), (GLvoid*)(offsetof(Vertex< uint8_t >, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type)
glVertexAttribIPointer(0, 3, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type)
// Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor
// does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the
// shader. This is mostly just to simplify this example code - in a real application you will know whether your
// chosen surface extractor generates normals and can skip uploading them if not.
glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals.
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex< uint8_t >), (GLvoid*)(offsetof(Vertex< uint8_t >, normal)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, normal)));
// Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code
// we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here.
glEnableVertexAttribArray(2); //We're talking about shader attribute '2'
GLint size = (std::min)(sizeof(uint8_t), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type)
glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(Vertex< uint8_t >), (GLvoid*)(offsetof(Vertex< uint8_t >, data)));
glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, data)));
// We're done uploading and can now unbind.
glBindVertexArray(0);
@ -133,12 +133,16 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
std::cout << shader->log().toStdString() << std::endl;
if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/decode.frag"))
{
std::cerr << shader->log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
std::cout << shader->log().toStdString() << std::endl;
openGLWidget.setShader(shader);
//Create an empty volume and then place a sphere in it
@ -146,15 +150,15 @@ int main(int argc, char *argv[])
createSphereInVolume(volData, 30);
// Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see.
auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
//auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion());
//auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion());
// The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to
// decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code.
auto decodedMesh = decode(mesh);
//auto decodedMesh = decode(mesh);
//Pass the surface to the OpenGL window
OpenGLMeshData meshData = buildOpenGLMeshData(decodedMesh);
OpenGLMeshData meshData = buildOpenGLMeshData(mesh);
openGLWidget.addMeshData(meshData);
openGLWidget.setViewableRegion(volData.getEnclosingRegion());

View File

@ -446,7 +446,7 @@ namespace PolyVox
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000));
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInCells.getLowerZ()));
const Vector3DUint16 v3dPositionAsUint(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp));
@ -461,7 +461,7 @@ namespace PolyVox
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp);
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
surfaceVertex.position = v3dPositionAsUint;
surfaceVertex.position = v3dScaledPosition;
surfaceVertex.normal = v3dNormal;
surfaceVertex.data = uMaterial;
@ -480,7 +480,7 @@ namespace PolyVox
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000));
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()));
const Vector3DUint16 v3dPositionAsUint(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp));
@ -495,7 +495,7 @@ namespace PolyVox
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp);
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
surfaceVertex.position = v3dPositionAsUint;
surfaceVertex.position = v3dScaledPosition;
surfaceVertex.normal = v3dNormal;
surfaceVertex.data = uMaterial;
@ -514,7 +514,7 @@ namespace PolyVox
const float fInterp = static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000));
const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp);
const Vector3DUint16 v3dPositionAsUint(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
const Vector3DUint16 v3dScaledPosition(static_cast<uint16_t>(v3dPosition.getX() * 256.0f), static_cast<uint16_t>(v3dPosition.getY() * 256.0f), static_cast<uint16_t>(v3dPosition.getZ() * 256.0f));
Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp));
// The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so
@ -528,7 +528,7 @@ namespace PolyVox
const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp);
MarchingCubesVertex<typename VolumeType::VoxelType> surfaceVertex;
surfaceVertex.position = v3dPositionAsUint;
surfaceVertex.position = v3dScaledPosition;
surfaceVertex.normal = v3dNormal;
surfaceVertex.data = uMaterial;