File Renderer.cpp¶
File List > AIAC > Render > Renderer.cpp
Go to the documentation of this file
// #####################################################################
// >>>>>>>>>>>>>>>>>>>>> BEGINNING OF LEGAL NOTICE >>>>>>>>>>>>>>>>>>>>>
//######################################################################
//
// This source file, along with its associated content, was authored by
// Andrea Settimi, Hong-Bin Yang, Naravich Chutisilp, and numerous other
// contributors. The code was originally developed at the Laboratory for
// Timber Construction (IBOIS, director: Prof. Yves Weinand) at the School of
// Architecture, Civil and Environmental Engineering (ENAC) at the Swiss
// Federal Institute of Technology in Lausanne (EPFL) for the Doctoral
// Research "Augmented Carpentry" (PhD researcher: Andrea Settimi,
// co-director: Dr. Julien Gamerro, director: Prof. Yves Weinand).
//
// Although the entire repository is distributed under the GPL license,
// these particular source files may also be used under the terms of the
// MIT license. By accessing or using this file, you agree to the following:
//
// 1. You may reproduce, modify, and distribute this file in accordance
// with the terms of the MIT license.
// 2. You must retain this legal notice in all copies or substantial
// portions of this file.
// 3. This file is provided "AS IS," without any express or implied
// warranties, including but not limited to the implied warranties of
// merchantability and fitness for a particular purpose.
//
// If you cannot or will not comply with the above conditions, you are
// not permitted to use this file. By proceeding, you acknowledge and
// accept all terms and conditions herein.
//
//######################################################################
// <<<<<<<<<<<<<<<<<<<<<<< END OF LEGAL NOTICE <<<<<<<<<<<<<<<<<<<<<<<<
// #####################################################################
//
#include "aiacpch.h"
#include "AIAC/Render/Renderer.h"
#include "TextRenderer.h"
#include "AIAC/Application.h"
#include "AIAC/Log.h"
#include "AIAC/Config.h"
#include "AIAC/Render/RenderAPI.h"
#include "glm/glm.hpp"
#include "glm/gtx/string_cast.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtc/matrix_transform.hpp"
#include "Shader.hpp"
#include "utils/utils.h"
#include "AIAC/LayerCameraCalib.h"
namespace AIAC
{
void Renderer::Init()
{
// Create and compile our GLSL program from the shaders
char* vertexFilePath = (char*)"assets/opengl/SimpleTransform.vs";
char* fragmentFilePath = (char*)"assets/opengl/SingleColor.fs";
m_BasicShaderProgram = LoadShaders(vertexFilePath, fragmentFilePath);
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
// Get a handle for our "MVP" uniform
m_MatrixId = glGetUniformLocation(m_BasicShaderProgram, "MVP");
// init the projection matrix based on the camera parameters
InitProjMatrix();
// Initialize the static interface of TextRenderer
TextRenderer::Init();
// Initialize sub views
InitMappingView();
InitGlobalView();
InitCamCalibView();
m_MappingView.SetSize(600, 442);
}
void Renderer::InitProjMatrix(){
// Calculate Perspective Projection Matrix based on camera intrinsic parameters
// Reference: https://strawlab.org/2011/11/05/augmented-reality-with-OpenGL/
cv::Mat cameraMatrix = AIAC_APP.GetLayer<LayerCamera>()->MainCamera.GetCameraMatrix();
float camW = AIAC_APP.GetLayer<LayerCamera>()->MainCamera.GetWidth();
float camH = AIAC_APP.GetLayer<LayerCamera>()->MainCamera.GetHeight();
float x0 = 0, y0 = 0,zF = 100.0f, zN =0.01f;
float fovX = cameraMatrix.at<float>(0,0);
float fovY = cameraMatrix.at<float>(1,1);
float cX = cameraMatrix.at<float>(0,2);
float cY = cameraMatrix.at<float>(1,2);
float perspectiveProjMatrixData[16] = {
2 * fovX / camW, 0, ( camW - 2 * cX + 2 * x0) / camW, 0,
0, 2 * fovY / camH, (-camH + 2 * cY + 2 * y0) / camH, 0,
0, 0, (-zF - zN)/(zF - zN), -2 * zF * zN / (zF - zN),
0, 0, -1, 0
};
glm::mat4 perspectiveProjMatrix = glm::transpose(glm::make_mat4(perspectiveProjMatrixData));
// opencv and opengl has different direction on y and z axis
glm::mat4 scalarMatrix(1.0f);
scalarMatrix[1][1] = -1;
scalarMatrix[2][2] = -1;
m_ProjMatrix = perspectiveProjMatrix * scalarMatrix;
// Save variable for later use
m_CamW = AIAC_APP.GetLayer<LayerCamera>()->MainCamera.GetWidth();
m_CamH = AIAC_APP.GetLayer<LayerCamera>()->MainCamera.GetHeight();
}
void Renderer::InitGlobalView()
{
m_GlobalView.Init(400, 300);
// build camera visualization object, which is a pyramid
const float CAMERA_SIZE_W = 1.6, CAMERA_SIZE_H = 1.2;
float bW = CAMERA_SIZE_W / 2, bH = CAMERA_SIZE_H / 2, h = 0.5f;
m_CamVisualizationEdges.emplace_back( bW, bH, 0);
m_CamVisualizationEdges.emplace_back( bW, -bH, 0);
m_CamVisualizationEdges.emplace_back( bW, -bH, 0);
m_CamVisualizationEdges.emplace_back(-bW, -bH, 0);
m_CamVisualizationEdges.emplace_back(-bW, -bH, 0);
m_CamVisualizationEdges.emplace_back(-bW, bH, 0);
m_CamVisualizationEdges.emplace_back(-bW, bH, 0);
m_CamVisualizationEdges.emplace_back( bW, bH, 0);
m_CamVisualizationEdges.emplace_back( 0, 0,-h);
m_CamVisualizationEdges.emplace_back( bW, bH, 0);
m_CamVisualizationEdges.emplace_back( 0, 0,-h);
m_CamVisualizationEdges.emplace_back(-bW, bH, 0);
m_CamVisualizationEdges.emplace_back( 0, 0,-h);
m_CamVisualizationEdges.emplace_back(-bW, -bH, 0);
m_CamVisualizationEdges.emplace_back( 0, 0,-h);
m_CamVisualizationEdges.emplace_back( bW, -bH, 0);
m_GlobalProjMatrix = glm::ortho(-m_GlobalProjOrthoSize, m_GlobalProjOrthoSize, -m_GlobalProjOrthoSize, m_GlobalProjOrthoSize, 0.0f, 1000.0f);
m_GlobalCamMatrix = glm::lookAt(
glm::vec3(20, 20, 20), // the position of your camera, in world space
glm::vec3(0, 0, 0), // where you want to look at, in world space
glm::vec3(0, 1, 0) // probably glm::vec3(0,1,0), but (0,-1,0) would make you looking upside-down, which can be great too
);
}
void Renderer::OnRender()
{
// During mapping, an overlay panel is opened, so we only render things on it
// and stop updating the main scene.
// TODO: mapping has some problem when calib file is switched (with slam map)
if(AIAC_APP.GetLayer<LayerSlam>()->IsMapping()) {
// RenderGlobalView();
RenderMappingView();
return;
}
if(AIAC_APP.GetLayer<LayerCameraCalib>()->IsCalibrating()) {
RenderCamCalibView();
return;
}
// Default, render the main scene
RenderMainView();
RenderGlobalView();
}
void Renderer::SetGlobalViewSize(float w, float h) {
m_GlobalView.SetSize(w, h);
}
void Renderer::UpdateGlobalViewCameraRotation(double diffX, double diffY){
auto t1 = glm::translate(glm::mat4(1),-m_GlobalCamLookAtCenter);
auto rx = glm::rotate(glm::mat4(1), float(-diffX / 100), glm::vec3(0,1,0));
auto ry = glm::rotate(glm::mat4(1), float(-diffY / 100), glm::vec3(1,0,0));
auto t2 = glm::translate(glm::mat4(1), m_GlobalCamLookAtCenter);
m_GlobalCamMatrix = m_GlobalCamMatrix * t2 * rx * ry * t1;
}
void Renderer::UpdateGlobalViewCameraTranslation(double diffX, double diffY){
m_GlobalCamMatrix[3][0] += float(diffX) / 10;
m_GlobalCamMatrix[3][1] -= float(diffY) / 10;
}
void Renderer::UpdateGlobalViewCameraScale(double diff) {
// m_GlobalCamMatrix[3][2] += float(diff) / 10; // this is for perspective projection
m_GlobalProjOrthoSize -= diff / 30;
if (m_GlobalProjOrthoSize < .1f) {
m_GlobalProjOrthoSize = .1f;
}
m_GlobalProjMatrix = glm::ortho(-m_GlobalProjOrthoSize, m_GlobalProjOrthoSize, -m_GlobalProjOrthoSize, m_GlobalProjOrthoSize, 0.0f, 1000.0f);
}
void Renderer::SetGlobalViewToActivatedComponent(StandardView standardView){
auto activatedComponent = AIAC_APP.GetLayer<LayerModel>()->GetACInfoModel().GetTimberInfo().GetCurrentComponent();
if (activatedComponent == nullptr) {
return;
}
m_GlobalCamLookAtCenter = activatedComponent->GetCenter();
glm::vec3 camPosition;
const double camDistance = 15.0;
const double sqrt2 = sqrt(2);
switch (standardView) {
case StandardView::TOP:
camPosition = glm::vec3(0, 0, 1);
break;
case StandardView::BOTTOM:
camPosition = glm::vec3(0, 0, -1);
break;
case StandardView::NW:
camPosition = glm::vec3(-sqrt2, sqrt2, 1);
break;
case StandardView::NE:
camPosition = glm::vec3(sqrt2, sqrt2, 1);
break;
case StandardView::SW:
camPosition = glm::vec3(-sqrt2, -sqrt2, 1);
break;
case StandardView::SE:
camPosition = glm::vec3(sqrt2, -sqrt2, 1);
break;
}
camPosition *= camDistance;
camPosition += m_GlobalCamLookAtCenter;
m_GlobalCamMatrix = glm::lookAt(
camPosition,
m_GlobalCamLookAtCenter,
glm::vec3(0, 1, 0)
);
}
void Renderer::RenderGlobalView() {
glBindVertexArray(m_VAO);
glUseProgram(m_BasicShaderProgram);
m_GlobalView.Activate();
glDisable(GL_DEPTH_TEST);
// visualize map
glm::mat4 finalPoseMatrix = m_GlobalProjMatrix * m_GlobalCamMatrix;
glUniformMatrix4fv(m_MatrixId, 1, GL_FALSE, &finalPoseMatrix[0][0]);
// Draw All objects
DrawAllGOs(finalPoseMatrix, 0.05f);
// Bind back to the main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::RenderMappingView() {
glBindVertexArray(m_VAO);
glUseProgram(m_BasicShaderProgram);
// Draw the small panel 3D view
m_GlobalView.Activate();
glm::mat4 finalPoseMatrix = m_ProjMatrix * AIAC_APP.GetLayer<LayerSlam>()->GetCamPoseGlm();
glUniformMatrix4fv(m_MatrixId, 1, GL_FALSE, &finalPoseMatrix[0][0]);
DrawSlamMap(AIAC_APP.GetLayer<LayerSlam>()->Slam.getMap(), glm::vec4(1, 0, 0, 1), 1.5);
// Draw the camera view
m_MappingView.Activate();
RenderCameraFrame(600, 442, Renderer::CameraFrameType::SLAM_PROCESSED);
// Bind back to the main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::RenderCamCalibView() {
m_CamCalibView.Activate();
RenderCameraFrame(600, 442, Renderer::CameraFrameType::RAW);
// Bind back to the main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::RenderMainView() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(m_VAO);
glUseProgram(m_BasicShaderProgram);
glDisable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RenderCameraFrame(AIAC_APP.GetWindow()->GetDisplayW(), AIAC_APP.GetWindow()->GetDisplayH());
// finalPoseMatrix is the perspective projected pose of the current camera detected by SLAM
glm::mat4 finalPoseMatrix = m_ProjMatrix * AIAC_APP.GetLayer<LayerSlam>()->GetCamPoseGlm();
glUniformMatrix4fv(m_MatrixId, 1, GL_FALSE, &finalPoseMatrix[0][0]);
// Draw the essential objects: map, point cloud map and digital model !
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glm::vec4 edgeColor;
if (AIAC_APP.GetLayer<LayerSlam>()->GetNumLostFrame() <= 3){
DrawAllGOs(finalPoseMatrix);
}
}
void Renderer::RenderCameraFrame(int w, int h, Renderer::CameraFrameType frameType) {
if ( w <= 0 || h <= 0 ){
stringstream ss;
ss << "Renderer::RenderCameraFrame: invalid size: (" << w << "," << h << ")";
throw std::runtime_error(ss.str());
}
GLuint frameGlTextureObj;
cv::Size frameSize;
if(frameType == Renderer::CameraFrameType::RAW) {
frameGlTextureObj = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetRawCurrentFrame().GetGlTextureObj();
frameSize.height = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetRawHeight();
frameSize.width = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetRawWidth();
} else if (frameType == Renderer::CameraFrameType::UNDISTORTED) {
frameGlTextureObj = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetCurrentFrame().GetGlTextureObj();
frameSize.height = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetHeight();
frameSize.width = AIAC_APP.GetLayer<AIAC::LayerCamera>()->MainCamera.GetWidth();
} else if (frameType == Renderer::CameraFrameType::SLAM_PROCESSED) {
frameGlTextureObj = AIAC_APP.GetLayer<LayerSlam>()->GetProcessedFrame().GetGlTextureObj();
frameSize = AIAC_APP.GetLayer<LayerSlam>()->Slam.imageParams.CamSize;
}
GLuint readFboIdFrame = 0;
glGenFramebuffers(1, &readFboIdFrame);
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFboIdFrame);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, frameGlTextureObj, 0);
glBlitFramebuffer(0, 0, frameSize.width, frameSize.height,
0, 0, w, h,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteFramebuffers(1, &readFboIdFrame);
glViewport(0,0,w,h); // Renderer on the whole framebuffer, complete from the lower left corner to the upper right
}
}