Files
zed-playground/new_playground/depth-sensing/src/GLViewer.cpp
T
crosstyan e7c5176229 Add depth sensing sample and OpenGL tests
- Implemented a new sample application in main.cpp to capture and display a live 3D point cloud using the ZED SDK and OpenGL.
- Created test_opengl.cpp to demonstrate basic OpenGL rendering with depth testing using two triangles.
- Added test_points.cpp to visualize a grid of colored points in OpenGL, showcasing point rendering capabilities.
2026-01-20 10:31:35 +08:00

779 lines
23 KiB
C++
Executable File

#include "GLViewer.hpp"
void print(std::string msg_prefix, sl::ERROR_CODE err_code, std::string msg_suffix) {
cout <<"[Sample]";
if (err_code != sl::ERROR_CODE::SUCCESS)
cout << "[Error] ";
else
cout<<" ";
cout << msg_prefix << " ";
if (err_code != sl::ERROR_CODE::SUCCESS) {
cout << " | " << toString(err_code) << " : ";
cout << toVerbose(err_code);
}
if (!msg_suffix.empty())
cout << " " << msg_suffix;
cout << endl;
}
const GLchar* VERTEX_SHADER =
"#version 330 core\n"
"layout(location = 0) in vec3 in_Vertex;\n"
"layout(location = 1) in vec3 in_Color;\n"
"uniform mat4 u_mvpMatrix;\n"
"out vec3 b_color;\n"
"void main() {\n"
" b_color = in_Color;\n"
" gl_Position = u_mvpMatrix * vec4(in_Vertex, 1);\n"
"}";
const GLchar* FRAGMENT_SHADER =
"#version 330 core\n"
"in vec3 b_color;\n"
"layout(location = 0) out vec4 out_Color;\n"
"void main() {\n"
" out_Color = vec4(b_color, 1);\n"
"}";
GLViewer* currentInstance_ = nullptr;
GLViewer::GLViewer() : available(false){
currentInstance_ = this;
mouseButton_[0] = mouseButton_[1] = mouseButton_[2] = false;
clearInputs();
previousMouseMotion_[0] = previousMouseMotion_[1] = 0;
}
GLViewer::~GLViewer() {}
void GLViewer::exit() {
if (currentInstance_) {
//pointCloud_.close();
available = false;
}
}
bool GLViewer::isAvailable() {
if(available)
glutMainLoopEvent();
return available;
}
Simple3DObject createFrustum(sl::CameraParameters param) {
// Create 3D axis
Simple3DObject it(sl::Translation(0, 0, 0), true);
float Z_ = -150;
sl::float3 cam_0(0, 0, 0);
sl::float3 cam_1, cam_2, cam_3, cam_4;
float fx_ = 1.f / param.fx;
float fy_ = 1.f / param.fy;
cam_1.z = Z_;
cam_1.x = (0 - param.cx) * Z_ *fx_;
cam_1.y = (0 - param.cy) * Z_ *fy_;
cam_2.z = Z_;
cam_2.x = (param.image_size.width - param.cx) * Z_ *fx_;
cam_2.y = (0 - param.cy) * Z_ *fy_;
cam_3.z = Z_;
cam_3.x = (param.image_size.width - param.cx) * Z_ *fx_;
cam_3.y = (param.image_size.height - param.cy) * Z_ *fy_;
cam_4.z = Z_;
cam_4.x = (0 - param.cx) * Z_ *fx_;
cam_4.y = (param.image_size.height - param.cy) * Z_ *fy_;
float const to_f = 1.f/ 255.f;
const sl::float4 clr_lime(217*to_f,255*to_f,66*to_f, 1.f);
it.addPoint(cam_0, clr_lime);
it.addPoint(cam_1, clr_lime);
it.addPoint(cam_0, clr_lime);
it.addPoint(cam_2, clr_lime);
it.addPoint(cam_0, clr_lime);
it.addPoint(cam_3, clr_lime);
it.addPoint(cam_0, clr_lime);
it.addPoint(cam_4, clr_lime);
it.setDrawingType(GL_LINES);
return it;
}
void CloseFunc(void) { if(currentInstance_) currentInstance_->exit();}
GLenum GLViewer::init(int argc, char **argv, sl::CameraParameters param, CUstream strm_, sl::Resolution image_size) {
glutInit(&argc, argv);
int wnd_w = glutGet(GLUT_SCREEN_WIDTH);
int wnd_h = glutGet(GLUT_SCREEN_HEIGHT) *0.9;
glutInitWindowSize(wnd_w*0.9, wnd_h*0.9);
glutInitWindowPosition(wnd_w*0.05, wnd_h*0.05);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow("ZED Depth Sensing");
GLenum err = glewInit();
if (GLEW_OK != err)
return err;
// Print OpenGL context info
std::cout << "\n=== OpenGL Context Information ===" << std::endl;
std::cout << "GL Vendor: " << glGetString(GL_VENDOR) << std::endl;
std::cout << "GL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "GL Version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
std::cout << "==================================\n" << std::endl;
pointCloud_.initialize(image_size, strm_);
// Compile and create the shader
shader_.set(VERTEX_SHADER, FRAGMENT_SHADER);
shMVPMatrixLoc_ = glGetUniformLocation(shader_.getProgramId(), "u_mvpMatrix");
// Create the camera - point cloud center is around Z=-3 to -4 meters (after shader scaling)
// Place camera at 2 meters looking at -3.5 meters (now in meters to match shader scaling)
camera_ = CameraGL(sl::Translation(0, 0, 2), sl::Translation(0, 0, -3.5));
sl::Rotation rot;
rot.setEulerAngles(sl::float3(0,0,0), false);
camera_.setRotation(rot);
frustum = createFrustum(param);
frustum.pushToGPU();
bckgrnd_clr = sl::float3(59, 63, 69);
bckgrnd_clr /= 255.f;
// Map glut function on this class methods
glutDisplayFunc(GLViewer::drawCallback);
glutMouseFunc(GLViewer::mouseButtonCallback);
glutMotionFunc(GLViewer::mouseMotionCallback);
glutReshapeFunc(GLViewer::reshapeCallback);
glutKeyboardFunc(GLViewer::keyPressedCallback);
glutKeyboardUpFunc(GLViewer::keyReleasedCallback);
glutCloseFunc(CloseFunc);
glEnable(GL_DEPTH_TEST);
#ifndef JETSON_STYLE
glEnable(GL_LINE_SMOOTH);
#endif
available = true;
return err;
}
void GLViewer::render() {
if (available) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(bckgrnd_clr.r, bckgrnd_clr.g, bckgrnd_clr.b, 1.f);
glPointSize(2.f); // Reset to normal size - was affecting frustum
update();
draw();
glutSwapBuffers();
glutPostRedisplay();
}
}
void GLViewer::updatePointCloud(sl::Mat &matXYZRGBA) {
pointCloud_.mutexData.lock();
pointCloud_.pushNewPC(matXYZRGBA);
pointCloud_.mutexData.unlock();
}
bool GLViewer::shouldSaveData(){
bool out = shouldSaveData_;
shouldSaveData_ = false;
return out;
}
void GLViewer::update() {
if (keyStates_['q'] == KEY_STATE::UP || keyStates_['Q'] == KEY_STATE::UP || keyStates_[27] == KEY_STATE::UP) {
pointCloud_.close();
currentInstance_->exit();
return;
}
if(keyStates_['s'] == KEY_STATE::UP || keyStates_['s'] == KEY_STATE::UP)
currentInstance_->shouldSaveData_ = true;
// Rotate camera with mouse
if (mouseButton_[MOUSE_BUTTON::LEFT]) {
camera_.rotate(sl::Rotation((float)mouseMotion_[1] * MOUSE_R_SENSITIVITY, camera_.getRight()));
camera_.rotate(sl::Rotation((float)mouseMotion_[0] * MOUSE_R_SENSITIVITY, camera_.getVertical() * -1.f));
}
// Translate camera with mouse (now using meters)
if (mouseButton_[MOUSE_BUTTON::RIGHT]) {
camera_.translate(camera_.getUp() * (float)mouseMotion_[1] * MOUSE_T_SENSITIVITY);
camera_.translate(camera_.getRight() * (float)mouseMotion_[0] * MOUSE_T_SENSITIVITY);
}
// Zoom in with mouse wheel (now using meters)
if (mouseWheelPosition_ != 0) {
if (mouseWheelPosition_ > 0) { // zoom
camera_.translate(camera_.getForward() * MOUSE_UZ_SENSITIVITY * -1);
}
else if (mouseWheelPosition_ < 0) {// unzoom
camera_.translate(camera_.getForward() * MOUSE_UZ_SENSITIVITY);
}
}
// Update point cloud buffers
pointCloud_.mutexData.lock();
pointCloud_.update();
pointCloud_.mutexData.unlock();
camera_.update();
clearInputs();
}
void GLViewer::draw() {
const sl::Transform vpMatrix = camera_.getViewProjectionMatrix();
// Draw point cloud first
pointCloud_.draw(vpMatrix);
// Then draw frustum on top
glUseProgram(shader_.getProgramId());
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glUniformMatrix4fv(shMVPMatrixLoc_, 1, GL_FALSE, sl::Transform::transpose(vpMatrix * frustum.getModelMatrix()).m);
frustum.draw();
glUseProgram(0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void GLViewer::clearInputs() {
mouseMotion_[0] = mouseMotion_[1] = 0;
mouseWheelPosition_ = 0;
for (unsigned int i = 0; i < 256; ++i)
if (keyStates_[i] != KEY_STATE::DOWN)
keyStates_[i] = KEY_STATE::FREE;
}
void GLViewer::drawCallback() {
currentInstance_->render();
}
void GLViewer::mouseButtonCallback(int button, int state, int x, int y) {
if (button < 5) {
if (button < 3) {
currentInstance_->mouseButton_[button] = state == GLUT_DOWN;
} else {
currentInstance_->mouseWheelPosition_ += button == MOUSE_BUTTON::WHEEL_UP ? 1 : -1;
}
currentInstance_->mouseCurrentPosition_[0] = x;
currentInstance_->mouseCurrentPosition_[1] = y;
currentInstance_->previousMouseMotion_[0] = x;
currentInstance_->previousMouseMotion_[1] = y;
}
}
void GLViewer::mouseMotionCallback(int x, int y) {
currentInstance_->mouseMotion_[0] = x - currentInstance_->previousMouseMotion_[0];
currentInstance_->mouseMotion_[1] = y - currentInstance_->previousMouseMotion_[1];
currentInstance_->previousMouseMotion_[0] = x;
currentInstance_->previousMouseMotion_[1] = y;
glutPostRedisplay();
}
void GLViewer::reshapeCallback(int width, int height) {
glViewport(0, 0, width, height);
float hfov = (180.0f / M_PI) * (2.0f * atan(width / (2.0f * 500)));
float vfov = (180.0f / M_PI) * (2.0f * atan(height / (2.0f * 500)));
currentInstance_->camera_.setProjection(hfov, vfov, currentInstance_->camera_.getZNear(), currentInstance_->camera_.getZFar());
}
void GLViewer::keyPressedCallback(unsigned char c, int x, int y) {
currentInstance_->keyStates_[c] = KEY_STATE::DOWN;
glutPostRedisplay();
}
void GLViewer::keyReleasedCallback(unsigned char c, int x, int y) {
currentInstance_->keyStates_[c] = KEY_STATE::UP;
}
void GLViewer::idle() {
glutPostRedisplay();
}
Simple3DObject::Simple3DObject() : vaoID_(0) {}
Simple3DObject::Simple3DObject(sl::Translation position, bool isStatic): isStatic_(isStatic) {
vaoID_ = 0;
drawingType_ = GL_TRIANGLES;
position_ = position;
rotation_.setIdentity();
}
Simple3DObject::~Simple3DObject() {
if (vaoID_ != 0) {
glDeleteBuffers(3, vboID_);
glDeleteVertexArrays(1, &vaoID_);
}
}
void Simple3DObject::addPoint(sl::float3 pt, sl::float3 clr) {
vertices_.push_back(pt.x);
vertices_.push_back(pt.y);
vertices_.push_back(pt.z);
colors_.push_back(clr.r);
colors_.push_back(clr.g);
colors_.push_back(clr.b);
indices_.push_back((int) indices_.size());
}
void Simple3DObject::addFace(sl::float3 p1, sl::float3 p2, sl::float3 p3, sl::float3 clr) {
vertices_.push_back(p1.x);
vertices_.push_back(p1.y);
vertices_.push_back(p1.z);
colors_.push_back(clr.r);
colors_.push_back(clr.g);
colors_.push_back(clr.b);
vertices_.push_back(p2.x);
vertices_.push_back(p2.y);
vertices_.push_back(p2.z);
colors_.push_back(clr.r);
colors_.push_back(clr.g);
colors_.push_back(clr.b);
vertices_.push_back(p3.x);
vertices_.push_back(p3.y);
vertices_.push_back(p3.z);
colors_.push_back(clr.r);
colors_.push_back(clr.g);
colors_.push_back(clr.b);
indices_.push_back((int) indices_.size());
indices_.push_back((int) indices_.size());
indices_.push_back((int) indices_.size());
}
void Simple3DObject::pushToGPU() {
if (!isStatic_ || vaoID_ == 0) {
if (vaoID_ == 0) {
glGenVertexArrays(1, &vaoID_);
glGenBuffers(3, vboID_);
}
glBindVertexArray(vaoID_);
glBindBuffer(GL_ARRAY_BUFFER, vboID_[0]);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(float), &vertices_[0], isStatic_ ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
glVertexAttribPointer(Shader::ATTRIB_VERTICES_POS, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(Shader::ATTRIB_VERTICES_POS);
glBindBuffer(GL_ARRAY_BUFFER, vboID_[1]);
glBufferData(GL_ARRAY_BUFFER, colors_.size() * sizeof(float), &colors_[0], isStatic_ ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
glVertexAttribPointer(Shader::ATTRIB_COLOR_POS, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(Shader::ATTRIB_COLOR_POS);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID_[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned int), &indices_[0], isStatic_ ? GL_STATIC_DRAW : GL_DYNAMIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
void Simple3DObject::clear() {
vertices_.clear();
colors_.clear();
indices_.clear();
}
void Simple3DObject::setDrawingType(GLenum type) {
drawingType_ = type;
}
void Simple3DObject::draw() {
glBindVertexArray(vaoID_);
glDrawElements(drawingType_, (GLsizei) indices_.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void Simple3DObject::translate(const sl::Translation& t) {
position_ = position_ + t;
}
void Simple3DObject::setPosition(const sl::Translation& p) {
position_ = p;
}
void Simple3DObject::setRT(const sl::Transform& mRT) {
position_ = mRT.getTranslation();
rotation_ = mRT.getOrientation();
}
void Simple3DObject::rotate(const sl::Orientation& rot) {
rotation_ = rot * rotation_;
}
void Simple3DObject::rotate(const sl::Rotation& m) {
this->rotate(sl::Orientation(m));
}
void Simple3DObject::setRotation(const sl::Orientation& rot) {
rotation_ = rot;
}
void Simple3DObject::setRotation(const sl::Rotation& m) {
this->setRotation(sl::Orientation(m));
}
const sl::Translation& Simple3DObject::getPosition() const {
return position_;
}
sl::Transform Simple3DObject::getModelMatrix() const {
sl::Transform tmp;
tmp.setOrientation(rotation_);
tmp.setTranslation(position_);
return tmp;
}
Shader::Shader(const GLchar* vs, const GLchar* fs) {
set(vs, fs);
}
void Shader::set(const GLchar* vs, const GLchar* fs) {
if (!compile(verterxId_, GL_VERTEX_SHADER, vs)) {
print("ERROR: while compiling vertex shader");
}
if (!compile(fragmentId_, GL_FRAGMENT_SHADER, fs)) {
print("ERROR: while compiling fragment shader");
}
programId_ = glCreateProgram();
glAttachShader(programId_, verterxId_);
glAttachShader(programId_, fragmentId_);
glBindAttribLocation(programId_, ATTRIB_VERTICES_POS, "in_vertex");
glBindAttribLocation(programId_, ATTRIB_COLOR_POS, "in_texCoord");
glLinkProgram(programId_);
GLint errorlk(0);
glGetProgramiv(programId_, GL_LINK_STATUS, &errorlk);
if (errorlk != GL_TRUE) {
print("ERROR: while linking shader : ");
GLint errorSize(0);
glGetProgramiv(programId_, GL_INFO_LOG_LENGTH, &errorSize);
char *error = new char[errorSize + 1];
glGetShaderInfoLog(programId_, errorSize, &errorSize, error);
error[errorSize] = '\0';
std::cout << error << std::endl;
delete[] error;
glDeleteProgram(programId_);
}
}
Shader::~Shader() {
if (verterxId_ != 0 && glIsShader(verterxId_))
glDeleteShader(verterxId_);
if (fragmentId_ != 0 && glIsShader(fragmentId_))
glDeleteShader(fragmentId_);
if (programId_ != 0 && glIsProgram(programId_))
glDeleteProgram(programId_);
}
GLuint Shader::getProgramId() {
return programId_;
}
bool Shader::compile(GLuint &shaderId, GLenum type, const GLchar* src) {
shaderId = glCreateShader(type);
if (shaderId == 0) {
return false;
}
glShaderSource(shaderId, 1, (const char**) &src, 0);
glCompileShader(shaderId);
GLint errorCp(0);
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &errorCp);
if (errorCp != GL_TRUE) {
print("ERROR: while compiling shader : ");
GLint errorSize(0);
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &errorSize);
char *error = new char[errorSize + 1];
glGetShaderInfoLog(shaderId, errorSize, &errorSize, error);
error[errorSize] = '\0';
std::cout << error << std::endl;
delete[] error;
glDeleteShader(shaderId);
return false;
}
return true;
}
const GLchar* POINTCLOUD_VERTEX_SHADER =
"#version 330 core\n"
"layout(location = 0) in vec4 in_VertexRGBA;\n"
"uniform mat4 u_mvpMatrix;\n"
"out vec4 b_color;\n"
"void main() {\n"
// Decompose the 4th channel of the XYZRGBA buffer to retrieve the color of the point (1float to 4uint)
" uint vertexColor = floatBitsToUint(in_VertexRGBA.w); \n"
" vec3 clr_int = vec3((vertexColor & uint(0x000000FF)), (vertexColor & uint(0x0000FF00)) >> 8, (vertexColor & uint(0x00FF0000)) >> 16);\n"
" b_color = vec4(clr_int.r / 255.0f, clr_int.g / 255.0f, clr_int.b / 255.0f, 1.f);"
// Scale from mm to m (divide by 1000) before applying MVP
" vec3 pos_meters = in_VertexRGBA.xyz * 0.001;\n"
" gl_Position = u_mvpMatrix * vec4(pos_meters, 1);\n"
"}";
const GLchar* POINTCLOUD_FRAGMENT_SHADER =
"#version 330 core\n"
"in vec4 b_color;\n"
"layout(location = 0) out vec4 out_Color;\n"
"void main() {\n"
" out_Color = b_color;\n"
"}";
PointCloud::PointCloud(): hasNewPCL_(false) {
}
PointCloud::~PointCloud() {
close();
}
void checkError(cudaError_t err) {
if(err != cudaSuccess)
std::cerr << "Error: (" << err << "): " << cudaGetErrorString(err) << std::endl;
}
void PointCloud::close() {
if (matGPU_.isInit()) {
matGPU_.free();
glDeleteBuffers(1, &bufferGLID_);
}
}
void PointCloud::initialize(sl::Resolution res, CUstream strm_) {
glGenBuffers(1, &bufferGLID_);
glBindBuffer(GL_ARRAY_BUFFER, bufferGLID_);
glBufferData(GL_ARRAY_BUFFER, res.area() * 4 * sizeof(float), 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
strm = strm_;
checkError(cudaGraphicsGLRegisterBuffer(&bufferCudaID_, bufferGLID_, cudaGraphicsRegisterFlagsWriteDiscard));
shader_.set(POINTCLOUD_VERTEX_SHADER, POINTCLOUD_FRAGMENT_SHADER);
shMVPMatrixLoc_ = glGetUniformLocation(shader_.getProgramId(), "u_mvpMatrix");
matGPU_.alloc(res, sl::MAT_TYPE::F32_C4, sl::MEM::GPU);
// Don't keep it mapped - we'll map/unmap in update()
numBytes_ = res.area() * 4 * sizeof(float);
}
void PointCloud::pushNewPC(sl::Mat &matXYZRGBA) {
if (matGPU_.isInit()) {
matGPU_.setFrom(matXYZRGBA, sl::COPY_TYPE::GPU_GPU, strm);
hasNewPCL_ = true;
}
}
void PointCloud::update() {
if (hasNewPCL_ && matGPU_.isInit()) {
// Map the resource for CUDA access
checkError(cudaGraphicsMapResources(1, &bufferCudaID_, strm));
checkError(cudaGraphicsResourceGetMappedPointer((void**) &xyzrgbaMappedBuf_, &numBytes_, bufferCudaID_));
// Copy data from ZED SDK to mapped OpenGL buffer
checkError(cudaMemcpyAsync(xyzrgbaMappedBuf_, matGPU_.getPtr<sl::float4>(sl::MEM::GPU), numBytes_, cudaMemcpyDeviceToDevice, strm));
// Synchronize to ensure copy completes
checkError(cudaStreamSynchronize(strm));
// Unmap so OpenGL can use it
checkError(cudaGraphicsUnmapResources(1, &bufferCudaID_, strm));
hasNewPCL_ = false;
}
}
void PointCloud::draw(const sl::Transform& vp) {
if (matGPU_.isInit()) {
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glPointSize(2.f);
glEnable(GL_PROGRAM_POINT_SIZE);
glUseProgram(shader_.getProgramId());
glUniformMatrix4fv(shMVPMatrixLoc_, 1, GL_FALSE, sl::Transform::transpose(vp).m);
glBindBuffer(GL_ARRAY_BUFFER, bufferGLID_);
glVertexAttribPointer(Shader::ATTRIB_VERTICES_POS, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(Shader::ATTRIB_VERTICES_POS);
int num_points = matGPU_.getResolution().area();
glDrawArrays(GL_POINTS, 0, num_points);
glDisableVertexAttribArray(Shader::ATTRIB_VERTICES_POS);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glEnable(GL_DEPTH_TEST);
}
}
const sl::Translation CameraGL::ORIGINAL_FORWARD = sl::Translation(0, 0, 1);
const sl::Translation CameraGL::ORIGINAL_UP = sl::Translation(0, 1, 0);
const sl::Translation CameraGL::ORIGINAL_RIGHT = sl::Translation(1, 0, 0);
CameraGL::CameraGL(sl::Translation position, sl::Translation direction, sl::Translation vertical) {
this->position_ = position;
setDirection(direction, vertical);
offset_ = sl::Translation(0, 0, 0);
view_.setIdentity();
updateView();
setProjection(90, 90, 0.01f, 50.f); // Near/far in meters (0.01m = 10mm, 50m = 50000mm)
updateVPMatrix();
}
CameraGL::~CameraGL() {}
void CameraGL::update() {
if (sl::Translation::dot(vertical_, up_) < 0)
vertical_ = vertical_ * -1.f;
updateView();
updateVPMatrix();
}
void CameraGL::setProjection(float horizontalFOV, float verticalFOV, float znear, float zfar) {
horizontalFieldOfView_ = horizontalFOV;
verticalFieldOfView_ = verticalFOV;
znear_ = znear;
zfar_ = zfar;
float fov_y = verticalFOV * M_PI / 180.f;
float fov_x = horizontalFOV * M_PI / 180.f;
projection_.setIdentity();
projection_(0, 0) = 1.0f / tanf(fov_x * 0.5f);
projection_(1, 1) = 1.0f / tanf(fov_y * 0.5f);
projection_(2, 2) = -(zfar + znear) / (zfar - znear);
projection_(3, 2) = -1;
projection_(2, 3) = -(2.f * zfar * znear) / (zfar - znear);
projection_(3, 3) = 0;
}
const sl::Transform& CameraGL::getViewProjectionMatrix() const {
return vpMatrix_;
}
float CameraGL::getHorizontalFOV() const {
return horizontalFieldOfView_;
}
float CameraGL::getVerticalFOV() const {
return verticalFieldOfView_;
}
void CameraGL::setOffsetFromPosition(const sl::Translation& o) {
offset_ = o;
}
const sl::Translation& CameraGL::getOffsetFromPosition() const {
return offset_;
}
void CameraGL::setDirection(const sl::Translation& direction, const sl::Translation& vertical) {
sl::Translation dirNormalized = direction;
dirNormalized.normalize();
this->rotation_ = sl::Orientation(ORIGINAL_FORWARD, dirNormalized * -1.f);
updateVectors();
this->vertical_ = vertical;
if (sl::Translation::dot(vertical_, up_) < 0)
rotate(sl::Rotation(M_PI, ORIGINAL_FORWARD));
}
void CameraGL::translate(const sl::Translation& t) {
position_ = position_ + t;
}
void CameraGL::setPosition(const sl::Translation& p) {
position_ = p;
}
void CameraGL::rotate(const sl::Orientation& rot) {
rotation_ = rot * rotation_;
updateVectors();
}
void CameraGL::rotate(const sl::Rotation& m) {
this->rotate(sl::Orientation(m));
}
void CameraGL::setRotation(const sl::Orientation& rot) {
rotation_ = rot;
updateVectors();
}
void CameraGL::setRotation(const sl::Rotation& m) {
this->setRotation(sl::Orientation(m));
}
const sl::Translation& CameraGL::getPosition() const {
return position_;
}
const sl::Translation& CameraGL::getForward() const {
return forward_;
}
const sl::Translation& CameraGL::getRight() const {
return right_;
}
const sl::Translation& CameraGL::getUp() const {
return up_;
}
const sl::Translation& CameraGL::getVertical() const {
return vertical_;
}
float CameraGL::getZNear() const {
return znear_;
}
float CameraGL::getZFar() const {
return zfar_;
}
void CameraGL::updateVectors() {
forward_ = ORIGINAL_FORWARD * rotation_;
up_ = ORIGINAL_UP * rotation_;
right_ = sl::Translation(ORIGINAL_RIGHT * -1.f) * rotation_;
}
void CameraGL::updateView() {
sl::Transform transformation(rotation_, (offset_ * rotation_) + position_);
view_ = sl::Transform::inverse(transformation);
}
void CameraGL::updateVPMatrix() {
vpMatrix_ = projection_ * view_;
}