969 lines
37 KiB
C++
969 lines
37 KiB
C++
#include "TriangleMeshVoxelizer.h"
|
|
#include <algorithm>
|
|
#include <unordered_set>
|
|
|
|
// Singletons
|
|
#include "../../PropertyLoader.h"
|
|
#include "../../shaders/ShaderLoader.h"
|
|
// Imports
|
|
#include "../../scene/PNG.h"
|
|
#include "../../scene/Scene.h"
|
|
#include "../../scene/ObjLoader.h"
|
|
#include "../Util/Stopwatch.h"
|
|
#include "../IntersectTests.h"
|
|
#include "../BitHelper.h"
|
|
|
|
bool TriangleMeshVoxelizer::Initialize() {
|
|
if (verbose) printf("Initializing BaseOctreeBuilder... ");
|
|
Stopwatch watch;
|
|
watch.Reset();
|
|
|
|
if (!InitializeGLFW())
|
|
return false;
|
|
|
|
glewExperimental = GL_TRUE;
|
|
if (glewInit() != GLEW_OK) {
|
|
fprintf(stderr, "Failed to initialize GLEW\n");
|
|
return false;
|
|
}
|
|
if (verbose) printf("Initialization took %d ms \n", (int)(watch.GetTime() * 1000));
|
|
return true;
|
|
}
|
|
|
|
bool TriangleMeshVoxelizer::LoadScene(const std::string& sceneFileName)
|
|
{
|
|
if (verbose) printf("Reading scene \"%s\"... ", sceneFileName.c_str());
|
|
Stopwatch watch; watch.Reset();
|
|
if (!mObjLoader->Load(sceneFileName.c_str(), mScene)) return false;
|
|
if (verbose) printf("Done in %d ms\n", (int)(watch.GetTime() * 1000));
|
|
|
|
// Prepare OpenGL for rendering
|
|
LoadScene(mScene);
|
|
LoadShaders(mScene);
|
|
|
|
// Calculate scene details
|
|
CalculateBoundingBox(mScene);
|
|
CalculateRootNode();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool TriangleMeshVoxelizer::UnloadScene()
|
|
{
|
|
// Clear the texture from memory
|
|
for (Mesh mesh : mScene.meshes)
|
|
glDeleteTextures(1, &mTextures[mesh.texture]);
|
|
// Clear the scene
|
|
mScene = Scene();
|
|
return true;
|
|
}
|
|
|
|
std::vector<glm::uvec3> TriangleMeshVoxelizer::GetValidCoords(unsigned8 scale)
|
|
{
|
|
if (scale == 0) return std::vector<glm::uvec3>(1, glm::uvec3(0));
|
|
else return CalculateValidSubtrees(scale);
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::Voxelize(unsigned8 scale, unsigned8 partScale, glm::uvec3 partCoord, const std::function<void(const VoxelInfo&, bool best)>& nodeAdder, bool colors, bool normals, bool reflectivity)
|
|
{
|
|
mReadColors = colors; mReadNormals = normals; mReadReflectivity = reflectivity;
|
|
|
|
float stepSize = 1.f / (float)BitHelper::Exp2(scale - partScale);
|
|
mCurPassRootSize = mRootSize * stepSize;
|
|
mCurPassGridSize = (unsigned)(BitHelper::Exp2(partScale));
|
|
|
|
InitDepthPeel();
|
|
DepthPeel(partCoord, nodeAdder);
|
|
TerminateDepthPeel();
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::CalculateBoundingBox(Scene& scene)
|
|
{
|
|
// Left = minX
|
|
sceneLeft = (*std::min_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.x < b.x; })).x;
|
|
// Right = maxX
|
|
sceneRight = (*std::max_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.x < b.x; })).x;
|
|
// Bottom = minY
|
|
sceneBottom = (*std::min_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.y < b.y; })).y;
|
|
// Top = maxY
|
|
sceneTop = (*std::max_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.y < b.y; })).y;
|
|
// Near = maxZ (OpenGL is weird ;) )
|
|
sceneNear = (*std::max_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.z < b.z; })).z;
|
|
// Far = minZ (OpenGL is weird ;) )
|
|
sceneFar = (*std::min_element(scene.vertices.begin(), scene.vertices.end(), [](glm::vec3 a, glm::vec3 b) { return a.z < b.z; })).z;
|
|
|
|
float width = sceneRight - sceneLeft;
|
|
float height = sceneTop - sceneBottom;
|
|
float depth = sceneNear - sceneFar;
|
|
float cubesize = std::max(std::max(width, height), depth);
|
|
float boundingBoxOffset = cubesize * 0.01f;
|
|
sceneLeft -= boundingBoxOffset;
|
|
sceneRight += boundingBoxOffset;
|
|
sceneBottom -= boundingBoxOffset;
|
|
sceneTop += boundingBoxOffset;
|
|
sceneNear += boundingBoxOffset;
|
|
sceneFar -= boundingBoxOffset;
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::CalculateRootNode()
|
|
{
|
|
float width = sceneRight - sceneLeft;
|
|
float height = sceneTop - sceneBottom;
|
|
float depth = sceneNear - sceneFar;
|
|
|
|
mRootSize = std::max(std::max(width, height), depth);
|
|
|
|
// Line below centers the scene (but puts it on the bottom)
|
|
mRootCenter = glm::vec3(sceneLeft + (width * 0.5f), sceneBottom + (0.5f * mRootSize), sceneFar + (0.5f * depth));
|
|
|
|
// Line below places the scene on the left bottom far position (optimal for compression).
|
|
//mRootCenter = glm::vec3(sceneLeft, sceneBottom, sceneFar) + 0.5f * mRootSize;
|
|
//mRootSize *= 1.01f;
|
|
}
|
|
|
|
std::vector<glm::uvec3> TriangleMeshVoxelizer::CalculateValidSubtrees(unsigned8 level)
|
|
{
|
|
Stopwatch watch; watch.Reset();
|
|
if (verbose) printf("Calculating valid subtrees... ");
|
|
unsigned steps = 1 << level;
|
|
glm::vec3 minPosition = mRootCenter - (mRootSize * 0.5f);
|
|
glm::vec3 maxPosition = mRootCenter + (mRootSize * 0.5f);
|
|
glm::vec3 cellSize = glm::vec3(mRootSize) / (float)steps;
|
|
|
|
auto uvec3hasher = [&](glm::uvec3 v) -> std::size_t { return (size_t)(v.x + v.y * steps + v.z * steps * steps); };
|
|
std::unordered_set < glm::uvec3, decltype(uvec3hasher)> validCoords(10, uvec3hasher);
|
|
// For all triangles in the scene
|
|
for (size_t i = 0; i + 2 < mScene.indices.size(); i += 3)
|
|
{
|
|
unsigned a = mScene.indices[i];
|
|
unsigned b = mScene.indices[i + 1];
|
|
unsigned c = mScene.indices[i + 2];
|
|
glm::vec3 triangle[3] = { mScene.vertices[a], mScene.vertices[b], mScene.vertices[c] };
|
|
// Build AABB bounding box around triangle:
|
|
glm::vec3 triangleMin = glm::min(glm::min(triangle[0], triangle[1]), triangle[2]);
|
|
glm::vec3 triangleMax = glm::max(glm::max(triangle[0], triangle[1]), triangle[2]);
|
|
// Process only the cells within this bounding box
|
|
glm::vec3 triangleMinCoordsF = glm::floor((triangleMin - minPosition) / cellSize);
|
|
glm::uvec3 triangleMinCoords(triangleMinCoordsF.x, triangleMinCoordsF.y, triangleMinCoordsF.z);
|
|
glm::vec3 triangleMaxCoordsF = glm::ceil((triangleMax - minPosition) / cellSize);
|
|
glm::uvec3 triangleMaxCoords(triangleMaxCoordsF.x, triangleMaxCoordsF.y, triangleMaxCoordsF.z);
|
|
// If there is an intersection, add the coord to validCoords
|
|
for (unsigned x = triangleMinCoords.x; x < triangleMaxCoords.x; x++)
|
|
for (unsigned y = triangleMinCoords.y; y < triangleMaxCoords.y; y++)
|
|
for (unsigned z = triangleMinCoords.z; z < triangleMaxCoords.z; z++)
|
|
{
|
|
glm::vec3 coordF(x, y, z);
|
|
glm::vec3 cellMinPosition = minPosition + cellSize * coordF;
|
|
glm::vec3 cellMaxPosition = cellMinPosition + cellSize;
|
|
if (IntersectTests::BoxTriangleIntersection(cellMinPosition, cellMaxPosition, triangle))
|
|
{
|
|
validCoords.insert(glm::uvec3(x, y, z));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<glm::uvec3> res;
|
|
for (glm::uvec3 v : validCoords)
|
|
res.push_back(v);
|
|
if (verbose) printf("Found %llu / %u valid subtrees in %u ms.\n", (unsigned64)validCoords.size(), steps * steps * steps, (unsigned)(watch.GetTime() * 1000));
|
|
return res;
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::InitDepthPeel()
|
|
{
|
|
Stopwatch watch; watch.Reset();
|
|
if (verbose) printf("Initializing Depth peeling... ");
|
|
|
|
depthData = new std::vector<GLfloat>(mCurPassGridSize * mCurPassGridSize);
|
|
colorData = new std::vector<GLubyte>(mReadColors ? mCurPassGridSize * mCurPassGridSize * 3 : 0);
|
|
normalData = new std::vector<GLfloat>(mReadNormals ? mCurPassGridSize * mCurPassGridSize * 3 : 0);
|
|
angleData = new std::vector<GLfloat>(mReadColors && interpolateColors ? mCurPassGridSize * mCurPassGridSize : 0);
|
|
reflectivityData = new std::vector<GLfloat>(mReadReflectivity ? mCurPassGridSize * mCurPassGridSize : 0);
|
|
|
|
// The framebuffer, which regroups 0, 1, or more textures, and 0 or 1 depth buffer.
|
|
glGenFramebuffers(1, &mFramebufferName);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
|
|
|
|
// Create a framebuffer texture containing the colors of the current frame
|
|
//if (readColors)
|
|
//{
|
|
glGenTextures(1, &mColorTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mColorTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mCurPassGridSize, mCurPassGridSize, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
//}
|
|
|
|
//if (readNormals)
|
|
//{
|
|
glGenTextures(1, &mNormalTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mNormalTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mCurPassGridSize, mCurPassGridSize, 0, GL_RGB, GL_FLOAT, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
//}
|
|
|
|
// Create a framebuffer texture containing the angle of the vector pointing to the camera and the normal of the triangle
|
|
//if (readColors & interpolateColors)
|
|
//{
|
|
glGenTextures(1, &mAngleTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mAngleTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, mCurPassGridSize, mCurPassGridSize, 0, GL_RED, GL_FLOAT, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
//}
|
|
|
|
glGenTextures(1, &mReflectivityTexture);
|
|
glBindTexture(GL_TEXTURE_2D, mReflectivityTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, mCurPassGridSize, mCurPassGridSize, 0, GL_RED, GL_FLOAT, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
// Create a first texture to contain a depth map
|
|
glGenTextures(1, &mDepthTexture1);
|
|
glBindTexture(GL_TEXTURE_2D, mDepthTexture1);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, mCurPassGridSize, mCurPassGridSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
// Create a second texture to contain another depth map
|
|
glGenTextures(1, &mDepthTexture2);
|
|
glBindTexture(GL_TEXTURE_2D, mDepthTexture2);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, mCurPassGridSize, mCurPassGridSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
// Build a depthbuffer for correct depth testing in the framebuffer.
|
|
glGenRenderbuffers(1, &mDepthRenderbuffer);
|
|
glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer);
|
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, mCurPassGridSize, mCurPassGridSize);
|
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer);
|
|
|
|
// Set "depthTexture" as our GL_DEPTH_ATTACHMENT
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTexture1, 0);
|
|
//if (readColors)
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0);
|
|
//if (readColors && interpolateColors)
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, mAngleTexture, 0);
|
|
//if (readNormals)
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, mNormalTexture, 0);
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, mReflectivityTexture, 0);
|
|
|
|
// Set the list of draw buffers.
|
|
GLenum DrawBuffers[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
|
|
glDrawBuffers(4, DrawBuffers); // "3" is the size of DrawBuffers
|
|
|
|
// Always check that our framebuffer is ok
|
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
|
std::cout << "Framebuffer broke. Building the octree failed" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// The fullscreen quad's FBO
|
|
static const GLfloat g_quad_vertex_buffer_data[] = {
|
|
-1.0f, -1.0f, 0.0f,
|
|
1.0f, -1.0f, 0.0f,
|
|
-1.0f, 1.0f, 0.0f,
|
|
-1.0f, 1.0f, 0.0f,
|
|
1.0f, -1.0f, 0.0f,
|
|
1.0f, 1.0f, 0.0f,
|
|
};
|
|
|
|
glGenBuffers(1, &mQuadVertexbuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexbuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
|
|
|
|
|
|
mQuadProgram = mShaderLoader->LoadShader("RenderTexture.vert", "RenderTexture.frag");
|
|
mImageRenderDepthTexID = glGetUniformLocation(mQuadProgram, "depthTexture");
|
|
mImageRenderColorTexID = glGetUniformLocation(mQuadProgram, "renderTexture");
|
|
mImageRenderUseDepthID = glGetUniformLocation(mQuadProgram, "showDepth");
|
|
|
|
if (verbose) printf("Depth peeling initialized in %d ms\n", (int)(watch.GetTime() * 1000));
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::DepthPeel(glm::uvec3 coord, const std::function<void(const VoxelInfo&, bool best)>& nodeAdder) {
|
|
mMissingNodes.clear();
|
|
glm::vec3 coordF(coord.x, coord.y, coord.z);
|
|
mCurPassRootCenter = (mRootCenter - (mRootSize * 0.5f)) + coordF * mCurPassRootSize + mCurPassRootSize * 0.5f;
|
|
|
|
unsigned frames = 0;
|
|
bool done = false;
|
|
Direction startDir = Direction::Top;
|
|
|
|
Direction curDir = startDir;
|
|
unsigned lastFrames = frames;
|
|
|
|
GLuint oldDepthTexture = mDepthTexture2;
|
|
GLuint curDepthTexture = mDepthTexture1;
|
|
|
|
SetDirection(curDir, oldDepthTexture);
|
|
|
|
Stopwatch mainWatch; mainWatch.Reset();
|
|
Stopwatch watch; watch.Reset();
|
|
Stopwatch frameWatch; frameWatch.Reset();
|
|
do {
|
|
if (!pixelsLeft) {
|
|
// Print details about the last direction
|
|
if (verbose) printf("Processed in %6d ms, %5.2f FPS\n", (int)(watch.GetTime() * 1000), (double)(frames - lastFrames) / watch.GetTime());
|
|
watch.Reset(); lastFrames = frames;
|
|
|
|
// Move to the next direction
|
|
unsigned curDirInt = static_cast<unsigned>(curDir);
|
|
curDir = static_cast<Direction>(++curDirInt % 3);
|
|
// We're done if we processed all directions
|
|
if (startDir == curDir)
|
|
break;
|
|
SetDirection(curDir, oldDepthTexture);
|
|
}
|
|
frames++;
|
|
|
|
// ************************************************************************************************************************************ //
|
|
// Render to our framebuffer //
|
|
// ************************************************************************************************************************************ //
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
|
|
glViewport(0, 0, mCurPassGridSize, mCurPassGridSize); // Render on the whole framebuffer, complete from the lower left corner to the upper right
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, curDepthTexture, 0);
|
|
|
|
// Clear the screen
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
RenderScene(curDir, oldDepthTexture, (float)mCurPassGridSize, (float)mCurPassGridSize);
|
|
|
|
// ************************************************************************************************************************************ //
|
|
// Render to what the user sees (before processing to improve performance) //
|
|
// ************************************************************************************************************************************ //
|
|
do
|
|
{
|
|
// Only render the debug image if the last debug image was drawn more than 1/60th of a second ago
|
|
if (manual || frameWatch.GetTime() > 1.0 / 60.0 || frames == 1)
|
|
{
|
|
frameWatch.Reset();
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
glViewport(0, 0, mWidth, mHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right
|
|
|
|
|
|
// Clear the screen
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
if (renderScene)
|
|
{
|
|
RenderScene(curDir, oldDepthTexture, (float)mWidth, (float)mHeight);
|
|
}
|
|
else
|
|
{
|
|
RenderDebugImage(curDepthTexture);
|
|
}
|
|
|
|
// Swap buffers
|
|
glfwSwapBuffers(mWindow);
|
|
glfwPollEvents();
|
|
}
|
|
} while (manual && glfwGetKey(mWindow, GLFW_KEY_SPACE) != GLFW_PRESS);
|
|
|
|
// Wait until the user releases the space bar
|
|
do { glfwPollEvents(); } while (glfwGetKey(mWindow, GLFW_KEY_SPACE) == GLFW_PRESS);
|
|
|
|
// ************************************************************************************************************************************ //
|
|
// Process the current layer, add all voxels to the tree //
|
|
// ************************************************************************************************************************************ //
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName);
|
|
glReadPixels(startTexX, startTexY, texWidth, texHeight, GL_DEPTH_COMPONENT, GL_FLOAT, &depthData->at(0));
|
|
colorTexWidth = BitHelper::CeilToNearestPowerOfTwo(texWidth);
|
|
if (mReadColors)
|
|
{
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
// When reading the colors, read the whole image, since something goes wrong with indices that aren't a power of two it seems...
|
|
glReadPixels(startTexX, startTexY, colorTexWidth, texHeight, GL_RGB, GL_UNSIGNED_BYTE, &colorData->at(0));
|
|
}
|
|
if (mReadColors && interpolateColors)
|
|
{
|
|
glReadBuffer(GL_COLOR_ATTACHMENT1);
|
|
glReadPixels(startTexX, startTexY, colorTexWidth, texHeight, GL_RED, GL_FLOAT, &angleData->at(0));
|
|
}
|
|
if (mReadNormals)
|
|
{
|
|
glReadBuffer(GL_COLOR_ATTACHMENT2);
|
|
glReadPixels(startTexX, startTexY, colorTexWidth, texHeight, GL_RGB, GL_FLOAT, &normalData->at(0));
|
|
}
|
|
if (mReadReflectivity)
|
|
{
|
|
glReadBuffer(GL_COLOR_ATTACHMENT3);
|
|
glReadPixels(startTexX, startTexY, colorTexWidth, texHeight, GL_RED, GL_FLOAT, &reflectivityData->at(0));
|
|
}
|
|
SetGridData(curDir, nodeAdder);
|
|
|
|
// Swap the old and new depthtexture, thus advancing to the next layer
|
|
oldDepthTexture = oldDepthTexture == mDepthTexture1 ? mDepthTexture2 : mDepthTexture1;
|
|
curDepthTexture = curDepthTexture == mDepthTexture1 ? mDepthTexture2 : mDepthTexture1;
|
|
firstPass = false;
|
|
} while (glfwGetKey(mWindow, GLFW_KEY_ESCAPE) != GLFW_PRESS && !done);
|
|
|
|
if (verbose) printf("Adding missing nodes...");
|
|
if (mReadColors && interpolateColors)
|
|
{
|
|
// Add the missing nodes in the current subtree
|
|
for (auto node : mMissingNodes)
|
|
nodeAdder(node.second, false);
|
|
}
|
|
|
|
if (verbose) printf("Depth peeling took %d ms.\n", (int)(mainWatch.GetTime() * 1000));
|
|
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::TerminateDepthPeel()
|
|
{
|
|
// Cleanup the used resources from GPU
|
|
glDeleteFramebuffers(1, &mFramebufferName);
|
|
glDeleteRenderbuffers(1, &mDepthRenderbuffer);
|
|
glDeleteTextures(1, &mDepthTexture1);
|
|
glDeleteTextures(1, &mDepthTexture2);
|
|
/*if (readColors)*/ glDeleteTextures(1, &mColorTexture);
|
|
/*if (readNormals)*/ glDeleteTextures(1, &mNormalTexture);
|
|
glDeleteTextures(1, &mAngleTexture);
|
|
glDeleteTextures(1, &mReflectivityTexture);
|
|
glDeleteBuffers(1, &mQuadVertexbuffer);
|
|
glDeleteProgram(mQuadProgram);
|
|
|
|
delete depthData;
|
|
delete colorData;
|
|
delete normalData;
|
|
delete angleData;
|
|
delete reflectivityData;
|
|
}
|
|
|
|
glm::ivec3 TriangleMeshVoxelizer::WorldToGrid(glm::vec3 world)
|
|
{
|
|
float halfRootSize = mCurPassRootSize * 0.5f;
|
|
float left = mCurPassRootCenter.x - halfRootSize;
|
|
float bottom = mCurPassRootCenter.y - halfRootSize;
|
|
float far = mCurPassRootCenter.z - halfRootSize;
|
|
return glm::ivec3(
|
|
((world.x - left) / mCurPassRootSize) * mCurPassGridSize,
|
|
((world.y - bottom) / mCurPassRootSize) * mCurPassGridSize,
|
|
((world.z - far) / mCurPassRootSize) * mCurPassGridSize);
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::SetDirection(Direction dir, unsigned oldDepthTexture)
|
|
{
|
|
if (verbose) printf("Processing %s view... ", dir == Top ? "Top " : (dir == Side ? "Side " : "Front"));
|
|
float one = 1;
|
|
firstPass = true; // First pass in this direction
|
|
pixelsLeft = true; // Assume there are at least some pixels in this direction
|
|
glClearTexImage(oldDepthTexture, 0, GL_DEPTH_COMPONENT32, GL_FLOAT, &one); // Clear the old depth texture, makes sure we don't use old depth peeling values for a new direction
|
|
// Reset AABB for texture read optimalization (based on scene size within octree)
|
|
glm::ivec3 lbf = WorldToGrid(glm::vec3(sceneLeft, sceneBottom, sceneFar));
|
|
glm::ivec3 rtn = WorldToGrid(glm::vec3(sceneRight, sceneTop, sceneNear));
|
|
// Make sure the coordinates are actually on the grid
|
|
lbf = glm::clamp(lbf, glm::ivec3(0), glm::ivec3(mCurPassGridSize));
|
|
rtn = glm::clamp(rtn, glm::ivec3(0), glm::ivec3(mCurPassGridSize));
|
|
texWidth = dir == Side ? rtn.z - lbf.z : rtn.x - lbf.x;
|
|
texHeight = dir == Top ? rtn.z - lbf.z : rtn.y - lbf.y;
|
|
startTexX = dir == Side ? lbf.z : lbf.x;
|
|
startTexY = dir == Top ? mCurPassGridSize - lbf.z - texHeight : lbf.y;
|
|
|
|
|
|
// Make sure we're looking in the right direction
|
|
Transform(dir);
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::Transform(Direction dir) {
|
|
|
|
float halfRootSize = mCurPassRootSize * 0.5f;
|
|
// Calculate the edges of the cube in world space
|
|
float left = mCurPassRootCenter.x - halfRootSize;
|
|
// float right = mCurPassRootCenter.x + halfRootSize;
|
|
// float bottom = mCurPassRootCenter.y - halfRootSize;
|
|
float top = mCurPassRootCenter.y + halfRootSize;
|
|
float near = mCurPassRootCenter.z + halfRootSize;
|
|
// float far = mCurPassRootCenter.z - halfRootSize;
|
|
|
|
glm::vec3 viewPoint = mCurPassRootCenter;
|
|
switch (dir)
|
|
{
|
|
case Side: viewPoint.x = left; break;
|
|
case Top: viewPoint.y = top; break;
|
|
case Front: viewPoint.z = near; break;
|
|
}
|
|
|
|
glm::mat4 mViewMatrix = glm::lookAt(viewPoint, mCurPassRootCenter, dir == Top ? glm::vec3(0, 0, -1) : glm::vec3(0, 1, 0));
|
|
mProjectionMatrix = glm::ortho(-halfRootSize, +halfRootSize, -halfRootSize, +halfRootSize, 0.f, mCurPassRootSize);
|
|
mMVP = mProjectionMatrix * mViewMatrix;
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::SetGridData(Direction dir, const std::function<void(const VoxelInfo&, bool best)>& nodeAdder) {
|
|
// Check if there are any pixels left
|
|
pixelsLeft = false;
|
|
unsigned minX = mCurPassGridSize, minY = mCurPassGridSize, maxX = 0, maxY = 0;
|
|
|
|
glm::u8vec3 color(0);
|
|
glm::vec3 normal(0);
|
|
float reflectivity = 0.f;
|
|
float depth;
|
|
float minAngle = 0.25f * sqrtf(2);
|
|
|
|
// From OpenGL Documentation:
|
|
// The data for the ith pixel in the jth row is placed in location j * width + i
|
|
for (unsigned j = 0; j < texHeight; j++) // row
|
|
for (unsigned i = 0; i < texWidth; i++) // col
|
|
{
|
|
depth = depthData->at(i + j * texWidth);
|
|
if (depth == 1.f)
|
|
continue;
|
|
|
|
pixelsLeft |= true;
|
|
|
|
unsigned x = i + startTexX;
|
|
unsigned y = j + startTexY;
|
|
|
|
// Find min and max for both directions in the image to determine bounding box for next run.
|
|
minX = std::min(minX, x);
|
|
minY = std::min(minY, y);
|
|
maxX = std::max(maxX, x);
|
|
maxY = std::max(maxY, y);
|
|
|
|
// Get the color of the texel
|
|
unsigned texCoord = i + (j * colorTexWidth);
|
|
if (mReadColors)
|
|
{
|
|
unsigned colorTexCoord = (3 * texCoord);
|
|
color = glm::u8vec3(colorData->at(colorTexCoord), colorData->at(colorTexCoord + 1), colorData->at(colorTexCoord + 2));
|
|
}
|
|
if (mReadNormals)
|
|
{
|
|
unsigned normalTexCoord = (3 * texCoord);
|
|
normal = (glm::vec3(normalData->at(normalTexCoord), normalData->at(normalTexCoord + 1), normalData->at(normalTexCoord + 2)) * 2.0f) - 1.0f;
|
|
}
|
|
if (mReadReflectivity)
|
|
{
|
|
reflectivity = reflectivityData->at(texCoord);
|
|
}
|
|
//color = glm::u8vec3(glm::abs(normal) * 255.0f);
|
|
|
|
// Based on the direction, current location and value of the pixel, mark one of the voxels.
|
|
// We're always looking from zero to higher values in the grid
|
|
unsigned gridDepth = (unsigned)(depth * (float)mCurPassGridSize);
|
|
glm::uvec3 coord;
|
|
switch (dir)
|
|
{
|
|
case Side: coord = glm::uvec3(gridDepth, y, x); break;
|
|
case Top: coord = glm::uvec3(x, mCurPassGridSize - gridDepth - 1, mCurPassGridSize - y - 1); break;
|
|
case Front: coord = glm::uvec3(x, y, mCurPassGridSize - gridDepth - 1); break;
|
|
}
|
|
|
|
VoxelInfo info(coord, color, normal, 0.f, reflectivity);
|
|
if (mReadColors && interpolateColors)
|
|
{
|
|
info.angle = angleData->at(texCoord);
|
|
if (info.angle < minAngle)
|
|
{
|
|
auto missingNode = mMissingNodes.find(coord);
|
|
if (missingNode == mMissingNodes.end())
|
|
mMissingNodes.insert(std::make_pair(coord, info));
|
|
else if (missingNode->second.angle < info.angle)
|
|
missingNode->second = info;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
nodeAdder(info, true);
|
|
}
|
|
startTexX = minX;
|
|
startTexY = minY;
|
|
texWidth = maxX -minX + 1;
|
|
texHeight = maxY - minY + 1;
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::LoadScene(Scene& scene)
|
|
{
|
|
Stopwatch watch;
|
|
watch.Reset();
|
|
if (verbose) printf("Loading scene... ");
|
|
|
|
TriangleMeshVoxelizer::Load2DTexture(mMissingTexture, interpolateColors);
|
|
|
|
for (Mesh mesh : scene.meshes)
|
|
{
|
|
TriangleMeshVoxelizer::Load2DTexture(mesh.texture, interpolateColors);
|
|
}
|
|
|
|
//glDisable(GL_DEPTH_TEST);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glCullFace(GL_FRONT_AND_BACK);
|
|
|
|
// Generate and bind vertex array object
|
|
glGenVertexArrays(1, &mVertexArrayID);
|
|
glBindVertexArray(mVertexArrayID);
|
|
|
|
// Generate vertex buffer
|
|
glGenBuffers(1, &mVertexBuffer);
|
|
glm::vec3 zeroVec(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
|
if (!scene.vertices.empty())
|
|
glBufferData(GL_ARRAY_BUFFER, scene.vertices.size() * sizeof(glm::vec3), &scene.vertices[0], GL_STATIC_DRAW);
|
|
else
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), &zeroVec, GL_STATIC_DRAW);
|
|
|
|
// Generate texture coordinate buffer
|
|
glGenBuffers(1, &mTextureBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mTextureBuffer);
|
|
if (!scene.uvs.empty())
|
|
glBufferData(GL_ARRAY_BUFFER, scene.uvs.size() * sizeof(glm::vec2), &scene.uvs[0], GL_STATIC_DRAW);
|
|
else
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2), &zeroVec, GL_STATIC_DRAW);
|
|
|
|
// Generate the vertex color buffer
|
|
glGenBuffers(1, &mVertexColorBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexColorBuffer);
|
|
if (!scene.colors.empty())
|
|
glBufferData(GL_ARRAY_BUFFER, scene.colors.size() * sizeof(glm::vec3), &scene.colors[0], GL_STATIC_DRAW);
|
|
else
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), &zeroVec, GL_STATIC_DRAW);
|
|
|
|
// Generate normal buffer
|
|
glGenBuffers(1, &mNormalBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mNormalBuffer);
|
|
if (!scene.normals.empty())
|
|
glBufferData(GL_ARRAY_BUFFER, scene.normals.size() * sizeof(glm::vec3), &scene.normals[0], GL_STATIC_DRAW);
|
|
else
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), &zeroVec, GL_STATIC_DRAW);
|
|
|
|
// Generate element buffer
|
|
glGenBuffers(1, &mElementBuffer);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
|
|
if (!scene.indices.empty())
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, scene.indices.size() * sizeof(unsigned), &scene.indices[0], GL_STATIC_DRAW);
|
|
|
|
if (verbose) printf("Scene loaded in %d ms\n", (int)(watch.GetTime() * 1000));
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::RenderScene(Direction dir, unsigned oldDepthTexture, float viewPortWidth, float viewPortHeight)
|
|
{
|
|
// Enable the shaders
|
|
glUseProgram(mDefaultProgramID);
|
|
|
|
// Bind old depth texture to texture unit 0
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, oldDepthTexture);
|
|
// Tell the fragment shader to use texture unit 0 for the old depth texture
|
|
glUniform1i(mOldDepthBufferSampler, 0);
|
|
glUniform1i(mFirstPass, firstPass);
|
|
glUniform1f(mDepthmargin, 1.0f / (float)mCurPassGridSize); // Half a cell margin
|
|
glm::vec3 cameraDir((dir == Side) ? -1.f : 0, (dir == Top) ? -1.f : 0, (dir == Front) ? 1.f : 0);
|
|
glUniform3f(mCameraDir, cameraDir.x, cameraDir.y, cameraDir.z);
|
|
glProgramUniformMatrix4fv(mDefaultProgramID, mPropertyLoader->GetIntProperty("shader_MVP"), 1, GL_FALSE, &mMVP[0][0]);
|
|
|
|
// Enable vertex attributes array (positions)
|
|
glEnableVertexAttribArray(mPropertyLoader->GetIntProperty("shader_vertexPosition"));
|
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
|
glVertexAttribPointer(
|
|
mPropertyLoader->GetIntProperty("shader_vertexPosition"), // Attribute positions
|
|
3, // Size
|
|
GL_FLOAT, // Type
|
|
GL_FALSE, // Normalized
|
|
0, // Stride
|
|
(void*)0 // Array buffer offset
|
|
);
|
|
|
|
// Enable vertex attributes array (texture coordinates)
|
|
glEnableVertexAttribArray(mPropertyLoader->GetIntProperty("shader_vertexUV"));
|
|
glBindBuffer(GL_ARRAY_BUFFER, mTextureBuffer);
|
|
glVertexAttribPointer(
|
|
mPropertyLoader->GetIntProperty("shader_vertexUV"), // Attribute texture coordinates
|
|
2, // Size
|
|
GL_FLOAT, // Type
|
|
GL_FALSE, // Normalized
|
|
0, // Stride
|
|
(void*)0 // Array buffer offset
|
|
);
|
|
|
|
// Enable vertex attributes array (vertex colors)
|
|
glEnableVertexAttribArray(stoi(mPropertyLoader->GetProperty("shader_vertexColor")));
|
|
glBindBuffer(GL_ARRAY_BUFFER, mVertexColorBuffer);
|
|
glVertexAttribPointer(
|
|
stoi(mPropertyLoader->GetProperty("shader_vertexColor")), // Attribute texture coordinates
|
|
3, // Size
|
|
GL_FLOAT, // Type
|
|
GL_FALSE, // Normalized
|
|
0, // Stride
|
|
(void*)0 // Array buffer offset
|
|
);
|
|
// Enable vertex attributes array (normals)
|
|
glEnableVertexAttribArray(stoi(mPropertyLoader->GetProperty("shader_vertexNormal")));
|
|
glBindBuffer(GL_ARRAY_BUFFER, mNormalBuffer);
|
|
glVertexAttribPointer(
|
|
stoi(mPropertyLoader->GetProperty("shader_vertexNormal")), // Attribute normals
|
|
3, // Size
|
|
GL_FLOAT, // Type
|
|
GL_FALSE, // Normalized
|
|
0, // Stride
|
|
(void*)0 // Array buffer offset
|
|
);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Render meshes
|
|
for (Mesh mesh : mScene.meshes) {
|
|
// Bind texture to texture unit 1
|
|
glActiveTexture(GL_TEXTURE1);
|
|
auto loadedTexture = mTextures.find(mesh.texture);
|
|
if (loadedTexture == mTextures.end() || mesh.texture == "")
|
|
glBindTexture(GL_TEXTURE_2D, mTextures[mMissingTexture]);
|
|
else
|
|
glBindTexture(GL_TEXTURE_2D, mTextures[mesh.texture]);
|
|
// Set texture sampler to texture unit 1
|
|
glUniform1i(mTextureSampler, 1);
|
|
glUniform1f(mReflectivity, mesh.reflectivity);
|
|
|
|
|
|
// Draw the element arrays
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mElementBuffer);
|
|
glDrawElements(
|
|
GL_TRIANGLES, // Drawing mode
|
|
mesh.size, // Element count
|
|
GL_UNSIGNED_INT, // Type
|
|
(void*)(mesh.offset * sizeof(unsigned)) // Element array buffer offset
|
|
);
|
|
}
|
|
|
|
// Disable vertex attributes arrays
|
|
glDisableVertexAttribArray(stoi(mPropertyLoader->GetProperty("shader_vertexPosition")));
|
|
glDisableVertexAttribArray(stoi(mPropertyLoader->GetProperty("shader_vertexUV")));
|
|
glDisableVertexAttribArray(stoi(mPropertyLoader->GetProperty("shader_vertexNormal")));
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::RenderDebugImage(GLuint depthTexture)
|
|
{
|
|
// Use our shader
|
|
glUseProgram(mQuadProgram);
|
|
|
|
// Bind our depth texture in Texture Unit 0
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, depthTexture);
|
|
// Set our sampler to user Texture Unit 0 for depth texture
|
|
glUniform1i(mImageRenderDepthTexID, 0);
|
|
|
|
// Bind our color texture in Texture Unit 1
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, (!mReadColors && mReadNormals) ? mNormalTexture : mColorTexture);
|
|
glUniform1i(mImageRenderColorTexID, 1);
|
|
|
|
glUniform1i(mImageRenderUseDepthID, !mReadColors && !mReadNormals ? 1 : 0);
|
|
|
|
// 1rst attribute buffer : vertices
|
|
glEnableVertexAttribArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mQuadVertexbuffer);
|
|
glVertexAttribPointer(
|
|
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
|
|
3, // size
|
|
GL_FLOAT, // type
|
|
GL_FALSE, // normalized?
|
|
0, // stride
|
|
(void*)0 // array buffer offset
|
|
);
|
|
|
|
// Draw the triangles !
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
|
|
|
|
glDisableVertexAttribArray(0);
|
|
}
|
|
|
|
//************************************
|
|
// Returns the index of the texture to access it in the texture vector
|
|
//************************************
|
|
size_t TriangleMeshVoxelizer::Load2DTexture(std::string filename, bool interpolation) {
|
|
if (textureLoaded(filename))
|
|
return mTextures[filename];
|
|
|
|
unsigned textureID;
|
|
glGenTextures(1, &textureID);
|
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
|
|
|
PNG* png = new PNG(filename.c_str());
|
|
|
|
if (png->Initialized())
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, png->W(), png->H(), 0, GL_RGBA, GL_UNSIGNED_BYTE, png->Data());
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
if (interpolation)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
glGenerateMipmap(GL_TEXTURE_2D);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
|
|
delete png;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
mTextures.insert(std::pair<std::string, unsigned>(filename, textureID));
|
|
|
|
return mTextures.size() - 1;
|
|
}
|
|
|
|
bool TriangleMeshVoxelizer::textureLoaded(std::string filename) {
|
|
auto it = mTextures.find(filename);
|
|
return it != mTextures.end();
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::ReloadShaders(const Scene& scene) {
|
|
glDeleteProgram(mDefaultProgramID);
|
|
LoadShaders(scene);
|
|
}
|
|
|
|
void TriangleMeshVoxelizer::LoadShaders(const Scene& scene)
|
|
{
|
|
Stopwatch watch; watch.Reset();
|
|
if (verbose) printf("Loading shaders... ");
|
|
std::map<std::string, std::string> additionalProperties;
|
|
// TODO: support scenes that contain texture-based and vertex-color based meshes.
|
|
if (scene.meshes[0].hasUVs && scene.meshes[0].hasVertexColors)
|
|
additionalProperties.insert(std::pair<std::string, std::string>("colorType", "TEXTURE_AND_VERTEX_COLORS"));
|
|
else if (scene.meshes[0].hasVertexColors)
|
|
additionalProperties.insert(std::pair<std::string, std::string>("colorType", "VERTEX_COLORS"));
|
|
else if (scene.meshes[0].hasUVs)
|
|
additionalProperties.insert(std::pair<std::string, std::string>("colorType", "TEXTURE_COLORS"));
|
|
else
|
|
additionalProperties.insert(std::pair<std::string, std::string>("colorType", "NO_COLORS"));
|
|
|
|
// Initialize and use shader program
|
|
mDefaultProgramID = mShaderLoader->LoadShader("DepthPeel.vert", "DepthPeel.frag", additionalProperties);
|
|
|
|
// Get texture ID
|
|
mTextureSampler = glGetUniformLocation(mDefaultProgramID, "textureSampler");
|
|
mReflectivity = glGetUniformLocation(mDefaultProgramID, "reflectivity");
|
|
mOldDepthBufferSampler = glGetUniformLocation(mDefaultProgramID, "lastDepthMap");
|
|
mFirstPass = glGetUniformLocation(mDefaultProgramID, "firstPass");
|
|
mDepthmargin = glGetUniformLocation(mDefaultProgramID, "depthMargin");
|
|
mCameraDir = glGetUniformLocation(mDefaultProgramID, "cameraDir");
|
|
if (verbose) printf("Shaders loaded in %d ms\n", (int)(watch.GetTime() * 1000));
|
|
}
|
|
|
|
|
|
TriangleMeshVoxelizer::TriangleMeshVoxelizer() :
|
|
depthData(NULL),
|
|
colorData(NULL),
|
|
normalData(NULL),
|
|
angleData(NULL),
|
|
mWindow(NULL)
|
|
{
|
|
ObjLoader::Create();
|
|
mObjLoader = ObjLoader::Instance();
|
|
ShaderLoader::Create();
|
|
mShaderLoader = ShaderLoader::Instance();
|
|
//mShaderLoader->SetShaderPath("../Research/shaders/");
|
|
PropertyLoader::Create();
|
|
mPropertyLoader = PropertyLoader::Instance();
|
|
mPropertyLoader->Clear();
|
|
mPropertyLoader->AddPropertyFile(std::string("properties.txt"));
|
|
mPropertyLoader->AddPropertyFile(std::string("shaders/shader_properties.txt"));
|
|
mPropertyLoader->Update();
|
|
|
|
mWidth = mPropertyLoader->GetIntProperty("octreebuilder_debug_width");
|
|
mHeight = mPropertyLoader->GetIntProperty("octreebuilder_debug_height");
|
|
manual = mPropertyLoader->GetProperty("octreebuilder_manual") != "0";
|
|
renderScene = mPropertyLoader->GetProperty("octreebuilder_renderscene") != "0";
|
|
verbose = mPropertyLoader->GetProperty("octreebuilder_verbose") != "0";
|
|
interpolateColors = mPropertyLoader->GetProperty("octreebuilder_interpolate_colors") != "0";
|
|
useCache = mPropertyLoader->GetProperty("octreebuilder_usecache") != "0";
|
|
mMissingTexture = mPropertyLoader->GetProperty("octreebuilder_missing_material");
|
|
}
|
|
|
|
TriangleMeshVoxelizer::~TriangleMeshVoxelizer() {
|
|
|
|
glDeleteBuffers(1, &mVertexBuffer);
|
|
glDeleteBuffers(1, &mTextureBuffer);
|
|
glDeleteBuffers(1, &mNormalBuffer);
|
|
glDeleteBuffers(1, &mVertexColorBuffer);
|
|
glDeleteBuffers(1, &mElementBuffer);
|
|
|
|
glDeleteProgram(mDefaultProgramID);
|
|
|
|
std::vector<unsigned> textureIDs;
|
|
for (std::map<std::string, unsigned>::iterator it = mTextures.begin(); it != mTextures.end(); ++it) {
|
|
textureIDs.push_back(it->second);
|
|
}
|
|
|
|
if (!textureIDs.empty())
|
|
glDeleteTextures((GLsizei)textureIDs.size(), &textureIDs[0]);
|
|
mTextures.clear();
|
|
glDeleteTextures(1, &mTextureSampler);
|
|
|
|
glDeleteVertexArrays(1, &mVertexArrayID);
|
|
|
|
glfwTerminate();
|
|
|
|
ObjLoader::Destroy();
|
|
ShaderLoader::Destroy();
|
|
PropertyLoader::Destroy();
|
|
}
|
|
|
|
|
|
bool TriangleMeshVoxelizer::Reinitialize(bool fullscreen) {
|
|
glDeleteBuffers(1, &mVertexBuffer);
|
|
glDeleteBuffers(1, &mTextureBuffer);
|
|
glDeleteBuffers(1, &mNormalBuffer);
|
|
glDeleteBuffers(1, &mElementBuffer);
|
|
|
|
glDeleteProgram(mDefaultProgramID);
|
|
|
|
std::vector<unsigned> textureIDs;
|
|
for (std::map<std::string, unsigned>::iterator it = mTextures.begin(); it != mTextures.end(); ++it) {
|
|
textureIDs.push_back(it->second);
|
|
}
|
|
|
|
glDeleteTextures((GLsizei)textureIDs.size(), &textureIDs[0]);
|
|
mTextures.clear();
|
|
glDeleteTextures(1, &mTextureSampler);
|
|
|
|
glDeleteVertexArrays(1, &mVertexArrayID);
|
|
|
|
glfwTerminate();
|
|
|
|
return Initialize();
|
|
}
|
|
|
|
bool TriangleMeshVoxelizer::InitializeGLFW() {
|
|
// Initialize GLFW
|
|
if (!glfwInit()) {
|
|
fprintf(stderr, "Failed to initialize GLFW\n");
|
|
return false;
|
|
}
|
|
glfwWindowHint(GLFW_SAMPLES, std::stoi(mPropertyLoader->GetProperty("anti_aliasing")));
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, std::stoi(mPropertyLoader->GetProperty("opengl_version_major")));
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, std::stoi(mPropertyLoader->GetProperty("opengl_version_minor")));
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
|
|
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
|
|
// Open a window and create OpenGL context
|
|
mWindow = glfwCreateWindow(mWidth, mHeight, mPropertyLoader->GetProperty("window_name").c_str(), NULL, NULL);
|
|
if (mWindow == NULL) {
|
|
fprintf(stderr, "Failed to open GLFW window.\n");
|
|
glfwTerminate();
|
|
return false;
|
|
}
|
|
glfwMakeContextCurrent(mWindow);
|
|
|
|
glfwSetInputMode(mWindow, GLFW_STICKY_KEYS, GL_TRUE);
|
|
|
|
return true;
|
|
}
|