Skip to content

Commit

Permalink
Render camera frustums and path with 'y' and 'h' keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperlogic committed Apr 12, 2024
1 parent bd306e8 commit 1c5ab72
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 13 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ add_executable(${PROJECT_NAME}

src/app.cpp
src/camerasconfig.cpp
src/camerapathrenderer.cpp
src/flycam.cpp
src/gaussiancloud.cpp
src/magiccarpet.cpp
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,21 @@ Desktop Controls
* c - toggle between initial SfM point cloud (if present) and gaussian splats.
* n - jump to next camera
* p - jump to previous camera
* y - toggle rendering of camera frustums
* h - toggle rendering of camera path
* return - save the current position and orientation of the world into a vr.json file.

VR Controls
---------------
* c - toggle between initial SfM point cloud (if present) and gaussian splats.
* left stick - move
* right stick - snap turn
* f - show hide floor carpet.
* single grab - translate the world.
* double grab - rotate and translate the world.
* triple grab - (double grab while trigger is depressed) scale, rotate and translate the world.
* c - toggle between initial SfM point cloud (if present) and gaussian splats.
* y - toggle rendering of camera frustums
* h - toggle rendering of camera path
* return - save the current position and orientation/scale of the world into a vr.json file.

Config Files
Expand Down
49 changes: 45 additions & 4 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "core/xrbuddy.h"

#include "camerasconfig.h"
#include "camerapathrenderer.h"
#include "flycam.h"
#include "gaussiancloud.h"
#include "magiccarpet.h"
Expand Down Expand Up @@ -400,6 +401,16 @@ bool App::Init()
Log::D("Could not find cameras.json\n");
}

if (camerasConfig)
{
cameraPathRenderer = std::make_shared<CameraPathRenderer>();
if (!cameraPathRenderer->Init(camerasConfig->GetCameraVec()))
{
Log::E("CameraPathRenderer Init failed\n");
return false;
}
}

// search for vr config file
// for example: if plyFilename is "input.ply", then search for "input_vr.json"
std::string vrConfigBaseFilename = GetFilenameWithoutExtension(plyFilename) + "_vr.json";
Expand All @@ -424,14 +435,14 @@ bool App::Init()
glm::mat4 floorMat(1.0f);
if (camerasConfig)
{
flyCamMat = camerasConfig->GetCameraVec()[cameraIndex];
flyCamMat = camerasConfig->GetCameraVec()[cameraIndex].mat;

// initialize magicCarpet from first camera and estimated floor position.
if (camerasConfig->GetNumCameras() > 0)
{
glm::vec3 floorNormal, floorPos;
camerasConfig->EstimateFloorPlane(floorNormal, floorPos);
glm::vec3 floorZ = camerasConfig->GetCameraVec()[0][2];
glm::vec3 floorZ = camerasConfig->GetCameraVec()[0].mat[2];
glm::vec3 floorY = floorNormal;
glm::vec3 floorX = glm::cross(floorY, floorZ);
floorZ = glm::cross(floorX, floorY);
Expand Down Expand Up @@ -545,6 +556,13 @@ bool App::Init()
debugRenderer->Render(fullEyeMat, projMat, viewport, nearFar);
}

if (cameraPathRenderer)
{
cameraPathRenderer->SetShowCameras(opt.drawCameraFrustums);
cameraPathRenderer->SetShowPath(opt.drawCameraPath);
cameraPathRenderer->Render(fullEyeMat, projMat, viewport, nearFar);
}

if (opt.drawCarpet)
{
magicCarpet->Render(fullEyeMat, projMat, viewport, nearFar);
Expand Down Expand Up @@ -602,7 +620,7 @@ bool App::Init()
{
cameraIndex -= (int)camerasConfig->GetNumCameras();
}
flyCam->SetCameraMat(camerasConfig->GetCameraVec()[cameraIndex]);
flyCam->SetCameraMat(camerasConfig->GetCameraVec()[cameraIndex].mat);
}
});

Expand All @@ -615,7 +633,7 @@ bool App::Init()
{
cameraIndex += (int)camerasConfig->GetNumCameras();
}
flyCam->SetCameraMat(camerasConfig->GetCameraVec()[cameraIndex]);
flyCam->SetCameraMat(camerasConfig->GetCameraVec()[cameraIndex].mat);
}
});

Expand All @@ -627,6 +645,22 @@ bool App::Init()
}
});

inputBuddy->OnKey(SDLK_y, [this](bool down, uint16_t mod)
{
if (down)
{
opt.drawCameraFrustums = !opt.drawCameraFrustums;
}
});

