From b7002161869c4e47eb4f2b08f3570dded88c713c Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 14:31:41 +0100 Subject: [PATCH 01/22] Added (more) volume constants --- src/consts.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/consts.h b/src/consts.h index 7e6faad..80afde8 100644 --- a/src/consts.h +++ b/src/consts.h @@ -5,12 +5,6 @@ #include // --------------------------- Basic Constants --------------------------- -// const int VOLUME_WIDTH = 576; // lon -const int VOLUME_WIDTH = 97; // lon -// const int VOLUME_HEIGHT = 361; // lat -const int VOLUME_HEIGHT = 71; // lat -const int VOLUME_DEPTH = 42; // lev - const int INITIAL_WINDOW_WIDTH = 1200; const int INITIAL_WINDOW_HEIGHT = 900; @@ -18,6 +12,16 @@ const double epsilon = 1e-10f; const double infty = 1e15f; // This value is used to represent missing values in data // --------------------------- Dataset Constants --------------------------- +// const int VOLUME_WIDTH = 576; // lon +const int VOLUME_WIDTH = 97; // lon +// const int VOLUME_HEIGHT = 361; // lat +const int VOLUME_HEIGHT = 71; // lat +const int VOLUME_DEPTH = 42; // lev + +const float DLON = 60.0f / VOLUME_WIDTH; // 60 for current trimmed data set range +const float DLAT = 35.0f / VOLUME_HEIGHT; // 35 for current trimmed data set range +const float DLEV = 1000.0f / VOLUME_DEPTH; // 1000 from max pressure (hPa) but not sure here + const float MIN_TEMP = 210.0f; const float MAX_TEMP = 240.0f; From 7fa2954e173cbb68e9078e98bead46b7e439c212 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 14:45:38 +0100 Subject: [PATCH 02/22] Moved and re-implemented gradient --- src/illumination/transferFunction.cu | 14 --------- src/linalg/mat.cu | 43 +++++++++++++++++----------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index c33e8e5..0ad9369 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -4,20 +4,6 @@ #include -// Samples the voxel nearest to the given coordinates. -__device__ float sampleVolumeNearest(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz) { - // x <-> height, y <-> width, z <-> depth <--- So far this is the best one - if (vx < 0) vx = 0; - if (vy < 0) vy = 0; - if (vz < 0) vz = 0; - if (vx >= volH) vx = volH - 1; - if (vy >= volW) vy = volW - 1; - if (vz >= volD) vz = volD - 1; - - int idx = vz * volW * volH + vx * volW + vy; - return volumeData[idx]; -} - // tri-linear interpolation - ready if necessary (but no visible improvement for full volume) __device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz) { int ix = (int)floorf(fx); diff --git a/src/linalg/mat.cu b/src/linalg/mat.cu index 2d1c8dc..f75b0dc 100644 --- a/src/linalg/mat.cu +++ b/src/linalg/mat.cu @@ -1,29 +1,40 @@ #include "mat.h" +#include "consts.h" + #include #include using namespace std; -__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, int x, int y, int z) { - // Finite difference for partial derivatives. +// Samples the voxel nearest to the given coordinates. +__device__ float sampleVolumeNearest(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz) { // For boundary voxels - clamp to the boundary. + if (vx < 0) vx = 0; + if (vy < 0) vy = 0; + if (vz < 0) vz = 0; + if (vx >= volH) vx = volH - 1; + if (vy >= volW) vy = volW - 1; + if (vz >= volD) vz = volD - 1; - int xm = max(x - 1, 0); - int xp = min(x + 1, volH - 1); - int ym = max(y - 1, 0); - int yp = min(y + 1, volW - 1); - int zm = max(z - 1, 0); - int zp = min(z + 1, volD - 1); + // x <-> height, y <-> width, z <-> depth + int idx = vz * volW * volH + vx * volW + vy; + return volumeData[idx]; +} - // Note: Assuming data is linearized (idx = z * W * H + x * W + y;) TODO: Unlinearize if data not linear - float gx = volumeData[z * volW * volH + xp * volW + y] - - volumeData[z * volW * volH + xm * volW + y]; - float gy = volumeData[z * volW * volH + x * volW + yp] - - volumeData[z * volW * volH + x * volW + ym]; - float gz = volumeData[zp * volW * volH + x * volW + y ] - - volumeData[zm * volW * volH + x * volW + y ]; +__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz) { + // Finite difference for partial derivatives. + - return Vec3::init(gx, gy, gz); + float dfdx = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx + 1, vy, vz) - + sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx - 1, vy, vz)) / (2.0f * DLAT); // x => height => lat + + float dfdy = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy + 1, vz) - + sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy - 1, vz)) / (2.0f * DLON); // y => width => lon + + float dfdz = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy, vz + 1) - + sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy, vz - 1)) / (2.0f * DLEV); + + return Vec3::init(dfdx, dfdy, dfdz); }; // TESTING: haven't tested this function at all tbh From 3a944138e956d1c2a08d6c10f1a44cad33113899 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 15:22:01 +0100 Subject: [PATCH 03/22] Implemented gradient to actually interpolate the data --- src/linalg/mat.cu | 55 +++++++++++++++++++++++++++++++++++++++-------- src/linalg/mat.h | 5 ++++- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/linalg/mat.cu b/src/linalg/mat.cu index f75b0dc..745ddfb 100644 --- a/src/linalg/mat.cu +++ b/src/linalg/mat.cu @@ -21,18 +21,55 @@ __device__ float sampleVolumeNearest(float* volumeData, const int volW, const in return volumeData[idx]; } -__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz) { - // Finite difference for partial derivatives. +// tri-linear interpolation - ready if necessary (but no visible improvement for full volume) +__device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz) { + int ix = (int)floorf(fx); + int iy = (int)floorf(fy); + int iz = (int)floorf(fz); + + // Clamp indices to valid range + int ix1 = min(ix + 1, volH - 1); + int iy1 = min(iy + 1, volW - 1); + int iz1 = min(iz + 1, volD - 1); + ix = max(ix, 0); + iy = max(iy, 0); + iz = max(iz, 0); + + // Compute weights + float dx = fx - ix; + float dy = fy - iy; + float dz = fz - iz; + + // Sample values + float c00 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy, iz) * (1.0f - dx) + + sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy, iz) * dx; + float c10 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy1, iz) * (1.0f - dx) + + sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy1, iz) * dx; + float c01 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy, iz1) * (1.0f - dx) + + sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy, iz1) * dx; + float c11 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy1, iz1) * (1.0f - dx) + + sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy1, iz1) * dx; + + float c0 = c00 * (1.0f - dy) + c10 * dy; + float c1 = c01 * (1.0f - dy) + c11 * dy; + + return c0 * (1.0f - dz) + c1 * dz; +} + +__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz) { + // Compute gradient using central differencing with trilinear interpolation + float hx = DLAT; // x => height => lat + float hy = DLON; // y => width => lon + float hz = DLEV; // z => depth => alt + float dfdx = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx + hx, fy, fz) - + sampleVolumeTrilinear(volumeData, volW, volH, volD, fx - hx, fy, fz)) / (2.0f * hx); - float dfdx = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx + 1, vy, vz) - - sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx - 1, vy, vz)) / (2.0f * DLAT); // x => height => lat + float dfdy = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy + hy, fz) - + sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy - hy, fz)) / (2.0f * hy); - float dfdy = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy + 1, vz) - - sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy - 1, vz)) / (2.0f * DLON); // y => width => lon - - float dfdz = (sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy, vz + 1) - - sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, vx, vy, vz - 1)) / (2.0f * DLEV); + float dfdz = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz + hz) - + sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz - hz)) / (2.0f * hz); return Vec3::init(dfdx, dfdy, dfdz); }; diff --git a/src/linalg/mat.h b/src/linalg/mat.h index 02234c0..7591761 100644 --- a/src/linalg/mat.h +++ b/src/linalg/mat.h @@ -4,7 +4,10 @@ #include "vec.h" #include "consts.h" -__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, int x, int y, int z); +__device__ float sampleVolumeNearest(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz); +__device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz); + +__device__ Vec3 computeGradient(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz); __device__ unsigned int packUnorm4x8(float r, float g, float b, float a); From a1869aba0260eb33b39656b0a2aa534693e13c6c Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 15:33:09 +0100 Subject: [PATCH 04/22] Improved silhoutte detection --- src/illumination/Raycaster.cu | 2 +- src/illumination/transferFunction.cu | 53 +++++----------------------- src/illumination/transferFunction.h | 6 ---- 3 files changed, 9 insertions(+), 52 deletions(-) diff --git a/src/illumination/Raycaster.cu b/src/illumination/Raycaster.cu index 400cce1..ba72985 100644 --- a/src/illumination/Raycaster.cu +++ b/src/illumination/Raycaster.cu @@ -98,7 +98,7 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const // If density ~ 0, skip shading if (density > minAllowedDensity) { - Vec3 grad = computeGradient(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, ix, iy, iz); + Vec3 grad = computeGradient(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, pos.x, pos.y, pos.z); float4 color = transferFunction(density, grad, pos, rayDir); // This already returns the alpha-weighted color //Accumulate color, and alpha diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 0ad9369..fe0650c 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -4,41 +4,6 @@ #include -// tri-linear interpolation - ready if necessary (but no visible improvement for full volume) -__device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz) { - int ix = (int)floorf(fx); - int iy = (int)floorf(fy); - int iz = (int)floorf(fz); - - // Clamp indices to valid range - int ix1 = min(ix + 1, volH - 1); - int iy1 = min(iy + 1, volW - 1); - int iz1 = min(iz + 1, volD - 1); - ix = max(ix, 0); - iy = max(iy, 0); - iz = max(iz, 0); - - // Compute weights - float dx = fx - ix; - float dy = fy - iy; - float dz = fz - iz; - - // Sample values - float c00 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy, iz) * (1.0f - dx) + - sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy, iz) * dx; - float c10 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy1, iz) * (1.0f - dx) + - sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy1, iz) * dx; - float c01 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy, iz1) * (1.0f - dx) + - sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy, iz1) * dx; - float c11 = sampleVolumeNearest(volumeData, volW, volH, volD, ix, iy1, iz1) * (1.0f - dx) + - sampleVolumeNearest(volumeData, volW, volH, volD, ix1, iy1, iz1) * dx; - - float c0 = c00 * (1.0f - dy) + c10 * dy; - float c1 = c01 * (1.0f - dy) + c11 * dy; - - return c0 * (1.0f - dz) + c1 * dz; -} - __device__ float opacityFromGradient(const Vec3 &grad) { float gradMag = grad.length(); @@ -98,7 +63,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 Vec3 normal = -grad.normalize(); Vec3 lightDir = (d_lightPos - pos).normalize(); Vec3 viewDir = -rayDir.normalize(); - Vec3 shadedColor = phongShading(normal, lightDir, viewDir, baseColor); + Vec3 shadedColor = phongShading(normal, lightDir, viewDir, baseColor); // TODO: Fix pixelated // Compose float4 result; @@ -108,15 +73,13 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 result.w = alpha; // --------------------------- Silhouettes --------------------------- - // TODO: This is the black silhouette, technically if we are doing alpha based on gradient then it's kind of redundant (?) ... but could also be used for even more pronounced edges - // TODO: Add a way to adjust the treshold (0.2f atm) - // TODO: I don't think we should literally be doing this => use gradient based opacity => delete the below if-statement - // if (fabs(grad.normalize().dot(rayDir.normalize())) < 0.2f) { - // result.x = 0.0f; - // result.y = 0.0f; - // result.z = 0.0f; - // result.w = 1.0f; - // } + Vec3 N = grad.normalize(); + if (grad.length() > 0.2f && fabs(N.dot(viewDir)) < 0.02f) { + result.x = 0.0f; + result.y = 0.0f; + result.z = 0.0f; + result.w = 1.0f; + } return result; } diff --git a/src/illumination/transferFunction.h b/src/illumination/transferFunction.h index cd33929..3fd55b7 100644 --- a/src/illumination/transferFunction.h +++ b/src/illumination/transferFunction.h @@ -7,12 +7,6 @@ // --------------------------- Color mapping --------------------------- - -// --------------------------- Volume sampling --------------------------- -__device__ float sampleVolumeNearest(float* volumeData, const int volW, const int volH, const int volD, int vx, int vy, int vz); -__device__ float sampleVolumeTrilinear(float* volumeData, const int volW, const int volH, const int volD, float fx, float fy, float fz); - - // --------------------------- Transfer function --------------------------- __device__ float4 transferFunction(float density, const Vec3& grad, const Point3& pos, const Vec3& rayDir); From db81b97264e65a6314c2eb2368b55c2863c9d1a6 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 15:58:52 +0100 Subject: [PATCH 05/22] Fixed max temp being wrong for some reason --- src/consts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consts.h b/src/consts.h index 80afde8..0811c7f 100644 --- a/src/consts.h +++ b/src/consts.h @@ -23,7 +23,7 @@ const float DLAT = 35.0f / VOLUME_HEIGHT; // 35 for current trimmed data set ra const float DLEV = 1000.0f / VOLUME_DEPTH; // 1000 from max pressure (hPa) but not sure here const float MIN_TEMP = 210.0f; -const float MAX_TEMP = 240.0f; +const float MAX_TEMP = 293.0f; const float MIN_SPEED = 0.0F; const float MAX_SPEED = 14.0f; From 6085a77c662e8b88c140a7092c728c435712884b Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 15:59:07 +0100 Subject: [PATCH 06/22] Added TODOs in comments --- src/illumination/transferFunction.cu | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index fe0650c..57525af 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -7,7 +7,7 @@ __device__ float opacityFromGradient(const Vec3 &grad) { float gradMag = grad.length(); - float alpha = 1.0f - expf(-d_opacityK * gradMag); + float alpha = 1.0f - expf(-d_opacityK * gradMag); // TODO: This parameter probably has the wrong scale return alpha; } @@ -53,7 +53,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 // TODO: Add a way to pick different function for alpha float alpha = opacityFromGradient(grad); // alpha = 0.1f; - alpha = opacitySigmoid(normDensity); +// alpha = opacitySigmoid(normDensity); // alpha = (1.0f - fabs(grad.normalize().dot(rayDir.normalize()))) * 0.8f + 0.2f; float alphaSample = density * alpha * 0.1; @@ -63,7 +63,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 Vec3 normal = -grad.normalize(); Vec3 lightDir = (d_lightPos - pos).normalize(); Vec3 viewDir = -rayDir.normalize(); - Vec3 shadedColor = phongShading(normal, lightDir, viewDir, baseColor); // TODO: Fix pixelated + Vec3 shadedColor = phongShading(normal, lightDir, viewDir, baseColor); // TODO: Check if still pixelated // Compose float4 result; @@ -78,7 +78,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 result.x = 0.0f; result.y = 0.0f; result.z = 0.0f; - result.w = 1.0f; + result.w = alpha; // TODO: Figure out what to do about silhouettes either only on top or not at all } return result; From 1b32469a69dc0280f719dd4312f557884c68b1da Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 18:21:43 +0100 Subject: [PATCH 07/22] Renamed sigmoid GUI params --- src/consts.cu | 4 ++-- src/consts.h | 4 ++-- src/gui/input/Widget.cpp | 12 ++++++------ src/gui/input/Widget.h | 4 ++-- src/illumination/transferFunction.cu | 4 ++-- src/linalg/mat.cu | 9 +++++++++ 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/consts.cu b/src/consts.cu index 2252c36..72733f6 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -49,6 +49,6 @@ void copyConstantsToDevice() { // ----------------------- TransferFunction ----------------------- __device__ float d_opacityK; -__device__ float d_sigmoidOne; -__device__ float d_sigmoidTwo; +__device__ float d_sigmoidShift; +__device__ float d_sigmoidExp; __device__ int d_tfComboSelected; diff --git a/src/consts.h b/src/consts.h index 0811c7f..239d58e 100644 --- a/src/consts.h +++ b/src/consts.h @@ -65,8 +65,8 @@ struct ColorStop { // factor for the opacity function extern __device__ float d_opacityK; // sigmoid function variables -extern __device__ float d_sigmoidOne; -extern __device__ float d_sigmoidTwo; +extern __device__ float d_sigmoidShift; +extern __device__ float d_sigmoidExp; // combo box index extern __device__ int d_tfComboSelected; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 92001ef..b6ba24c 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -27,8 +27,8 @@ Widget::Widget(GLFWwindow* window) { this->renderOnce = false; this->opacityK = 0; - this->sigmoidOne = 0.5f; - this->sigmoidTwo = -250.0f; + this->sigmoidShift = 0.5f; + this->sigmoidExp = -250.0f; this->tfComboSelected = 0; }; @@ -50,8 +50,8 @@ void Widget::tick(double fps) { 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::DragFloat("sigmoidShift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); + ImGui::InputFloat("sigmoidExp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); // the items[] contains the entries for the combobox. The selected index is stored as an int on this->tfComboSelected // the default entry is set in the constructor, so if you want that to be a specific entry just change it @@ -115,8 +115,8 @@ void Widget::copyToDevice() { 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)); + cudaMemcpyToSymbol(&d_sigmoidShift, &this->sigmoidShift, sizeof(float)); + cudaMemcpyToSymbol(&d_sigmoidExp, &this->sigmoidExp, sizeof(float)); cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(float)); } diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index 15370c7..52727b3 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -21,8 +21,8 @@ public: int tfComboSelected; int opacityK; float opacityKReal; - float sigmoidOne; - float sigmoidTwo; + float sigmoidShift; + float sigmoidExp; ImGuiIO io; diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 57525af..6930284 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -7,12 +7,12 @@ __device__ float opacityFromGradient(const Vec3 &grad) { float gradMag = grad.length(); - float alpha = 1.0f - expf(-d_opacityK * gradMag); // TODO: This parameter probably has the wrong scale + float alpha = 1.0f - expf(-1 * gradMag); // TODO: This parameter probably has the wrong scale return alpha; } __device__ float opacitySigmoid(float val) { - return 1.0f / (1.0f + expf(d_sigmoidTwo * (val - d_sigmoidOne))); + return 1.0f / (1.0f + expf(d_sigmoidExp * (val - d_sigmoidShift))); } __device__ Color3 colorMap(float normalizedValues, const ColorStop stops[], int N) { diff --git a/src/linalg/mat.cu b/src/linalg/mat.cu index 745ddfb..788867d 100644 --- a/src/linalg/mat.cu +++ b/src/linalg/mat.cu @@ -62,6 +62,7 @@ __device__ Vec3 computeGradient(float* volumeData, const int volW, const int vol float hy = DLON; // y => width => lon float hz = DLEV; // z => depth => alt + // Default float dfdx = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx + hx, fy, fz) - sampleVolumeTrilinear(volumeData, volW, volH, volD, fx - hx, fy, fz)) / (2.0f * hx); @@ -71,6 +72,14 @@ __device__ Vec3 computeGradient(float* volumeData, const int volW, const int vol float dfdz = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz + hz) - sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz - hz)) / (2.0f * hz); + // // DEBUG (TODO: Delete) - Back to nearest + // float dfdx = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx + 1), (int)roundf(fy), (int)roundf(fz)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx - 1), (int)roundf(fy), (int)roundf(fz))) / (2.0f * hx); + // float dfdy = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy + 1), (int)roundf(fz)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy - 1), (int)roundf(fz))) / (2.0f * hy); + // float dfdz = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz + 1)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz - 1))) / (2.0f * hz); + return Vec3::init(dfdx, dfdy, dfdz); }; From edcde639da322b1b64fc96f7a35bbefef036d2da Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 18:33:47 +0100 Subject: [PATCH 08/22] Renamed GUI elements --- src/gui/input/Widget.cpp | 4 ++-- src/illumination/transferFunction.cu | 26 ++++++++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index b6ba24c..8b9b2de 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -49,14 +49,14 @@ void Widget::tick(double fps) { 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::DragInt("Gradient exp. (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); ImGui::DragFloat("sigmoidShift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); ImGui::InputFloat("sigmoidExp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); // the items[] contains the entries for the combobox. The selected index is stored as an int on this->tfComboSelected // the default entry is set in the constructor, so if you want that to be a specific entry just change it // whatever value is selected here is available on the gpu as d_tfComboSelected. - const char* items[] = {"First option", "Another option", "this is the third option", "..."}; + const char* items[] = {"Opacity - gradient", "Opacity - sigmoid", "Opacity - constant", "..."}; if (ImGui::BeginCombo("ComboBox for transferFunction", items[this->tfComboSelected])) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 6930284..a360602 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -7,7 +7,7 @@ __device__ float opacityFromGradient(const Vec3 &grad) { float gradMag = grad.length(); - float alpha = 1.0f - expf(-1 * gradMag); // TODO: This parameter probably has the wrong scale + float alpha = 1.0f - expf(-d_opacityK * gradMag); // TODO: This parameter probably has the wrong scale return alpha; } @@ -51,12 +51,26 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 // TODO: This is a Gui select element // TODO: Add a way to pick different function for alpha - float alpha = opacityFromGradient(grad); - // alpha = 0.1f; -// alpha = opacitySigmoid(normDensity); - // alpha = (1.0f - fabs(grad.normalize().dot(rayDir.normalize()))) * 0.8f + 0.2f; + float alpha; + switch (d_tfComboSelected) { + case 0: + alpha = opacityFromGradient(grad); + break; + + case 1: + alpha = opacitySigmoid(normDensity); + break; - float alphaSample = density * alpha * 0.1; + case 2: + alpha = 0.1f; + break; + + default: + alpha = 1.0f; // This should not be reached anyway + break; + } + + float alphaSample = density * alpha * 0.1; // TODO: Why is this still 0.1? // --------------------------- Shading --------------------------- // Apply Phong From 30182885f8f1d81eae73b9757e1587c0c4a5d5a9 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 18:46:43 +0100 Subject: [PATCH 09/22] Added log slider for opacity const option --- src/consts.cu | 1 + src/consts.h | 4 +++- src/gui/input/Widget.cpp | 5 +++++ src/gui/input/Widget.h | 2 ++ src/illumination/transferFunction.cu | 2 +- 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/consts.cu b/src/consts.cu index 72733f6..fc9d1b9 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -52,3 +52,4 @@ __device__ float d_opacityK; __device__ float d_sigmoidShift; __device__ float d_sigmoidExp; __device__ int d_tfComboSelected; +__device__ float d_opacityConst; diff --git a/src/consts.h b/src/consts.h index 239d58e..dcfa599 100644 --- a/src/consts.h +++ b/src/consts.h @@ -62,13 +62,15 @@ struct ColorStop { Color3 color; }; -// factor for the opacity function +// factor for the gradient opacity function extern __device__ float d_opacityK; // sigmoid function variables extern __device__ float d_sigmoidShift; extern __device__ float d_sigmoidExp; // combo box index extern __device__ int d_tfComboSelected; +// constant opacity option +extern __device__ float d_opacityConst; const int lenStopsPythonLike = 5; const int lenStopsGrayscale = 2; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 8b9b2de..03f3a04 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -30,6 +30,7 @@ Widget::Widget(GLFWwindow* window) { this->sigmoidShift = 0.5f; this->sigmoidExp = -250.0f; this->tfComboSelected = 0; + this->opacityConst = 100; }; // REFACTOR: should probably not have all the logic in one function; something like a list of ImplementedWidgets with each a Render() function (a la interface) would be better. @@ -52,6 +53,7 @@ void Widget::tick(double fps) { ImGui::DragInt("Gradient exp. (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); ImGui::DragFloat("sigmoidShift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); ImGui::InputFloat("sigmoidExp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); + ImGui::DragInt("Opacity constant (log [1e-5, 1])", &this->opacityConst, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); // the items[] contains the entries for the combobox. The selected index is stored as an int on this->tfComboSelected // the default entry is set in the constructor, so if you want that to be a specific entry just change it @@ -118,6 +120,9 @@ void Widget::copyToDevice() { cudaMemcpyToSymbol(&d_sigmoidShift, &this->sigmoidShift, sizeof(float)); cudaMemcpyToSymbol(&d_sigmoidExp, &this->sigmoidExp, sizeof(float)); cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(float)); + + this->opacityConstReal = std::pow(10.0f, (-5 + 0.05 * this->opacityConst)); + cudaMemcpyToSymbol(&d_opacityConst, &this->opacityConstReal, sizeof(float)); } Widget::~Widget() { diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index 52727b3..c2fe991 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -23,6 +23,8 @@ public: float opacityKReal; float sigmoidShift; float sigmoidExp; + int opacityConst; + float opacityConstReal; ImGuiIO io; diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index a360602..0cb3271 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -62,7 +62,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 break; case 2: - alpha = 0.1f; + alpha = d_opacityConst; break; default: From 08e3da320af5a94ffed78501f3c88e191b2e10ac Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:43:23 +0100 Subject: [PATCH 10/22] Added notes for later --- notes.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 notes.md diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..484e789 --- /dev/null +++ b/notes.md @@ -0,0 +1,2 @@ +# Notes to self (probably consider for report TODO: Delete this later probably) +- Temp. normalized with zero at Celsius is essentially all blue, so it's not very useful. \ No newline at end of file From 33365a26a762b62fca9e6e2bcb975110a773f281 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:43:39 +0100 Subject: [PATCH 11/22] That note turned out to be wrong tho --- notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes.md b/notes.md index 484e789..f08445b 100644 --- a/notes.md +++ b/notes.md @@ -1,2 +1,2 @@ # Notes to self (probably consider for report TODO: Delete this later probably) -- Temp. normalized with zero at Celsius is essentially all blue, so it's not very useful. \ No newline at end of file +- \ No newline at end of file From 4b95bb728dfa69af185c3c24422e4737b3e7b1dc Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:44:16 +0100 Subject: [PATCH 12/22] Implemented picker for color map --- src/consts.cu | 1 + src/consts.h | 1 + src/gui/input/Widget.cpp | 19 ++++++++++++++++++- src/gui/input/Widget.h | 1 + src/illumination/transferFunction.cu | 28 +++++++++++++++++++++++----- 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/consts.cu b/src/consts.cu index fc9d1b9..ed48441 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -52,4 +52,5 @@ __device__ float d_opacityK; __device__ float d_sigmoidShift; __device__ float d_sigmoidExp; __device__ int d_tfComboSelected; +__device__ int d_tfComboSelectedColor; __device__ float d_opacityConst; diff --git a/src/consts.h b/src/consts.h index dcfa599..7d739a3 100644 --- a/src/consts.h +++ b/src/consts.h @@ -69,6 +69,7 @@ extern __device__ float d_sigmoidShift; extern __device__ float d_sigmoidExp; // combo box index extern __device__ int d_tfComboSelected; +extern __device__ int d_tfComboSelectedColor; // constant opacity option extern __device__ float d_opacityConst; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 03f3a04..1dfd3ef 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -71,6 +71,21 @@ void Widget::tick(double fps) { } ImGui::EndCombo(); } + + // Same comments as above apply + const char* items2[] = {"Python-like", "BPR", "Greyscale", "..."}; + if (ImGui::BeginCombo("ComboBox for color map", items2[this->tfComboSelectedColor])) + { + for (int n = 0; n < IM_ARRAYSIZE(items2); n++) + { + const bool is_selected = (this->tfComboSelectedColor == n); + if (ImGui::Selectable(items2[n], is_selected)) + this->tfComboSelectedColor = n; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } ImGui::End(); ImGui::Begin("Light Controls"); @@ -119,10 +134,12 @@ void Widget::copyToDevice() { cudaMemcpyToSymbol(&d_sigmoidShift, &this->sigmoidShift, sizeof(float)); cudaMemcpyToSymbol(&d_sigmoidExp, &this->sigmoidExp, sizeof(float)); - cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(float)); + cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(int)); this->opacityConstReal = std::pow(10.0f, (-5 + 0.05 * this->opacityConst)); cudaMemcpyToSymbol(&d_opacityConst, &this->opacityConstReal, sizeof(float)); + + cudaMemcpyToSymbol(&d_tfComboSelectedColor, &this->tfComboSelectedColor, sizeof(int)); } Widget::~Widget() { diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index c2fe991..ac2cbcd 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -19,6 +19,7 @@ public: char* fps; int tfComboSelected; + int tfComboSelectedColor; int opacityK; float opacityKReal; float sigmoidShift; diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 0cb3271..060548a 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -40,17 +40,35 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 // --------------------------- Sample the volume --------------------------- // TODO: Somehow pick if to use temp of speed normalization ... or pass extremas as params. - float normDensity = (density - MIN_TEMP) / (MAX_TEMP - MIN_TEMP); + // float normDensity = (density - MIN_TEMP) / (MAX_TEMP - MIN_TEMP); + float normDensity = (density - 273) / (MAX_TEMP - MIN_TEMP)+16.f/21.f; // Make zero match Celsius zero + // float normDensity = (density - MIN_SPEED) / (MAX_SPEED - MIN_SPEED); normDensity = clamp(normDensity, 0.0f, 1.0f); // --------------------------- Map density to color --------------------------- - // TODO: Add a way to pick stops here - Color3 baseColor = colorMap(normDensity, d_stopsPythonLike, lenStopsPythonLike); + // Pick color map + Color3 baseColor; + switch (d_tfComboSelectedColor) { + case 0: + baseColor = colorMap(normDensity, d_stopsPythonLike, lenStopsPythonLike); + break; + + case 1: + baseColor = colorMap(normDensity, d_stopsBluePurleRed, lenStopsBluePurpleRed); + break; - // TODO: This is a Gui select element - // TODO: Add a way to pick different function for alpha + case 2: + baseColor = colorMap(normDensity, d_stopsGrayscale, lenStopsGrayscale); + break; + + default: + baseColor = colorMap(normDensity, d_stopsPythonLike, lenStopsPythonLike); + break; + } + + // Pick opacity function float alpha; switch (d_tfComboSelected) { case 0: From acc170508139d6c2324be6b5581f66d2e275371b Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:45:06 +0100 Subject: [PATCH 13/22] Fixed curly braces for no particular reason --- src/gui/input/Widget.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 1dfd3ef..6762b2b 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -59,10 +59,8 @@ void Widget::tick(double fps) { // the default entry is set in the constructor, so if you want that to be a specific entry just change it // whatever value is selected here is available on the gpu as d_tfComboSelected. const char* items[] = {"Opacity - gradient", "Opacity - sigmoid", "Opacity - constant", "..."}; - if (ImGui::BeginCombo("ComboBox for transferFunction", items[this->tfComboSelected])) - { - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { + if (ImGui::BeginCombo("ComboBox for transferFunction", items[this->tfComboSelected])) { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) { const bool is_selected = (this->tfComboSelected == n); if (ImGui::Selectable(items[n], is_selected)) this->tfComboSelected = n; @@ -74,10 +72,8 @@ void Widget::tick(double fps) { // Same comments as above apply const char* items2[] = {"Python-like", "BPR", "Greyscale", "..."}; - if (ImGui::BeginCombo("ComboBox for color map", items2[this->tfComboSelectedColor])) - { - for (int n = 0; n < IM_ARRAYSIZE(items2); n++) - { + if (ImGui::BeginCombo("ComboBox for color map", items2[this->tfComboSelectedColor])) { + for (int n = 0; n < IM_ARRAYSIZE(items2); n++) { const bool is_selected = (this->tfComboSelectedColor == n); if (ImGui::Selectable(items2[n], is_selected)) this->tfComboSelectedColor = n; From fca8ea3e841ec425c02d88cf030ed4da25208d4f Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:46:27 +0100 Subject: [PATCH 14/22] Thought of a fair note after all --- notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes.md b/notes.md index f08445b..1004d49 100644 --- a/notes.md +++ b/notes.md @@ -1,2 +1,2 @@ # Notes to self (probably consider for report TODO: Delete this later probably) -- \ No newline at end of file +- Temp. "zero" is at celsius 0, but the interval of values of temps. is not symmetric so technically the color distrubution is skewed -> Maybe discuss this in the report. \ No newline at end of file From f11eff0e9667bce3e77aff9bcad188633b13902c Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:53:50 +0100 Subject: [PATCH 15/22] Added alpha accum gui param --- src/consts.cu | 1 + src/consts.h | 4 +++- src/gui/input/Widget.cpp | 3 +++ src/gui/input/Widget.h | 1 + src/illumination/Raycaster.cu | 2 +- 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/consts.cu b/src/consts.cu index ed48441..3e3b336 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -51,6 +51,7 @@ void copyConstantsToDevice() { __device__ float d_opacityK; __device__ float d_sigmoidShift; __device__ float d_sigmoidExp; +__device__ float d_alphaAcumLimit; __device__ int d_tfComboSelected; __device__ int d_tfComboSelectedColor; __device__ float d_opacityConst; diff --git a/src/consts.h b/src/consts.h index 7d739a3..93b04f2 100644 --- a/src/consts.h +++ b/src/consts.h @@ -32,7 +32,7 @@ const float MAX_SPEED = 14.0f; // --------------------------- Raycasting Constants --------------------------- const int SAMPLES_PER_PIXEL = 4; -const float alphaAcumLimit = 0.4f; // TODO: Atm, this only works with sigmoid +// const float alphaAcumLimit = 0.4f; // TODO: Atm, this only works with sigmoid const float minAllowedDensity = 0.001f; const float stepSize = 0.02f; @@ -67,6 +67,8 @@ extern __device__ float d_opacityK; // sigmoid function variables extern __device__ float d_sigmoidShift; extern __device__ float d_sigmoidExp; +// alpha accumulation limit +extern __device__ float d_alphaAcumLimit; // combo box index extern __device__ int d_tfComboSelected; extern __device__ int d_tfComboSelectedColor; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 6762b2b..a49a50c 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -29,6 +29,7 @@ Widget::Widget(GLFWwindow* window) { this->opacityK = 0; this->sigmoidShift = 0.5f; this->sigmoidExp = -250.0f; + this->alphaAcumLimit = 0.4f; this->tfComboSelected = 0; this->opacityConst = 100; }; @@ -53,6 +54,7 @@ void Widget::tick(double fps) { ImGui::DragInt("Gradient exp. (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); ImGui::DragFloat("sigmoidShift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); ImGui::InputFloat("sigmoidExp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); + ImGui::DragFloat("Alpha accumulation limit", &this->alphaAcumLimit, 0.01f, 0.0f, 1.0f, "%.2f"); ImGui::DragInt("Opacity constant (log [1e-5, 1])", &this->opacityConst, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); // the items[] contains the entries for the combobox. The selected index is stored as an int on this->tfComboSelected @@ -130,6 +132,7 @@ void Widget::copyToDevice() { cudaMemcpyToSymbol(&d_sigmoidShift, &this->sigmoidShift, sizeof(float)); cudaMemcpyToSymbol(&d_sigmoidExp, &this->sigmoidExp, sizeof(float)); + cudaMemcpyToSymbol(&d_alphaAcumLimit, &this->alphaAcumLimit, sizeof(float)); cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(int)); this->opacityConstReal = std::pow(10.0f, (-5 + 0.05 * this->opacityConst)); diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index ac2cbcd..73f5cc6 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -24,6 +24,7 @@ public: float opacityKReal; float sigmoidShift; float sigmoidExp; + float alphaAcumLimit; int opacityConst; float opacityConstReal; diff --git a/src/illumination/Raycaster.cu b/src/illumination/Raycaster.cu index ba72985..9e6db0d 100644 --- a/src/illumination/Raycaster.cu +++ b/src/illumination/Raycaster.cu @@ -84,7 +84,7 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const float alphaAccum = 0.0f; float t = tNear; // Front to back - while (t < tFar && alphaAccum < alphaAcumLimit) { + while (t < tFar && alphaAccum < d_alphaAcumLimit) { Point3 pos = d_cameraPos + rayDir * t; // Convert to volume indices From 91c9aa193c10c7994b47ce8e19dad50e4277905e Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 19:55:16 +0100 Subject: [PATCH 16/22] Made transfer function gui names shorter --- src/gui/input/Widget.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index a49a50c..1ad2e2c 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -51,17 +51,17 @@ void Widget::tick(double fps) { float min = -1, max = 1; ImGui::Begin("Transfer Function Controls"); - ImGui::DragInt("Gradient exp. (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); - ImGui::DragFloat("sigmoidShift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); - ImGui::InputFloat("sigmoidExp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); - ImGui::DragFloat("Alpha accumulation limit", &this->alphaAcumLimit, 0.01f, 0.0f, 1.0f, "%.2f"); - ImGui::DragInt("Opacity constant (log [1e-5, 1])", &this->opacityConst, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragInt("Grad. exp. (log [1e-10, 1])", &this->opacityK, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragFloat("Sig. shift", &this->sigmoidShift, 0.01f, 0.0f, 1.0f, "%.2f"); + ImGui::InputFloat("Sig. sxp", &this->sigmoidExp, 10.0f, 100.0f, "%.0f"); + ImGui::DragFloat("Alpha accum. limit", &this->alphaAcumLimit, 0.01f, 0.0f, 1.0f, "%.2f"); + ImGui::DragInt("Opacity const. (log [1e-5, 1])", &this->opacityConst, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); // the items[] contains the entries for the combobox. The selected index is stored as an int on this->tfComboSelected // the default entry is set in the constructor, so if you want that to be a specific entry just change it // whatever value is selected here is available on the gpu as d_tfComboSelected. const char* items[] = {"Opacity - gradient", "Opacity - sigmoid", "Opacity - constant", "..."}; - if (ImGui::BeginCombo("ComboBox for transferFunction", items[this->tfComboSelected])) { + if (ImGui::BeginCombo("Transfer function", items[this->tfComboSelected])) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { const bool is_selected = (this->tfComboSelected == n); if (ImGui::Selectable(items[n], is_selected)) @@ -74,7 +74,7 @@ void Widget::tick(double fps) { // Same comments as above apply const char* items2[] = {"Python-like", "BPR", "Greyscale", "..."}; - if (ImGui::BeginCombo("ComboBox for color map", items2[this->tfComboSelectedColor])) { + if (ImGui::BeginCombo("Color map", items2[this->tfComboSelectedColor])) { for (int n = 0; n < IM_ARRAYSIZE(items2); n++) { const bool is_selected = (this->tfComboSelectedColor == n); if (ImGui::Selectable(items2[n], is_selected)) From 2c6594244e90d9af297ca2c7402e4a4d9c956804 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 20:03:39 +0100 Subject: [PATCH 17/22] Added samples per pixel gui param --- src/consts.cu | 3 +++ src/consts.h | 5 ++--- src/gui/input/Widget.cpp | 4 ++++ src/gui/input/Widget.h | 1 + src/illumination/Raycaster.cu | 22 +++++++++++----------- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/consts.cu b/src/consts.cu index 3e3b336..63f6242 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -55,3 +55,6 @@ __device__ float d_alphaAcumLimit; __device__ int d_tfComboSelected; __device__ int d_tfComboSelectedColor; __device__ float d_opacityConst; + +// ----------------------- Raycasting ----------------------- +__device__ int d_samplesPerPixel; diff --git a/src/consts.h b/src/consts.h index 93b04f2..b43dcd0 100644 --- a/src/consts.h +++ b/src/consts.h @@ -30,9 +30,6 @@ const float MAX_SPEED = 14.0f; // --------------------------- Raycasting Constants --------------------------- -const int SAMPLES_PER_PIXEL = 4; - -// const float alphaAcumLimit = 0.4f; // TODO: Atm, this only works with sigmoid const float minAllowedDensity = 0.001f; const float stepSize = 0.02f; @@ -74,6 +71,8 @@ extern __device__ int d_tfComboSelected; extern __device__ int d_tfComboSelectedColor; // constant opacity option extern __device__ float d_opacityConst; +// samples per pixel +extern __device__ int d_samplesPerPixel; const int lenStopsPythonLike = 5; const int lenStopsGrayscale = 2; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 1ad2e2c..5884138 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -25,6 +25,7 @@ Widget::Widget(GLFWwindow* window) { this->fps = (char*)malloc(512*sizeof(char)); this->paused = true; this->renderOnce = false; + this->samplesPerPixel = 1; this->opacityK = 0; this->sigmoidShift = 0.5f; @@ -101,6 +102,7 @@ void Widget::tick(double fps) { } sprintf(this->fps, "%.3f fps\n", fps); ImGui::Text(this->fps); + ImGui::DragInt("Samples per pixel", &this->samplesPerPixel, 1, 1, 16, "%d", ImGuiSliderFlags_AlwaysClamp); ImGui::End(); ImGui::Begin("Camera Controls"); @@ -125,6 +127,8 @@ 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_samplesPerPixel, &this->samplesPerPixel, sizeof(int)); // cudaMemcpyToSymbol(&d_opacityK, &this->opacityK, sizeof(float)); this->opacityKReal = std::pow(10.0f, (-10 + 0.1 * this->opacityK)); diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index 73f5cc6..0fb1d28 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -17,6 +17,7 @@ public: bool paused; bool renderOnce; char* fps; + int samplesPerPixel; int tfComboSelected; int tfComboSelectedColor; diff --git a/src/illumination/Raycaster.cu b/src/illumination/Raycaster.cu index 9e6db0d..beb98d9 100644 --- a/src/illumination/Raycaster.cu +++ b/src/illumination/Raycaster.cu @@ -20,14 +20,14 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const float accumR = 0.0f; float accumG = 0.0f; float accumB = 0.0f; - float accumA = 1.0f * (float)SAMPLES_PER_PIXEL; + float accumA = 1.0f * (float)d_samplesPerPixel; // Initialize random state for ray scattering curandState randState; curand_init(1234, px + py * width, 0, &randState); // Multiple samples per pixel - for (int s = 0; s < SAMPLES_PER_PIXEL; s++) { + for (int s = 0; s < d_samplesPerPixel; s++) { // Map to [-1, 1] float jitterU = (curand_uniform(&randState) - 0.5f) / width; float jitterV = (curand_uniform(&randState) - 0.5f) / height; @@ -71,11 +71,11 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const intersectAxis(d_cameraPos.z, rayDir.z, 0.0f, (float)VOLUME_DEPTH); if (tNear > tFar) { - // No intersection -> Set to brackground color (multiply by SAMPLES_PER_PIXEL because we divide by it later) - accumR = d_backgroundColor.x * (float)SAMPLES_PER_PIXEL; - accumG = d_backgroundColor.y * (float)SAMPLES_PER_PIXEL; - accumB = d_backgroundColor.z * (float)SAMPLES_PER_PIXEL; - accumA = 1.0f * (float)SAMPLES_PER_PIXEL; + // No intersection -> Set to brackground color (multiply by d_samplesPerPixel because we divide by it later) + accumR = d_backgroundColor.x * (float)d_samplesPerPixel; + accumG = d_backgroundColor.y * (float)d_samplesPerPixel; + accumB = d_backgroundColor.z * (float)d_samplesPerPixel; + accumA = 1.0f * (float)d_samplesPerPixel; } else { if (tNear < 0.0f) tNear = 0.0f; @@ -130,10 +130,10 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const // Average samples - accumR /= (float)SAMPLES_PER_PIXEL; - accumG /= (float)SAMPLES_PER_PIXEL; - accumB /= (float)SAMPLES_PER_PIXEL; - accumA /= (float)SAMPLES_PER_PIXEL; + accumR /= (float)d_samplesPerPixel; + accumG /= (float)d_samplesPerPixel; + accumB /= (float)d_samplesPerPixel; + accumA /= (float)d_samplesPerPixel; // Final colour framebuffer.writePixel(px, py, accumR, accumG, accumB, accumA); From 98055642bd035fd6b7cfea8624d6122452ee861b Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 20:04:43 +0100 Subject: [PATCH 18/22] Commented out some debug code --- src/main.cu | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main.cu b/src/main.cu index 6127861..aec5022 100644 --- a/src/main.cu +++ b/src/main.cu @@ -79,25 +79,25 @@ int main() { } } - // Store the half-way up slice data into a file TODO: Remove this debug - std::ofstream myfile; - myfile.open("halfwayup.txt"); - for (int i = 0; i < VOLUME_WIDTH; i++) { - for (int j = 0; j < VOLUME_HEIGHT; j++) { - myfile << hostVolume[i + j*VOLUME_WIDTH + VOLUME_DEPTH/2*VOLUME_WIDTH*VOLUME_HEIGHT] << " "; - } - myfile << std::endl; - } - myfile.close(); + // // Store the half-way up slice data into a file TODO: Remove this debug + // std::ofstream myfile; + // myfile.open("halfwayup.txt"); + // for (int i = 0; i < VOLUME_WIDTH; i++) { + // for (int j = 0; j < VOLUME_HEIGHT; j++) { + // myfile << hostVolume[i + j*VOLUME_WIDTH + VOLUME_DEPTH/2*VOLUME_WIDTH*VOLUME_HEIGHT] << " "; + // } + // myfile << std::endl; + // } + // myfile.close(); - // Print min, max, avg., and median values TODO: Remove this debug - float minVal = *std::min_element(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH, [](float a, float b) { - if (a <= epsilon) return false; - if (b <= epsilon) return true; - return a < b; - }); - float maxVal = *std::max_element(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH); - std::cout << "minVal: " << minVal << " maxVal: " << maxVal << std::endl; + // // Print min, max, avg., and median values TODO: Remove this debug + // float minVal = *std::min_element(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH, [](float a, float b) { + // if (a <= epsilon) return false; + // if (b <= epsilon) return true; + // return a < b; + // }); + // float maxVal = *std::max_element(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH); + // std::cout << "minVal: " << minVal << " maxVal: " << maxVal << std::endl; // // print min, max, avg., and median values <--- the code actually does not work when this snippet is enabled so probably TODO: Delete this later // std::sort(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH); // float sum = std::accumulate(hostVolume, hostVolume + VOLUME_WIDTH * VOLUME_HEIGHT * VOLUME_DEPTH, 0.0f); From c26462165a4055f61a48fd63b4c97a482747a702 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 20:05:36 +0100 Subject: [PATCH 19/22] Removed old debug code from back when the pause button was not a thing --- src/gui/MainWindow.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index dd15872..39cc41d 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -8,16 +8,6 @@ #include "input/Widget.h" -// TODO: Delete -void saveImage2(const char* filename, unsigned char* framebuffer, int width, int height) { // TODO: Figure out a better way to do this - std::ofstream imageFile(filename, std::ios::out | std::ios::binary); - imageFile << "P6\n" << width << " " << height << "\n255\n"; - for (int i = 0; i < width * height * 3; i++) { - imageFile << framebuffer[i]; - } - imageFile.close(); -} - Window::Window(unsigned int w, unsigned int h) { this->w = w; this->h = h; @@ -69,14 +59,6 @@ int Window::init(float* data) { while (!glfwWindowShouldClose(window)) { Window::tick(); } - // TODO: Remove this, this was just for ray-casting debug - // Window::tick(); - // Window::tick(); - // // Save the image - // unsigned char* pixels = new unsigned char[this->w * this->h * 3]; - // glReadPixels(0, 0, this->w, this->h, GL_RGB, GL_UNSIGNED_BYTE, pixels); - // saveImage2("output.ppm", pixels, this->w, this->h); - // delete[] pixels; Window::free(data); return 0; From b4c7d3a7a5f611d8ba58a332572f607f5778c17c Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 20:18:25 +0100 Subject: [PATCH 20/22] Removed debug code --- src/linalg/mat.cu | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/linalg/mat.cu b/src/linalg/mat.cu index 788867d..11bc87d 100644 --- a/src/linalg/mat.cu +++ b/src/linalg/mat.cu @@ -72,14 +72,6 @@ __device__ Vec3 computeGradient(float* volumeData, const int volW, const int vol float dfdz = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz + hz) - sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz - hz)) / (2.0f * hz); - // // DEBUG (TODO: Delete) - Back to nearest - // float dfdx = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx + 1), (int)roundf(fy), (int)roundf(fz)) - - // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx - 1), (int)roundf(fy), (int)roundf(fz))) / (2.0f * hx); - // float dfdy = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy + 1), (int)roundf(fz)) - - // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy - 1), (int)roundf(fz))) / (2.0f * hy); - // float dfdz = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz + 1)) - - // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz - 1))) / (2.0f * hz); - return Vec3::init(dfdx, dfdy, dfdz); }; From d5df4ea188261abe8770acf4e8dec4681ee28b71 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 20:31:40 +0100 Subject: [PATCH 21/22] Added silhoutte gui control --- src/consts.cu | 2 ++ src/consts.h | 3 +++ src/gui/input/Widget.cpp | 7 +++++++ src/gui/input/Widget.h | 2 ++ src/illumination/transferFunction.cu | 2 +- 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/consts.cu b/src/consts.cu index 63f6242..30afa91 100644 --- a/src/consts.cu +++ b/src/consts.cu @@ -55,6 +55,8 @@ __device__ float d_alphaAcumLimit; __device__ int d_tfComboSelected; __device__ int d_tfComboSelectedColor; __device__ float d_opacityConst; +__device__ bool d_showSilhouettes; +__device__ float d_silhouettesThreshold; // ----------------------- Raycasting ----------------------- __device__ int d_samplesPerPixel; diff --git a/src/consts.h b/src/consts.h index b43dcd0..ca71393 100644 --- a/src/consts.h +++ b/src/consts.h @@ -73,6 +73,9 @@ extern __device__ int d_tfComboSelectedColor; extern __device__ float d_opacityConst; // samples per pixel extern __device__ int d_samplesPerPixel; +// Silhouettes +extern __device__ bool d_showSilhouettes; +extern __device__ float d_silhouettesThreshold; const int lenStopsPythonLike = 5; const int lenStopsGrayscale = 2; diff --git a/src/gui/input/Widget.cpp b/src/gui/input/Widget.cpp index 5884138..aa35119 100644 --- a/src/gui/input/Widget.cpp +++ b/src/gui/input/Widget.cpp @@ -33,6 +33,8 @@ Widget::Widget(GLFWwindow* window) { this->alphaAcumLimit = 0.4f; this->tfComboSelected = 0; this->opacityConst = 100; + this->showSilhouettes = true; + this->silhouettesThreshold = 0.02f; }; // REFACTOR: should probably not have all the logic in one function; something like a list of ImplementedWidgets with each a Render() function (a la interface) would be better. @@ -85,6 +87,9 @@ void Widget::tick(double fps) { } ImGui::EndCombo(); } + + if (ImGui::Button(this->showSilhouettes ? "Hide Silhouettes" : "Show Silhouettes")) this->showSilhouettes = !this->showSilhouettes; + ImGui::DragFloat("Silhouettes threshold", &this->silhouettesThreshold, 0.001f, 0.0f, 0.5f, "%.3f"); ImGui::End(); ImGui::Begin("Light Controls"); @@ -138,6 +143,8 @@ void Widget::copyToDevice() { cudaMemcpyToSymbol(&d_sigmoidExp, &this->sigmoidExp, sizeof(float)); cudaMemcpyToSymbol(&d_alphaAcumLimit, &this->alphaAcumLimit, sizeof(float)); cudaMemcpyToSymbol(&d_tfComboSelected, &this->tfComboSelected, sizeof(int)); + cudaMemcpyToSymbol(&d_showSilhouettes, &this->showSilhouettes, sizeof(bool)); + cudaMemcpyToSymbol(&d_silhouettesThreshold, &this->silhouettesThreshold, sizeof(float)); this->opacityConstReal = std::pow(10.0f, (-5 + 0.05 * this->opacityConst)); cudaMemcpyToSymbol(&d_opacityConst, &this->opacityConstReal, sizeof(float)); diff --git a/src/gui/input/Widget.h b/src/gui/input/Widget.h index 0fb1d28..99a1ef2 100644 --- a/src/gui/input/Widget.h +++ b/src/gui/input/Widget.h @@ -28,6 +28,8 @@ public: float alphaAcumLimit; int opacityConst; float opacityConstReal; + bool showSilhouettes; + float silhouettesThreshold; ImGuiIO io; diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 060548a..36e845b 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -106,7 +106,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 // --------------------------- Silhouettes --------------------------- Vec3 N = grad.normalize(); - if (grad.length() > 0.2f && fabs(N.dot(viewDir)) < 0.02f) { + if (d_showSilhouettes && grad.length() > 0.2f && fabs(N.dot(viewDir)) < d_silhouettesThreshold) { result.x = 0.0f; result.y = 0.0f; result.z = 0.0f; From a3b6aab0c7f461993193df66ba015f2d4efd1994 Mon Sep 17 00:00:00 2001 From: Martin Opat Date: Wed, 15 Jan 2025 21:25:52 +0100 Subject: [PATCH 22/22] Wrapping up --- src/illumination/Raycaster.cu | 2 +- src/illumination/transferFunction.cu | 11 ++++++----- src/img/handler.h | 2 +- src/linalg/mat.cu | 10 +++++++++- src/linalg/vec.h | 2 +- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/illumination/Raycaster.cu b/src/illumination/Raycaster.cu index beb98d9..f66a9d9 100644 --- a/src/illumination/Raycaster.cu +++ b/src/illumination/Raycaster.cu @@ -92,7 +92,7 @@ __global__ void raycastKernel(float* volumeData, FrameBuffer framebuffer, const int iy = (int)roundf(pos.y); int iz = (int)roundf(pos.z); - // Sample (pick appropriate method based on volume size) TODO: Add a way to pick this in GUI + // Sample (pick appropriate method based on volume size) TODO: Consider adding a way to pick this in GUI (?) // float density = sampleVolumeNearest(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, ix, iy, iz); float density = sampleVolumeTrilinear(volumeData, VOLUME_WIDTH, VOLUME_HEIGHT, VOLUME_DEPTH, pos.x, pos.y, pos.z); diff --git a/src/illumination/transferFunction.cu b/src/illumination/transferFunction.cu index 36e845b..a6b9087 100644 --- a/src/illumination/transferFunction.cu +++ b/src/illumination/transferFunction.cu @@ -5,9 +5,10 @@ -__device__ float opacityFromGradient(const Vec3 &grad) { +__device__ float opacityFromGradient(const Vec3 &grad, const Vec3& rayDir) { float gradMag = grad.length(); - float alpha = 1.0f - expf(-d_opacityK * gradMag); // TODO: This parameter probably has the wrong scale + // float gradMag = grad.length()*(1-fabs(grad.normalize().dot(rayDir))); // Alternative, but not particularly better + float alpha = 1.0f - expf(-d_opacityK * gradMag); return alpha; } @@ -39,7 +40,7 @@ __device__ Color3 colorMap(float normalizedValues, const ColorStop stops[], int __device__ float4 transferFunction(float density, const Vec3& grad, const Point3& pos, const Vec3& rayDir) { // --------------------------- Sample the volume --------------------------- - // TODO: Somehow pick if to use temp of speed normalization ... or pass extremas as params. + // TODO: Somehow pick if to use temp of speed normalization ... or pass extremas as params. <-If we decide to visualize more than 1 type of data // float normDensity = (density - MIN_TEMP) / (MAX_TEMP - MIN_TEMP); float normDensity = (density - 273) / (MAX_TEMP - MIN_TEMP)+16.f/21.f; // Make zero match Celsius zero @@ -72,7 +73,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 float alpha; switch (d_tfComboSelected) { case 0: - alpha = opacityFromGradient(grad); + alpha = opacityFromGradient(grad, rayDir); break; case 1: @@ -110,7 +111,7 @@ __device__ float4 transferFunction(float density, const Vec3& grad, const Point3 result.x = 0.0f; result.y = 0.0f; result.z = 0.0f; - result.w = alpha; // TODO: Figure out what to do about silhouettes either only on top or not at all + result.w = alpha; } return result; diff --git a/src/img/handler.h b/src/img/handler.h index 9fe80f5..4b032a9 100644 --- a/src/img/handler.h +++ b/src/img/handler.h @@ -3,7 +3,7 @@ #include -void saveImage(const char* filename, unsigned char* framebuffer, int width, int height) { // TODO: Figure out a better way to do this +void saveImage(const char* filename, unsigned char* framebuffer, int width, int height) { std::ofstream imageFile(filename, std::ios::out | std::ios::binary); imageFile << "P6\n" << width << " " << height << "\n255\n"; for (int i = 0; i < width * height * 3; i++) { diff --git a/src/linalg/mat.cu b/src/linalg/mat.cu index 11bc87d..7fbf8a5 100644 --- a/src/linalg/mat.cu +++ b/src/linalg/mat.cu @@ -72,6 +72,14 @@ __device__ Vec3 computeGradient(float* volumeData, const int volW, const int vol float dfdz = (sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz + hz) - sampleVolumeTrilinear(volumeData, volW, volH, volD, fx, fy, fz - hz)) / (2.0f * hz); + // // DEBUG (TODO: Delete) - Back to nearest + // float dfdx = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx + 1), (int)roundf(fy), (int)roundf(fz)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx - 1), (int)roundf(fy), (int)roundf(fz))) / (2.0f * hx); + // float dfdy = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy + 1), (int)roundf(fz)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy - 1), (int)roundf(fz))) / (2.0f * hy); + // float dfdz = (sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz + 1)) - + // sampleVolumeNearest(volumeData, volW, volH, volD, (int)roundf(fx), (int)roundf(fy), (int)roundf(fz - 1))) / (2.0f * hz); + return Vec3::init(dfdx, dfdy, dfdz); }; @@ -84,7 +92,7 @@ __device__ unsigned int packUnorm4x8(float r, float g, float b, float a) { float len = sqrtf(r*r + g*g + b*b + a*a); - // This is a Vec4 but i can't be bothered to make that its own struct/class; FIXME: maybe do that if we need to? + // This is a Vec4 but i can't be bothered to make that its own struct/class; FIXME: maybe do that if we need to? From Martin: We could use a Vec4 for rgba too, but I don't feel like it either u.in[0] = round(r/len * 255.0f); u.in[1] = round(g/len * 255.0f); u.in[2] = round(b/len * 255.0f); diff --git a/src/linalg/vec.h b/src/linalg/vec.h index 281709a..a243cb9 100644 --- a/src/linalg/vec.h +++ b/src/linalg/vec.h @@ -3,7 +3,7 @@ #include #include -struct Vec3 { // TODO: Maybe make this into a class ... maybe +struct Vec3 { double x, y, z; static __host__ __device__ Vec3 init(double x, double y, double z) {Vec3 v = {x, y, z}; return v;}