fixed camera viewport bug and implemented basic flow of rays

This commit is contained in:
Benjamin Kyd
2023-10-16 14:30:39 +01:00
parent 8db675acf6
commit dc946e77f2
8 changed files with 249 additions and 215 deletions

View File

@@ -39,6 +39,8 @@ typedef struct Camera {
Camera* camera_create();
void camera_cleanup(Camera* camera);
void camera_draw_ui(Camera* camera);
void camera_update(Camera* camera);
bool camera_did_update(Camera* camera);
void camera_new_frame(Camera* camera);
@@ -47,11 +49,11 @@ glm::mat4 camera_get_view(Camera* camera);
glm::mat4 camera_get_projection(Camera* camera);
glm::mat4 camera_get_look(Camera* camera);
void raster_set_viewport(Camera* camera, glm::ivec2 viewport);
glm::ivec2 raster_get_viewport(Camera* camera);
void camera_raster_set_viewport(Camera* camera, glm::ivec2 viewport);
glm::ivec2 camera_raster_get_viewport(Camera* camera);
void ray_set_viewport(Camera* camera, glm::ivec2 viewport);
glm::ivec2 ray_get_viewport(Camera* camera);
void camera_ray_set_viewport(Camera* camera, glm::ivec2 viewport);
glm::ivec2 camera_ray_get_viewport(Camera* camera);
void camera_move(Camera* camera, uint8_t movement_delta);
void camera_mouse_move(Camera* camera, glm::vec2 mouse_delta);

View File

@@ -42,8 +42,7 @@ InfernoApp* inferno_create()
basicMaterial->setGlShader(basicShader);
scene::Mesh* mesh = new scene::Mesh;
// mesh->loadOBJ("res/cornell-box.obj");
mesh->loadOBJ("res/sponza.obj");
mesh->loadOBJ("res/cornell-box.obj");
mesh->ready();
mesh->setMaterial(basicMaterial);
@@ -53,6 +52,7 @@ InfernoApp* inferno_create()
scene::scene_add_object(app->Scene, object);
app->PreviewRenderer = graphics::preview_create();
app->RayRenderer = graphics::rayr_create(app->Scene);
return app;
}
@@ -185,8 +185,9 @@ int inferno_run(InfernoApp* app)
inferno_stop_move_input(app);
}
graphics::raster_set_viewport(scene::scene_get_camera(app->Scene),
graphics::camera_raster_set_viewport(scene::scene_get_camera(app->Scene),
{ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y });
graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);
graphics::preview_draw(app->PreviewRenderer, app->Scene);
ImTextureID texture = (ImTextureID)graphics::preview_get_rendered_texture(app->PreviewRenderer);
@@ -201,54 +202,25 @@ int inferno_run(InfernoApp* app)
if (showRenderSettings && ImGui::Begin("Inferno HART")) {
if (ImGui::TreeNode("Camera")) {
ImGui::PushItemWidth(100);
ImGui::Text("Camera Position X,Y,Z");
graphics::Camera* camera = scene::scene_get_camera(app->Scene);
bool positionUpdated = false;
ImGui::DragFloat("X", &camera->Position.x, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
positionUpdated = true;
ImGui::DragFloat("Y", &camera->Position.y, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
positionUpdated = true;
ImGui::DragFloat("Z", &camera->Position.z, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
if (ImGui::IsItemEdited())
positionUpdated = true;
if (positionUpdated)
graphics::camera_set_position(camera, graphics::camera_get_position(camera));
bool viewUpdated = false;
ImGui::Text("Camera Look Yaw, Pitch, Roll");
ImGui::DragFloat("Yaw", &camera->Yaw, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::DragFloat("Pitch", &camera->Pitch, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::DragFloat("Roll", &camera->Roll, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::PopItemWidth();
ImGui::PushItemWidth(300);
ImGui::Text("Camera Zoom");
ImGui::DragFloat("Zoom", &camera->FOV, -0.1f, 0.01f, 180.0f, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
if (viewUpdated)
graphics::camera_update(camera);
ImGui::PopItemWidth();
graphics::camera_draw_ui(camera);
ImGui::TreePop();
}
if (ImGui::TreeNode("Preview Render")) {
ImGui::Checkbox("Show Preview", &showPreview);
ImGui::TreePop();
}
if (ImGui::TreeNode("RayTraced Render")) {
ImGui::Text("Lol");
graphics::rayr_draw_ui(app->RayRenderer);
ImGui::TreePop();
}
ImGui::End();
}
if (ImGui::Begin("Render")) {
ImGui::End();
}

View File

@@ -3,7 +3,7 @@
#include "graphics.hpp"
#include "scene/scene.hpp"
#include "scene/camera.hpp"
// #include "renderer/renderer.hpp"
#include "renderer/renderer.hpp"
#include "preview_renderer/renderer.hpp"
#include <memory>
@@ -27,7 +27,7 @@ typedef struct InfernoApp {
InfernoInput* Input;
scene::Scene* Scene;
graphics::PreviewRenderer* PreviewRenderer;
// graphics::RayRenderer* RayRenderer;
graphics::RayRenderer* RayRenderer;
} InfernoApp;
InfernoApp* inferno_create();

View File

@@ -53,10 +53,43 @@ void preview_cleanup(PreviewRenderer* renderer)
{
}
void preview_set_viewport(PreviewRenderer* renderer, Viewport* viewport)
void preview_draw_ui(PreviewRenderer* renderer)
{
}
void preview_set_viewport(PreviewRenderer* renderer, Camera* camera)
{
auto viewport = camera_raster_get_viewport(camera);
renderer->Viewport = &viewport;
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
renderer->Viewport->x,
renderer->Viewport->y,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
NULL);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetDepthTexture);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
renderer->Viewport->x,
renderer->Viewport->y,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
NULL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
GLuint preview_get_rendered_texture(PreviewRenderer* renderer)
{
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
@@ -65,48 +98,18 @@ GLuint preview_get_rendered_texture(PreviewRenderer* renderer)
void preview_draw(PreviewRenderer* renderer, scene::Scene* scene)
{
const glm::ivec2& viewport = graphics::raster_get_viewport(scene::scene_get_camera(scene));
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
viewport.x,
viewport.y,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
NULL);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetDepthTexture);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_DEPTH24_STENCIL8,
viewport.x,
viewport.y,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
NULL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// clear
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
glClearColor(0.1, 0.1, 0.1, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// draw
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
glViewport(0,
0,
renderer->Viewport.x,
renderer->Viewport.y);
renderer->Viewport->x,
renderer->Viewport->y);
glEnable(GL_DEPTH_TEST);

View File

@@ -11,9 +11,10 @@ struct Scene;
namespace inferno::graphics {
struct Viewport;
struct Camera;
typedef struct PreviewRenderer {
glm::ivec2 Viewport;
glm::ivec2* Viewport;
GLuint RenderTarget = 0;
GLuint RenderTargetTexture = 0;
@@ -23,6 +24,9 @@ typedef struct PreviewRenderer {
PreviewRenderer* preview_create();
void preview_cleanup(PreviewRenderer* renderer);
void preview_draw_ui(PreviewRenderer* renderer);
void preview_set_viewport(PreviewRenderer* renderer, Camera* camera);
GLuint preview_get_rendered_texture(PreviewRenderer* renderer);
void preview_draw(PreviewRenderer* renderer, scene::Scene* scene);

View File

@@ -1,111 +1,113 @@
// #include "renderer.hpp"
//
// #include <graphics.hpp>
//
// #include <scene/camera.hpp>
// #include <scene/scene.hpp>
// #include <scene/mesh.hpp>
// #include <tracing/ray.hpp>
// #include <tracing/hit.hpp>
//
// #include "ray_source.hpp"
//
// #include <yolo/yolo.hpp>
//
// #include <iostream>
//
// namespace inferno::graphics {
//
// RayRenderer* rayr_create(glm::ivec2 viewport, HHM* accelIface)
#include "renderer.hpp"
#include <graphics.hpp>
#include <scene/camera.hpp>
#include <scene/mesh.hpp>
#include <scene/scene.hpp>
#include <tracing/hit.hpp>
#include <tracing/ray.hpp>
#include "ray_source.hpp"
#include <yolo/yolo.hpp>
#include <scene/camera.hpp>
#include <iostream>
namespace inferno::graphics {
RayRenderer* rayr_create(scene::Scene* scene)
{
RayRenderer* renderer = new RayRenderer;
renderer->Scene = scene;
auto camera = scene::scene_get_camera(scene);
auto viewport = camera_ray_get_viewport(camera);
renderer->Viewport = &viewport;
renderer->RenderData = new glm::fvec4[renderer->Viewport->x * renderer->Viewport->y];
glGenTextures(1, &renderer->RenderTargetTexture);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderer->Viewport->x, renderer->Viewport->y, 0, GL_RGBA, GL_FLOAT, renderer->RenderData);
glBindTexture(GL_TEXTURE_2D, 0);
return renderer;
}
void rayr_cleanup(RayRenderer* renderer)
{
delete[] renderer->RenderData;
}
void rayr_draw_ui(RayRenderer* renderer)
{
}
void rayr_set_viewport(RayRenderer* renderer, glm::ivec2 size)
{
renderer->Viewport = &size;
delete renderer->RenderData;
renderer->RenderData = new glm::fvec4[renderer->Viewport->x * renderer->Viewport->y];
glGenTextures(1, &renderer->RenderTargetTexture);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderer->Viewport->x, renderer->Viewport->y, 0, GL_RGBA, GL_FLOAT, renderer->RenderData);
glBindTexture(GL_TEXTURE_2D, 0);
}
GLuint rayr_get_rendered_texture(RayRenderer*& renderer)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
return renderer->RenderTargetTexture;
}
glm::fvec4* rayr_get_render_data(RayRenderer*& renderer)
{
return renderer->RenderData;
}
void rayr_prepare(RayRenderer*& renderer)
{
assert(renderer->Scene != nullptr);
if (scene::scene_did_update(renderer->Scene)) {
yolo::debug("Scene updated, rebuilding acceleration structure");
// renderer->AccelerationInterface->newScene(renderer->CurrentScene);
}
}
// void rayr_draw(RayRenderer*& renderer)
// {
// RayRenderer* renderer = new RayRenderer;
// renderer->RenderTargetSize = viewport;
// renderer->RenderData = new glm::fvec4[renderer->RenderTargetSize.x * renderer->RenderTargetSize.y];
//
// glGenTextures(1, &renderer->RenderTargetTexture);
// glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
//
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//
// glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderer->RenderTargetSize.x, renderer->RenderTargetSize.y, 0, GL_RGBA, GL_FLOAT, renderer->RenderData);
//
// glBindTexture(GL_TEXTURE_2D, 0);
//
// return renderer;
// }
//
// void rayr_cleanup(RayRenderer* renderer)
// {
// delete[] renderer->RenderData;
// }
//
// void rayr_set_scene(RayRenderer* renderer, std::shared_ptr<scene::Scene> scene)
// {
// renderer->CurrentScene = scene;
// if (renderer->RaySource != nullptr)
// {
// delete renderer->RaySource;
// }
// // renderer->RaySource = new RaySource(scene->getCamera());
// // the scene will be sent to the module on prepare
// // as it did update during initialisation
//
// // mIface->newScene(scene);
// }
//
// void rayr_set_viewport(RayRenderer* &renderer, glm::ivec2 size)
// {
// renderer->RenderTargetSize = size;
// }
//
// glm::ivec2 rayr_get_viewport(RayRenderer* &renderer)
// {
// return renderer->RenderTargetSize;
// }
//
// GLuint rayr_get_rendered_texture(RayRenderer* &renderer)
// {
// std::lock_guard<std::mutex> lock(renderer->RenderDataMutex);
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
// glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
// return renderer->RenderTargetTexture;
// }
//
// glm::fvec4* rayr_get_render_data(RayRenderer* &renderer)
// {
// std::lock_guard<std::mutex> lock(renderer->RenderDataMutex);
// return renderer->RenderData;
// }
//
// void rayr_prepare(RayRenderer* &renderer)
// {
// assert(renderer->CurrentScene != nullptr);
// // here, scene_did_update takes a unique_ptr, but we have a shared_ptr
// // so we need to call unique() to get the unique_ptr but that will error
// // with non-const ltype so we need to const_cast it
// if (scene::scene_did_update(renderer->CurrentScene))
// {
// yolo::debug("New Scene!");
// // renderer->AccelerationInterface->newScene(renderer->CurrentScene);
// }
// }
//
// void rayr_draw(RayRenderer* &renderer)
// {
// scene::scene_frame_tick(renderer->CurrentScene);
// scene::scene_frame_tick(renderer->Scene);
// // TODO: Rays should definately be bump allocated if possible, this is KBs of
// // ray data and nothing else being reallocated every frame for no reason
// ReferencedRayField startRays = mRaySource->getInitialRays(true);
// // ReferencedRayField startRays = mRaySource->getInitialRays(true);
//
// for (int x = 0; x < mRenderTargetSize.x; x++)
// for (int y = 0; y < mRenderTargetSize.y; y++)
// {
// mTarget[y * mRenderTargetSize.x + x] = { 0.1f, 0.1f, 0.1f, 1.0f };
// }
// for (int y = 0; y < mRenderTargetSize.y; y++) {
// mTarget[y * mRenderTargetSize.x + x] = { 0.1f, 0.1f, 0.1f, 1.0f };
// }
// mCurrentRefTable = &startRays.Reference;
//
// // before we start we now want to check that it hasn't been force-stopped
@@ -113,8 +115,7 @@
//
// yolo::info("Sample complete");
//
// for (auto* ray : startRays.Field)
// {
// for (auto* ray : startRays.Field) {
// delete ray;
// }
// }
@@ -122,22 +123,20 @@
// void RayRenderer::computeHit(HitInfo* info)
// {
// static float mind = 100000.0f;
// static float maxd = 0.0f;
// static float maxd = 0.0f;
// // TODO: Make sure signal is started
// if (!(*mCurrentRefTable).count(info->Caller->Reference))
// {
// if (!(*mCurrentRefTable).count(info->Caller->Reference)) {
// yolo::warn("Why is the ray not in the map?!");
// return;
// }
// glm::ivec2 pos = (*mCurrentRefTable)[info->Caller->Reference];
// float d = info->Distance;
// if (d < mind) mind = d;
// if (d > maxd) maxd = d;
// float d = info->Distance;
// if (d < mind)
// mind = d;
// if (d > maxd)
// maxd = d;
// float n = (d - mind) / (maxd - mind);
// mTarget[pos.y * mRenderTargetSize.x + pos.x] = { n, n, n, 1.0f};
// }
// void mHaultWait();
// std::unordered_map<uint32_t, glm::ivec2>* mCurrentRefTable;
//
//
// mTarget[pos.y * mRenderTargetSize.x + pos.x] = { n, n, n, 1.0f };
// }
}

View File

@@ -8,13 +8,12 @@
#include <unordered_map>
namespace inferno::scene {
struct Scene;
struct Scene;
}
namespace inferno::graphics {
class HHM;
class Camera;
class HitInfo;
class RaySource;
class RenderDispatcher;
@@ -22,17 +21,22 @@ class RenderDispatcher;
typedef struct RayRenderer {
glm::ivec2* Viewport;
// TODO: Can this be direct 2 GPU?
// TODO: Can this be direct to GPU?
// NOTE: Probably not
glm::fvec4* RenderData = nullptr;
GLuint RenderTargetTexture = 0;
// Internal stuffs
RaySource* RaySource = nullptr;
// RaySource* RaySource = nullptr;
scene::Scene* Scene = nullptr;
} RayRenderer;
RayRenderer* rayr_create(glm::ivec2 viewport, HHM* accelIface);
// Expects complete scene
RayRenderer* rayr_create(scene::Scene* scene);
void rayr_cleanup(RayRenderer* renderer);
void rayr_draw_ui(RayRenderer* renderer);
void rayr_set_viewport(RayRenderer* renderer, glm::ivec2 size);
GLuint rayr_get_rendered_texture(RayRenderer* renderer);

View File

@@ -1,5 +1,7 @@
#include <scene/camera.hpp>
#include <graphics.hpp>
namespace inferno::graphics {
Camera* camera_create()
@@ -35,6 +37,54 @@ void camera_cleanup(Camera* camera)
delete camera;
}
void camera_draw_ui(Camera* camera)
{
ImGui::PushItemWidth(100);
ImGui::Text("Camera Position X,Y,Z");
bool positionUpdated = false;
ImGui::DragFloat("X", &camera->Position.x, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
positionUpdated = true;
ImGui::DragFloat("Y", &camera->Position.y, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
positionUpdated = true;
ImGui::DragFloat("Z", &camera->Position.z, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
if (ImGui::IsItemEdited())
positionUpdated = true;
if (positionUpdated)
graphics::camera_set_position(camera, graphics::camera_get_position(camera));
bool viewUpdated = false;
ImGui::Text("Camera Look Yaw, Pitch, Roll");
ImGui::DragFloat("Yaw", &camera->Yaw, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::DragFloat("Pitch", &camera->Pitch, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::DragFloat("Roll", &camera->Roll, 0.01f, -FLT_MAX, FLT_MAX, "%.2f", ImGuiSliderFlags_None);
if (ImGui::IsItemEdited())
viewUpdated = true;
ImGui::PopItemWidth();
ImGui::PushItemWidth(300);
ImGui::Text("Camera Zoom");
ImGui::DragFloat("Zoom", &camera->FOV, -0.1f, 0.01f, 180.0f, "%.2f", ImGuiSliderFlags_None);
ImGui::SameLine();
if (ImGui::IsItemEdited())
viewUpdated = true;
if (viewUpdated)
graphics::camera_update(camera);
ImGui::PopItemWidth();
}
void camera_update(Camera* camera)
{
glm::mat4 matRoll = glm::mat4(1.0f);
@@ -100,7 +150,7 @@ glm::mat4 camera_get_look(Camera* camera)
return camera->LookMatrix;
}
void raster_set_viewport(Camera* camera, glm::ivec2 viewport)
void camera_raster_set_viewport(Camera* camera, glm::ivec2 viewport)
{
std::lock_guard<std::mutex> lock(camera->_impl->CamMutex);
camera->Views.Raster = viewport;
@@ -111,19 +161,19 @@ void raster_set_viewport(Camera* camera, glm::ivec2 viewport)
1000.0f);
}
glm::ivec2 raster_get_viewport(Camera* camera)
glm::ivec2 camera_raster_get_viewport(Camera* camera)
{
std::lock_guard<std::mutex> lock(camera->_impl->CamMutex);
return camera->Views.Raster;
}
void ray_set_viewport(Camera* camera, glm::ivec2 viewport)
void camera_ray_set_viewport(Camera* camera, glm::ivec2 viewport)
{
std::lock_guard<std::mutex> lock(camera->_impl->CamMutex);
camera->Views.Ray = viewport;
}
glm::ivec2 ray_get_viewport(Camera* camera)
glm::ivec2 camera_ray_get_viewport(Camera* camera)
{
std::lock_guard<std::mutex> lock(camera->_impl->CamMutex);
return camera->Views.Ray;