inputBuddy->OnKey(SDLK_h, [this](bool down, uint16_t mod)
{
if (down)
{
opt.drawCameraPath = !opt.drawCameraPath;
}
});

inputBuddy->OnKey(SDLK_RETURN, [this, vrConfigFilename](bool down, uint16_t mod)
{
if (down)
Expand Down Expand Up @@ -939,6 +973,13 @@ bool App::Render(float dt, const glm::ivec2& windowSize)
debugRenderer->Render(cameraMat, projMat, viewport, nearFar);
}

if (cameraPathRenderer)
{
cameraPathRenderer->SetShowCameras(opt.drawCameraFrustums);
cameraPathRenderer->SetShowPath(opt.drawCameraPath);
cameraPathRenderer->Render(cameraMat, projMat, viewport, nearFar);
}

if (opt.drawCarpet)
{
magicCarpet->Render(cameraMat, projMat, viewport, nearFar);
Expand Down
4 changes: 4 additions & 0 deletions src/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "maincontext.h"

class CamerasConfig;
class CameraPathRenderer;
class DebugRenderer;
class FlyCam;
class GaussianCloud;
Expand Down Expand Up @@ -64,12 +65,15 @@ class App
bool drawDebug = true;
bool debugLogging = false;
bool drawFps = true;
bool drawCameraFrustums = false;
bool drawCameraPath = false;
};

MainContext& mainContext;
Options opt;
std::string plyFilename;
std::shared_ptr<DebugRenderer> debugRenderer;
std::shared_ptr<CameraPathRenderer> cameraPathRenderer;
std::shared_ptr<TextRenderer> textRenderer;
std::shared_ptr<XrBuddy> xrBuddy;

Expand Down
197 changes: 197 additions & 0 deletions src/camerapathrenderer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
Copyright (c) 2024 Anthony J. Thibault
This software is licensed under the MIT License. See LICENSE for more details.
*/

#include "camerapathrenderer.h"

#ifdef __ANDROID__
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/glew.h>
#endif

#include "core/log.h"
#include "core/util.h"

#include "camerasconfig.h"

CameraPathRenderer::CameraPathRenderer()
{
}

CameraPathRenderer::~CameraPathRenderer()
{
}

bool CameraPathRenderer::Init(const std::vector<Camera>& cameraVec)
{
ddProg = std::make_shared<Program>();
if (!ddProg->LoadVertFrag("shader/debugdraw_vert.glsl", "shader/debugdraw_frag.glsl"))
{
Log::E("Error loading CameraPathRenderer shader!\n");
return false;
}

BuildCamerasVao(cameraVec);
BuildPathVao(cameraVec);

return true;
}

// viewport = (x, y, width, height)
void CameraPathRenderer::Render(const glm::mat4& cameraMat, const glm::mat4& projMat,
const glm::vec4& viewport, const glm::vec2& nearFar)
{
if (!showCameras && !showPath)
{
return;
}

GL_ERROR_CHECK("CameraPathRenderer::Render() begin");

glm::mat4 modelViewProjMat = projMat * glm::inverse(cameraMat);

ddProg->Bind();
ddProg->SetUniform("modelViewProjMat", modelViewProjMat);

if (showCameras)
{
camerasVao->Bind();
glDrawElements(GL_LINES, numCameraVerts, GL_UNSIGNED_INT, nullptr);
camerasVao->Unbind();
}

if (showPath)
{
pathVao->Bind();
glDrawElements(GL_LINES, numPathVerts, GL_UNSIGNED_INT, nullptr);
pathVao->Unbind();
}

GL_ERROR_CHECK("CameraPathRenderer::Render() draw");
}

void CameraPathRenderer::BuildCamerasVao(const std::vector<Camera>& cameraVec)
{
camerasVao = std::make_shared<VertexArrayObject>();

const uint32_t NUM_LINES = 8;
const float FRUSTUM_LEN = 0.1f;
const glm::vec4 FRUSTUM_COLOR(0.0f, 1.0f, 0.0f, 1.0f);

numCameraVerts = (uint32_t)cameraVec.size() * NUM_LINES * 2;

std::vector<glm::vec3> posVec;
posVec.reserve(numCameraVerts);
std::vector<glm::vec4> colVec;
colVec.reserve(numCameraVerts);
std::vector<uint32_t> indexVec;
indexVec.reserve(numCameraVerts);

// build lines for each frustum
for (auto& c : cameraVec)
{
float xRadius = FRUSTUM_LEN / cosf(c.fov.x / 2.0f);
float xOffset = xRadius * sinf(c.fov.x / 2.0f);
float yRadius = FRUSTUM_LEN / cosf(c.fov.y / 2.0f);
float yOffset = yRadius * sinf(c.fov.y / 2.0f);

const uint32_t NUM_FRUSTUM_VERTS = 5;
glm::vec3 verts[NUM_FRUSTUM_VERTS] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(xOffset, yOffset, -FRUSTUM_LEN),
glm::vec3(-xOffset, yOffset, -FRUSTUM_LEN),
glm::vec3(-xOffset, -yOffset, -FRUSTUM_LEN),
glm::vec3(xOffset, -yOffset, -FRUSTUM_LEN)
};
for (int i = 0; i < NUM_FRUSTUM_VERTS; i++)
{
verts[i] = XformPoint(c.mat, verts[i]);
}

posVec.push_back(verts[0]); posVec.push_back(verts[1]);
posVec.push_back(verts[0]); posVec.push_back(verts[2]);
posVec.push_back(verts[0]); posVec.push_back(verts[3]);
posVec.push_back(verts[0]); posVec.push_back(verts[4]);

posVec.push_back(verts[1]); posVec.push_back(verts[2]);
posVec.push_back(verts[2]); posVec.push_back(verts[3]);
posVec.push_back(verts[3]); posVec.push_back(verts[4]);
posVec.push_back(verts[4]); posVec.push_back(verts[1]);

for (int i = 0; i < NUM_LINES; i++)
{
colVec.push_back(FRUSTUM_COLOR); colVec.push_back(FRUSTUM_COLOR);
}
}

auto posBuffer = std::make_shared<BufferObject>(GL_ARRAY_BUFFER, posVec);
auto colBuffer = std::make_shared<BufferObject>(GL_ARRAY_BUFFER, colVec);

// build element array
assert(numCameraVerts <= std::numeric_limits<uint32_t>::max());
for (uint32_t i = 0; i < numCameraVerts; i++)
{
indexVec.push_back(i);
}
auto indexBuffer = std::make_shared<BufferObject>(GL_ELEMENT_ARRAY_BUFFER, indexVec, GL_DYNAMIC_STORAGE_BIT);

// setup vertex array object with buffers
camerasVao->SetAttribBuffer(ddProg->GetAttribLoc("position"), posBuffer);
camerasVao->SetAttribBuffer(ddProg->GetAttribLoc("color"), colBuffer);
camerasVao->SetElementBuffer(indexBuffer);
}

