feat (wip): real-time gui with rendering in opengl

This commit is contained in:
2025-01-03 19:57:10 +01:00
parent c92d0bc2a9
commit c23a33ebef
22 changed files with 656 additions and 62 deletions

View File

@@ -0,0 +1,13 @@
#include "FrameBuffer.h"
#include "linalg/linalg.h"
__host__ FrameBuffer::FrameBuffer(unsigned int w, unsigned int h) : w(w), h(h) {}
__device__ void FrameBuffer::writePixel(int x, int y, float r, float g, float b) {
int i = y * this->w + x;
// the opengl buffer uses BGRA format; dunno why
this->buffer[i] = packUnorm4x8(b, g, r, 1.0f);
}

View File

@@ -0,0 +1,20 @@
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include "cuda_runtime.h"
#include "linalg/linalg.h"
#include <cstdint>
class FrameBuffer {
public:
uint32_t* buffer;
std::size_t buffer_size;
unsigned int w;
unsigned int h;
__host__ FrameBuffer(unsigned int w, unsigned int h);
__device__ void writePixel(int x, int y, float r, float g, float b);
};
#endif // FRAMEBUFFER_H

View File

@@ -1,14 +1,16 @@
#ifndef RAYCASTER_H
#define RAYCASTER_H
#include "Raycaster.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda_runtime.h>
#include "linalg/linalg.h"
#include "consts.h"
#include "shading.h"
#include <iostream>
#include "objs/sphere.h"
// Raycast + phong, TODO: Consider wrapping in a class
__global__ void raycastKernel(float* volumeData, unsigned char* framebuffer) {
__global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer) {
int px = blockIdx.x * blockDim.x + threadIdx.x;
int py = blockIdx.y * blockDim.y + threadIdx.y;
if (px >= IMAGE_WIDTH || py >= IMAGE_HEIGHT) return;
@@ -117,10 +119,109 @@ __global__ void raycastKernel(float* volumeData, unsigned char* framebuffer) {
accumB /= (float)SAMPLES_PER_PIXEL;
// Final colour
int fbIndex = (py * IMAGE_WIDTH + px) * 3;
framebuffer[fbIndex + 0] = (unsigned char)(fminf(accumR, 1.f) * 255);
framebuffer[fbIndex + 1] = (unsigned char)(fminf(accumG, 1.f) * 255);
framebuffer[fbIndex + 2] = (unsigned char)(fminf(accumB, 1.f) * 255);
framebuffer.writePixel(px, py, accumR, accumG, accumB);
// int fbIndex = (py * IMAGE_WIDTH + px) * 3;
// framebuffer[fbIndex + 0] = (unsigned char)(fminf(accumR, 1.f) * 255);
// framebuffer[fbIndex + 1] = (unsigned char)(fminf(accumG, 1.f) * 255);
// framebuffer[fbIndex + 2] = (unsigned char)(fminf(accumB, 1.f) * 255);
}
#endif // RAYCASTER_H
Raycaster::Raycaster(cudaGraphicsResource_t resources, int w, int h) {
this->resources = resources;
this->w = h;
this->w = h;
this->fb = new FrameBuffer(w, h);
// camera_info = CameraInfo(Vec3(0.0f, 0.0f, 0.0f), Vec3(0.0f, 0.0f, 0.0f), 90.0f, (float) w, (float) h);
// d_camera = thrust::device_new<Camera*>();
int res = cudaDeviceSynchronize();
if (res) {
std::cout << "CUDA error while synchronizing device: " << res;
cudaDeviceReset();
exit(1);
}
res = cudaDeviceSynchronize();
if (res) {
std::cout << "CUDA error while synchronizing device: " << res;
cudaDeviceReset();
exit(1);
}
}
void Raycaster::render() {
int res = cudaGraphicsMapresources(1, this->resources);
if (res) {
std::cout << "CUDA error while mapping graphic resource: " << res;
cudaDeviceReset();
exit(1);
}
// check_cuda_errors(cudaGraphicsResourceGetMappedPointer((void**)&(frame_buffer->device_ptr), &(frame_buffer->buffer_size), resources));
res = cudaGraphicsResourceGetMappedPointer((void**)(this->fb->buffer), &this->fb->buffer_size, this->resources);
if (res) {
std::cout << "CUDA error while fetching resource pointer: " << res;
cudaDeviceReset();
exit(1);
}
// FIXME: might not be the best parallelization configuraiton
int tx = 32;
int ty = 32;
dim3 blocks(this->w / tx + 1, this->h / ty + 1);
dim3 threads(tx, ty);
// TODO: pass camera info at some point
// TODO: pass float volume data.
// frame buffer is implicitly copied to the device each frame
raycastKernel<<<blocks, threads>>> (nullptr, this->fb);
res = cudaGetLastError();
if (res) {
std::cout << "CUDA error while raycasting: " << res;
cudaDeviceReset();
exit(1);
}
res = cudaDeviceSynchronize();
if (res) {
std::cout << "CUDA error while synchronizing device: " << res;
cudaDeviceReset();
exit(1);
}
res = cudaGraphicsUnmapResources(1, &this->resources);
if (res) {
std::cout << "CUDA error while unmapping a resource: " << res;
cudaDeviceReset();
exit(1);
}
}
void Raycaster::resize(int w, int h) {
this->w = w;
this->h = h;
delete fb;
this->fb = new FrameBuffer(w, h);
// TODO: should be globals probably
int tx = 8;
int ty = 8;
dim3 blocks(w / tx + 1, h / ty + 1);
dim3 threads(tx, ty);
int res = cudaDeviceSynchronize();
if (res != 0) {
std::cout << "CUDA error while synchronizing device: " << res;
cudaDeviceReset();
exit(1);
}
}

View File

@@ -0,0 +1,33 @@
#ifndef RAYCASTER_H
#define RAYCASTER_H
// #include "Camera.h"
#include "cuda_runtime.h"
#include "FrameBuffer.h"
#include "linalg/linalg.h"
// #include <thrust/device_ptr.h>
__global__ void raycastKernel(float* volumeData, unsigned char* framebuffer);
struct Raycaster {
// thrust::device_ptr<Camera*> d_camera;
// CameraInfo camera_info;
cudaGraphicsResource_t resources;
FrameBuffer* fb;
int w;
int h;
Raycaster() {};
Raycaster(cudaGraphicsResource_t resources, int nx, int ny);
// ~Raycaster();
void set_camera(Vec3 position, Vec3 forward, Vec3 up);
void render();
void resize(int nx, int ny);
// void raycastKernel(float* volumeData, unsigned char* framebuffer); // TODO: proper framebuffer class
};
#endif // RAYCASTER_H

View File

@@ -1,7 +1,7 @@
#ifndef ILLUMINATION_H
#define ILLUMINATION_H
#include "raycaster.h"
#include "Raycaster.h"
#include "shading.h"
#endif // ILLUMINATION_H
#endif // ILLUMINATION_H

View File

@@ -0,0 +1,14 @@
#include "shading.h"
// TODO: Consider wrapping this in a class (?)
__device__ Vec3 phongShading(const Vec3& normal, const Vec3& lightDir, const Vec3& viewDir, const Vec3& baseColor) {
Vec3 ambient = baseColor * ambientStrength;
double diff = fmax(normal.dot(lightDir), 0.0);
Vec3 diffuse = baseColor * (diffuseStrength * diff);
Vec3 reflectDir = (normal * (2.0 * normal.dot(lightDir)) - lightDir).normalize();
double spec = pow(fmax(viewDir.dot(reflectDir), 0.0), shininess);
Vec3 specular = Vec3::init(1.0, 1.0, 1.0) * (specularStrength * spec);
return ambient + diffuse + specular;
};

View File

@@ -4,17 +4,7 @@
#include "linalg/linalg.h"
#include "consts.h"
// TODO: Consider wrapping this in a class (?)
__device__ Vec3 phongShading(const Vec3& normal, const Vec3& lightDir, const Vec3& viewDir, const Vec3& baseColor) {
Vec3 ambient = baseColor * ambientStrength;
double diff = fmax(normal.dot(lightDir), 0.0);
Vec3 diffuse = baseColor * (diffuseStrength * diff);
__device__ Vec3 phongShading(const Vec3& normal, const Vec3& lightDir, const Vec3& viewDir, const Vec3& baseColor);
Vec3 reflectDir = (normal * (2.0 * normal.dot(lightDir)) - lightDir).normalize();
double spec = pow(fmax(viewDir.dot(reflectDir), 0.0), shininess);
Vec3 specular = Vec3::init(1.0, 1.0, 1.0) * (specularStrength * spec);
return ambient + diffuse + specular;
}
#endif // SHADING_H
#endif // SHADING_H