implemented some more controls

This commit is contained in:
Djairo Hougee 2025-01-11 17:54:01 +01:00
parent dc0175f88a
commit 9c7dd45858
7 changed files with 68 additions and 30 deletions

View File

@ -28,9 +28,9 @@ const ColorStop h_stopsBluePurleRed[] = {
__device__ Point3 d_cameraPos;
__device__ Vec3 d_cameraDir;
__device__ Vec3 d_cameraUp;
__device__ Point3 d_lightPos;
__device__ Color3 d_backgroundColor;
__device__ Vec3 d_cameraUp;
Vec3 h_cameraUp = Vec3::init(0.0, 1.0, 0.0).normalize();
@ -45,3 +45,9 @@ void copyConstantsToDevice() {
// ----------------------- Camera and Light -----------------------
cudaMemcpyToSymbol(d_cameraUp, &h_cameraUp, sizeof(Vec3));
}
// ----------------------- TransferFunction -----------------------
__device__ float d_opacityK;
__device__ float d_sigmoidOne;
__device__ float d_sigmoidTwo;

View File

@ -11,9 +11,8 @@ const int VOLUME_WIDTH = 97; // lon
const int VOLUME_HEIGHT = 71; // lat
const int VOLUME_DEPTH = 42; // lev
// TODO: replace with window->w and window->h
const int IMAGE_WIDTH = 800;
const int IMAGE_HEIGHT = 600;
const int INITIAL_WINDOW_WIDTH = 1200;
const int INITIAL_WINDOW_HEIGHT = 900;
const double epsilon = 1e-10f;
const double infty = 1e15f; // This value is used to represent missing values in data
@ -52,12 +51,19 @@ extern __device__ Point3 d_lightPos;
// Background color
extern __device__ Color3 d_backgroundColor;
// --------------------------- Transfer Function Constants ---------------------------
struct ColorStop {
float pos; // in [0,1]
Color3 color;
};
// factor for the opacity function
extern __device__ float d_opacityK;
// sigmoid function variables
extern __device__ float d_sigmoidOne;
extern __device__ float d_sigmoidTwo;
const int lenStopsPythonLike = 5;
const int lenStopsGrayscale = 2;
const int lenStopsBluePurpleRed = 3;

View File

@ -13,9 +13,9 @@ Widget::Widget(GLFWwindow* window) {
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init();
// this->cameraPos = Point3::init(50.0f, -50.0f, -75.0f); // Camera for partially trimmed data set
this->cameraPos = Point3::init(300.0f, 200.0f, -700.0f); // Camera for full data set
//
this->cameraPos = Point3::init(50.0f, -50.0f, -75.0f); // Camera for partially trimmed data set
// this->cameraPos = Point3::init(300.0f, 200.0f, -700.0f); // Camera for full data set
Vec3 h_center = Vec3::init((float)VOLUME_WIDTH/2.0f, (float)VOLUME_HEIGHT/2.0f, (float)VOLUME_DEPTH/2.0f);
this->cameraDir = (h_center - this->cameraPos).normalize();
@ -25,8 +25,13 @@ Widget::Widget(GLFWwindow* window) {
this->fps = (char*)malloc(512*sizeof(char));
this->paused = true;
this->renderOnce = false;
this->opacityK = 0;
this->sigmoidOne = 0.5f;
this->sigmoidTwo = -250.0f;
};
// TODO: can be marginally improvement by only copying changed values to device - however we're dealing with individual floats here so i dont think the benefit would be all that obvious.
void Widget::tick(double fps) {
if (this->renderOnce) {
this->renderOnce = false;
@ -40,16 +45,22 @@ void Widget::tick(double fps) {
// input widgets
float min = -1, max = 1;
ImGui::Begin("Transfer Function Controls");
ImGui::DragInt("k (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat("sigmoidOne", &this->sigmoidOne, 0.01f, 0.0f, 1.0f, "%.2f");
ImGui::InputFloat("sigmoidTwo", &this->sigmoidTwo, 10.0f, 100.0f, "%.0f");
ImGui::End();
ImGui::Begin("Light Controls");
ImGui::DragScalar("X coordinate", ImGuiDataType_Double, &this->lightPos.x, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Y coordinate", ImGuiDataType_Double, &this->lightPos.y, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Z coordinate", ImGuiDataType_Double, &this->lightPos.z, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("X coordinate", ImGuiDataType_Double, &this->lightPos.x, 0.5f, &min, &max, "%.3f");
ImGui::DragScalar("Y coordinate", ImGuiDataType_Double, &this->lightPos.z, 0.5f, &min, &max, "%.3f");
ImGui::DragScalar("Z coordinate", ImGuiDataType_Double, &this->lightPos.y, 0.5f, &min, &max, "%.3f");
ImGui::End();
ImGui::Begin("Miscellaneous");
if (ImGui::Button(this->paused ? "Unpause" : "Pause")) this->paused = !this->paused;
ImGui::SameLine();
if (ImGui::Button("render Once")) {
if (ImGui::Button("Render once")) {
this->paused = !this->paused;
this->renderOnce = true;
}
@ -58,12 +69,12 @@ void Widget::tick(double fps) {
ImGui::End();
ImGui::Begin("Camera Controls");
ImGui::DragScalar("X position", ImGuiDataType_Double, &this->cameraPos.x, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Y position", ImGuiDataType_Double, &this->cameraPos.y, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Z position", ImGuiDataType_Double, &this->cameraPos.z, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("X position", ImGuiDataType_Double, &this->cameraPos.x, 0.5f, &min, &max, "%.3f");
ImGui::DragScalar("Y position", ImGuiDataType_Double, &this->cameraPos.z, 0.5f, &min, &max, "%.3f");
ImGui::DragScalar("Z position", ImGuiDataType_Double, &this->cameraPos.y, 0.5f, &min, &max, "%.3f");
ImGui::DragScalar("X direction", ImGuiDataType_Double, &this->cameraDir.x, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Y direction", ImGuiDataType_Double, &this->cameraDir.y, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Z direction", ImGuiDataType_Double, &this->cameraDir.z, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Y direction", ImGuiDataType_Double, &this->cameraDir.z, 0.005f, &min, &max, "%.3f");
ImGui::DragScalar("Z direction", ImGuiDataType_Double, &this->cameraDir.y, 0.005f, &min, &max, "%.3f");
ImGui::End();
copyToDevice();
@ -79,6 +90,13 @@ void Widget::copyToDevice() {
cudaMemcpyToSymbol(&d_cameraDir, &this->cameraDir, sizeof(Vec3));
cudaMemcpyToSymbol(&d_lightPos, &this->lightPos, sizeof(Point3));
cudaMemcpyToSymbol(&d_backgroundColor, &this->bgColor, sizeof(Color3));
// cudaMemcpyToSymbol(&d_opacityK, &this->opacityK, sizeof(float));
this->opacityKReal = std::pow(10.0f, (-10 + 0.1 * this->opacityK));
cudaMemcpyToSymbol(&d_opacityK, &this->opacityKReal, sizeof(float));
cudaMemcpyToSymbol(&d_sigmoidOne, &this->sigmoidOne, sizeof(float));
cudaMemcpyToSymbol(&d_sigmoidTwo, &this->sigmoidTwo, sizeof(float));
}
Widget::~Widget() {

View File

@ -12,12 +12,17 @@ public:
Point3 cameraDir;
Vec3 cameraPos;
Point3 lightPos;
Color3 bgColor;
Color3 bgColor; // TODO: widget
bool paused;
bool renderOnce;
char* fps;
int opacityK;
float opacityKReal;
float sigmoidOne;
float sigmoidTwo;
ImGuiIO io;
void tick(double fps);

View File

@ -12,10 +12,10 @@
#include <curand_kernel.h>
// TODO: instead of IMAGEWIDTH and IMAGEHEIGHT this should reflect the windowSize;
__global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer) {
__global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const int width, const int height) {
int px = blockIdx.x * blockDim.x + threadIdx.x;
int py = blockIdx.y * blockDim.y + threadIdx.y;
if (px >= IMAGE_WIDTH || py >= IMAGE_HEIGHT) return;
if (px >= width || py >= height) return;
float accumR = 0.0f;
float accumG = 0.0f;
@ -24,15 +24,15 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer) {
// Initialize random state for ray scattering
curandState randState;
curand_init(1234, px + py * IMAGE_WIDTH, 0, &randState);
curand_init(1234, px + py * width, 0, &randState);
// Multiple samples per pixel
for (int s = 0; s < SAMPLES_PER_PIXEL; s++) {
// Map to [-1, 1]
float jitterU = (curand_uniform(&randState) - 0.5f) / IMAGE_WIDTH;
float jitterV = (curand_uniform(&randState) - 0.5f) / IMAGE_HEIGHT;
float u = ((px + 0.5f + jitterU) / IMAGE_WIDTH ) * 2.0f - 1.0f;
float v = ((py + 0.5f + jitterV) / IMAGE_HEIGHT) * 2.0f - 1.0f;
float jitterU = (curand_uniform(&randState) - 0.5f) / width;
float jitterV = (curand_uniform(&randState) - 0.5f) / height;
float u = ((px + 0.5f + jitterU) / width ) * 2.0f - 1.0f;
float v = ((py + 0.5f + jitterV) / height) * 2.0f - 1.0f;
float tanHalfFov = tanf(fov * 0.5f);
u *= tanHalfFov;
@ -167,7 +167,7 @@ void Raycaster::render() {
// TODO: pass camera info at some point
// frame buffer is implicitly copied to the device each frame
raycastKernel<<<threadSize, blockSize>>> (this->data, *this->fb);
raycastKernel<<<threadSize, blockSize>>> (this->data, *this->fb, this->w, this->h);
check_cuda_errors(cudaGetLastError());
check_cuda_errors(cudaDeviceSynchronize());

View File

@ -1,4 +1,7 @@
#include "transferFunction.h"
#include "consts.h"
#include <stdio.h>
// Samples the voxel nearest to the given coordinates.
@ -53,13 +56,12 @@ __device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const
__device__ float opacityFromGradient(const Vec3 &grad) {
float gradMag = grad.length();
float k = 1e-6f; // tweak (the smaller the value, the less opacity) // TODO: Add a slider for this
float alpha = 1.0f - expf(-k * gradMag);
float alpha = 1.0f - expf(-d_opacityK * gradMag);
return alpha;
}
__device__ float opacitySigmoid(float val) {
return 1.0f / (1.0f + expf(-250.f * (val - 0.5f))); // TODO: Parametrize and add sliders
return 1.0f / (1.0f + expf(d_sigmoidTwo * (val - d_sigmoidOne)));
}
__device__ Color3 colorMap(float normalizedValues, const ColorStop stops[], int N) {
@ -96,6 +98,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3
// TODO: Add a way to pick stops here
Color3 baseColor = colorMap(normDensity, d_stopsPythonLike, lenStopsPythonLike);
// TODO: This is a Gui select element
// TODO: Add a way to pick different function for alpha
float alpha = opacityFromGradient(grad);
// alpha = 0.1f;

View File

@ -15,7 +15,7 @@
static float* d_volume = nullptr;
// FIXME: segfaults on window resize - the raycasting function should work with window->w and window-h instead of constants.
// FIXME: segfaults on window resize - the problem is _not_ in the raycasting function
// TODO: general
// * very similarly - actual code for loading new data as the simulation progresses - right now its effectively a static image loader * pause button once that dataloading is implemented
@ -116,7 +116,7 @@ int main() {
copyConstantsToDevice();
// Create the GUI
Window window(IMAGE_WIDTH, IMAGE_HEIGHT);
Window window(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT);
int out = window.init(d_volume);
// memory management