void CameraPathRenderer::BuildPathVao(const std::vector<Camera>& cameraVec)
{
pathVao = std::make_shared<VertexArrayObject>();

const uint32_t NUM_LINES = 1;
const glm::vec4 PATH_COLOR(0.0f, 1.0f, 1.0f, 1.0f);

numPathVerts = (uint32_t)cameraVec.size() * NUM_LINES * 2;

std::vector<glm::vec3> posVec;
posVec.reserve(numPathVerts);
std::vector<glm::vec4> colVec;
colVec.reserve(numPathVerts);
std::vector<uint32_t> indexVec;
indexVec.reserve(numPathVerts);

// build lines for each path segment
if (cameraVec.size() > 1)
{
const Camera* prev = &cameraVec[cameraVec.size() - 1];
for (size_t i = 1; i < cameraVec.size(); i++)
{
const Camera* curr = cameraVec.data() + i;
glm::vec3 prevPos = glm::vec3(prev->mat[3]);
glm::vec3 currPos = glm::vec3(curr->mat[3]);
posVec.push_back(prevPos);
posVec.push_back(currPos);
colVec.push_back(PATH_COLOR);
colVec.push_back(PATH_COLOR);
prev = curr;
}
}

auto posBuffer = std::make_shared<BufferObject>(GL_ARRAY_BUFFER, posVec);
auto colBuffer = std::make_shared<BufferObject>(GL_ARRAY_BUFFER, colVec);

// build element array
assert(numPathVerts <= std::numeric_limits<uint32_t>::max());
for (uint32_t i = 0; i < numPathVerts; i++)
{
indexVec.push_back(i);
}
auto indexBuffer = std::make_shared<BufferObject>(GL_ELEMENT_ARRAY_BUFFER, indexVec, GL_DYNAMIC_STORAGE_BIT);

// setup vertex array object with buffers
pathVao->SetAttribBuffer(ddProg->GetAttribLoc("position"), posBuffer);
pathVao->SetAttribBuffer(ddProg->GetAttribLoc("color"), colBuffer);
pathVao->SetElementBuffer(indexBuffer);
}
Loading

0 comments on commit 1c5ab72

Please sign in to comment.