added transparency and LUT lookup
This commit is contained in:
49
TSE-RTS/Resources/DCMVizPresets/Preset1.json
Normal file
49
TSE-RTS/Resources/DCMVizPresets/Preset1.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"transparencyCount": 4,
|
||||||
|
"transparency": [
|
||||||
|
{
|
||||||
|
"index": 0.3114,
|
||||||
|
"transpValue": 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.3233,
|
||||||
|
"transpValue": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.5431,
|
||||||
|
"transpValue": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.5675,
|
||||||
|
"transpValue": 0.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"colorCount": 6,
|
||||||
|
"colors": [
|
||||||
|
{
|
||||||
|
"index": 0.0000,
|
||||||
|
"color": { "x": 0.00, "y": 0.00, "z": 0.00 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.2256,
|
||||||
|
"color": { "x": 0.10, "y": 0.08, "z": 0.08 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.2598,
|
||||||
|
"color": { "x": 0.30, "y": 0.22, "z": 0.20 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.3233,
|
||||||
|
"color": { "x": 0.92, "y": 0.88, "z": 0.78 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.4454,
|
||||||
|
"color": { "x": 0.96, "y": 0.92, "z": 0.84 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 0.5431,
|
||||||
|
"color": { "x": 1.00, "y": 0.98, "z": 0.92 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
283
TSE-RTS/src/elements/visualizationData.cpp
Normal file
283
TSE-RTS/src/elements/visualizationData.cpp
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
#include "visualizationData.hpp"
|
||||||
|
#include "json.hpp"
|
||||||
|
#include "utils/JsonExports.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr int LUT_WIDTH = 256;
|
||||||
|
constexpr int LUT_HEIGHT = 256;
|
||||||
|
constexpr int LUT_PIXEL_COUNT = LUT_WIDTH * LUT_HEIGHT;
|
||||||
|
constexpr float LUT_INV_MAX_INDEX = 1.0f / static_cast<float>(LUT_PIXEL_COUNT - 1);
|
||||||
|
|
||||||
|
inline float Clamp01(const float value)
|
||||||
|
{
|
||||||
|
return std::min(1.0f, std::max(0.0f, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Lerp(const float a, const float b, const float t)
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualizationData VisualizationData::LoadVisualizationSetting(string path)
|
||||||
|
{
|
||||||
|
VisualizationData dataOut{};
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
const fs::path jsonPath = fs::absolute(path);
|
||||||
|
if(!fs::exists(jsonPath) || !fs::is_regular_file(jsonPath))
|
||||||
|
{
|
||||||
|
return dataOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream in(jsonPath, std::ios::in | std::ios::binary);
|
||||||
|
if(!in.is_open())
|
||||||
|
{
|
||||||
|
return dataOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json json = nlohmann::json::parse(in, nullptr, false);
|
||||||
|
if(json.is_discarded() || !json.is_object())
|
||||||
|
{
|
||||||
|
return dataOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto transpIt = json.find("transparency");
|
||||||
|
const auto colorsIt = json.find("colors");
|
||||||
|
|
||||||
|
const std::size_t transpArrayCount = (transpIt != json.end() && transpIt->is_array()) ? transpIt->size() : 0;
|
||||||
|
const std::size_t colorArrayCount = (colorsIt != json.end() && colorsIt->is_array()) ? colorsIt->size() : 0;
|
||||||
|
|
||||||
|
const std::size_t transpCount = std::min(json.value("transparencyCount", transpArrayCount), transpArrayCount);
|
||||||
|
const std::size_t colorCount = std::min(json.value("colorCount", colorArrayCount), colorArrayCount);
|
||||||
|
|
||||||
|
dataOut.transparencyCount = transpCount;
|
||||||
|
dataOut.colorCount = colorCount;
|
||||||
|
|
||||||
|
if(transpCount > 0)
|
||||||
|
{
|
||||||
|
dataOut.transparency = new TransparencyData[transpCount]();
|
||||||
|
for(std::size_t i = 0; i < transpCount; ++i)
|
||||||
|
{
|
||||||
|
const nlohmann::json& point = (*transpIt)[i];
|
||||||
|
dataOut.transparency[i].index = point.value("index", 0.0f);
|
||||||
|
dataOut.transparency[i].transpValue = point.value("transpValue", 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(colorCount > 0)
|
||||||
|
{
|
||||||
|
dataOut.colors = new ColorData[colorCount]();
|
||||||
|
for(std::size_t i = 0; i < colorCount; ++i)
|
||||||
|
{
|
||||||
|
const nlohmann::json& point = (*colorsIt)[i];
|
||||||
|
dataOut.colors[i].index = point.value("index", 0.0f);
|
||||||
|
const auto colorIt = point.find("color");
|
||||||
|
if(colorIt != point.end() && colorIt->is_object() &&
|
||||||
|
colorIt->contains("x") && colorIt->contains("y") && colorIt->contains("z"))
|
||||||
|
{
|
||||||
|
dataOut.colors[i].color = TSE::ImportVector3(*colorIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualizationData::FillLUTTexture(Texture& texture) const
|
||||||
|
{
|
||||||
|
if(static_cast<int>(texture.Width()) != LUT_WIDTH || static_cast<int>(texture.Height()) != LUT_HEIGHT)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TransparencyData> transparencyPoints;
|
||||||
|
std::vector<ColorData> colorPoints;
|
||||||
|
|
||||||
|
if(transparency != nullptr && transparencyCount > 0)
|
||||||
|
{
|
||||||
|
transparencyPoints.assign(transparency, transparency + transparencyCount);
|
||||||
|
std::sort(transparencyPoints.begin(), transparencyPoints.end(), [](const TransparencyData& a, const TransparencyData& b)
|
||||||
|
{
|
||||||
|
return a.index < b.index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(colors != nullptr && colorCount > 0)
|
||||||
|
{
|
||||||
|
colorPoints.assign(colors, colors + colorCount);
|
||||||
|
std::sort(colorPoints.begin(), colorPoints.end(), [](const ColorData& a, const ColorData& b)
|
||||||
|
{
|
||||||
|
return a.index < b.index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t transparencySegment = 0;
|
||||||
|
std::size_t colorSegment = 0;
|
||||||
|
|
||||||
|
if(texture.bpp() == 32)
|
||||||
|
{
|
||||||
|
byte* pixel = texture.GetImagePtr();
|
||||||
|
if(pixel == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < LUT_PIXEL_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const float value = static_cast<float>(i) * LUT_INV_MAX_INDEX;
|
||||||
|
|
||||||
|
float alpha = 1.0f;
|
||||||
|
if(!transparencyPoints.empty())
|
||||||
|
{
|
||||||
|
if(transparencyPoints.size() == 1 || value <= transparencyPoints.front().index)
|
||||||
|
{
|
||||||
|
alpha = transparencyPoints.front().transpValue;
|
||||||
|
}
|
||||||
|
else if(value >= transparencyPoints.back().index)
|
||||||
|
{
|
||||||
|
alpha = transparencyPoints.back().transpValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(transparencySegment + 1 < transparencyPoints.size() &&
|
||||||
|
value > transparencyPoints[transparencySegment + 1].index)
|
||||||
|
{
|
||||||
|
++transparencySegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransparencyData& p0 = transparencyPoints[transparencySegment];
|
||||||
|
const TransparencyData& p1 = transparencyPoints[transparencySegment + 1];
|
||||||
|
const float range = p1.index - p0.index;
|
||||||
|
const float t = (std::abs(range) > 1e-7f) ? Clamp01((value - p0.index) / range) : 0.0f;
|
||||||
|
alpha = Lerp(p0.transpValue, p1.transpValue, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = 0.0f;
|
||||||
|
float g = 0.0f;
|
||||||
|
float b = 0.0f;
|
||||||
|
if(!colorPoints.empty())
|
||||||
|
{
|
||||||
|
if(colorPoints.size() == 1 || value <= colorPoints.front().index)
|
||||||
|
{
|
||||||
|
r = colorPoints.front().color.x;
|
||||||
|
g = colorPoints.front().color.y;
|
||||||
|
b = colorPoints.front().color.z;
|
||||||
|
}
|
||||||
|
else if(value >= colorPoints.back().index)
|
||||||
|
{
|
||||||
|
r = colorPoints.back().color.x;
|
||||||
|
g = colorPoints.back().color.y;
|
||||||
|
b = colorPoints.back().color.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(colorSegment + 1 < colorPoints.size() &&
|
||||||
|
value > colorPoints[colorSegment + 1].index)
|
||||||
|
{
|
||||||
|
++colorSegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorData& p0 = colorPoints[colorSegment];
|
||||||
|
const ColorData& p1 = colorPoints[colorSegment + 1];
|
||||||
|
const float range = p1.index - p0.index;
|
||||||
|
const float t = (std::abs(range) > 1e-7f) ? Clamp01((value - p0.index) / range) : 0.0f;
|
||||||
|
|
||||||
|
r = Lerp(p0.color.x, p1.color.x, t);
|
||||||
|
g = Lerp(p0.color.y, p1.color.y, t);
|
||||||
|
b = Lerp(p0.color.z, p1.color.z, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pixel++ = static_cast<byte>(Clamp01(b) * 255.0f);
|
||||||
|
*pixel++ = static_cast<byte>(Clamp01(g) * 255.0f);
|
||||||
|
*pixel++ = static_cast<byte>(Clamp01(r) * 255.0f);
|
||||||
|
*pixel++ = static_cast<byte>(Clamp01(alpha) * 255.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture.Apply();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < LUT_PIXEL_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const float value = static_cast<float>(i) * LUT_INV_MAX_INDEX;
|
||||||
|
|
||||||
|
float alpha = 1.0f;
|
||||||
|
if(!transparencyPoints.empty())
|
||||||
|
{
|
||||||
|
if(transparencyPoints.size() == 1 || value <= transparencyPoints.front().index)
|
||||||
|
{
|
||||||
|
alpha = transparencyPoints.front().transpValue;
|
||||||
|
}
|
||||||
|
else if(value >= transparencyPoints.back().index)
|
||||||
|
{
|
||||||
|
alpha = transparencyPoints.back().transpValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(transparencySegment + 1 < transparencyPoints.size() &&
|
||||||
|
value > transparencyPoints[transparencySegment + 1].index)
|
||||||
|
{
|
||||||
|
++transparencySegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransparencyData& p0 = transparencyPoints[transparencySegment];
|
||||||
|
const TransparencyData& p1 = transparencyPoints[transparencySegment + 1];
|
||||||
|
const float range = p1.index - p0.index;
|
||||||
|
const float t = (std::abs(range) > 1e-7f) ? Clamp01((value - p0.index) / range) : 0.0f;
|
||||||
|
alpha = Lerp(p0.transpValue, p1.transpValue, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = 0.0f;
|
||||||
|
float g = 0.0f;
|
||||||
|
float b = 0.0f;
|
||||||
|
if(!colorPoints.empty())
|
||||||
|
{
|
||||||
|
if(colorPoints.size() == 1 || value <= colorPoints.front().index)
|
||||||
|
{
|
||||||
|
r = colorPoints.front().color.x;
|
||||||
|
g = colorPoints.front().color.y;
|
||||||
|
b = colorPoints.front().color.z;
|
||||||
|
}
|
||||||
|
else if(value >= colorPoints.back().index)
|
||||||
|
{
|
||||||
|
r = colorPoints.back().color.x;
|
||||||
|
g = colorPoints.back().color.y;
|
||||||
|
b = colorPoints.back().color.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(colorSegment + 1 < colorPoints.size() &&
|
||||||
|
value > colorPoints[colorSegment + 1].index)
|
||||||
|
{
|
||||||
|
++colorSegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorData& p0 = colorPoints[colorSegment];
|
||||||
|
const ColorData& p1 = colorPoints[colorSegment + 1];
|
||||||
|
const float range = p1.index - p0.index;
|
||||||
|
const float t = (std::abs(range) > 1e-7f) ? Clamp01((value - p0.index) / range) : 0.0f;
|
||||||
|
|
||||||
|
r = Lerp(p0.color.x, p1.color.x, t);
|
||||||
|
g = Lerp(p0.color.y, p1.color.y, t);
|
||||||
|
b = Lerp(p0.color.z, p1.color.z, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int x = (i & 255);
|
||||||
|
const int y = (i >> 8);
|
||||||
|
texture.SetPixelNoApply(x, y, Color(Clamp01(r), Clamp01(g), Clamp01(b), Clamp01(alpha)));
|
||||||
|
}
|
||||||
|
|
||||||
|
texture.Apply();
|
||||||
|
}
|
||||||
33
TSE-RTS/src/elements/visualizationData.hpp
Normal file
33
TSE-RTS/src/elements/visualizationData.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Types.hpp"
|
||||||
|
#include "Vector3.hpp"
|
||||||
|
#include "elements/Texture.hpp"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
using namespace TSE;
|
||||||
|
|
||||||
|
struct TransparencyData
|
||||||
|
{
|
||||||
|
float index;
|
||||||
|
float transpValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ColorData
|
||||||
|
{
|
||||||
|
Vector3 color;
|
||||||
|
float index;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VisualizationData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TransparencyData* transparency = nullptr;
|
||||||
|
ColorData* colors = nullptr;
|
||||||
|
std::size_t transparencyCount = 0;
|
||||||
|
std::size_t colorCount = 0;
|
||||||
|
|
||||||
|
static VisualizationData LoadVisualizationSetting(string path);
|
||||||
|
void FillLUTTexture(Texture& texture) const;
|
||||||
|
};
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "BehaviourScripts/CanvasScaler.hpp"
|
#include "BehaviourScripts/CanvasScaler.hpp"
|
||||||
#include "Random.hpp"
|
#include "Random.hpp"
|
||||||
#include "elements/VolumeTexture3D.hpp"
|
#include "elements/VolumeTexture3D.hpp"
|
||||||
|
#include "elements/visualizationData.hpp"
|
||||||
|
|
||||||
#define circleRadius 32
|
#define circleRadius 32
|
||||||
#define circleFallof 25
|
#define circleFallof 25
|
||||||
@@ -149,7 +150,11 @@ void game::setup(TSE::Scene* s, TSE::IWindow* wnd)
|
|||||||
|
|
||||||
s->AddLayer(&renderingLayer);
|
s->AddLayer(&renderingLayer);
|
||||||
|
|
||||||
float smallDicomDevider = 8.0f;
|
float smallDicomDevider = 16.0f;
|
||||||
|
|
||||||
|
Texture* lutTexture = new Texture(256, 256, 32);
|
||||||
|
VisualizationData data = VisualizationData::LoadVisualizationSetting("./DCMVizPresets/Preset1.json");
|
||||||
|
data.FillLUTTexture(*lutTexture);
|
||||||
|
|
||||||
VolumeTexture3D* dicom = new VolumeTexture3D("./DCM");
|
VolumeTexture3D* dicom = new VolumeTexture3D("./DCM");
|
||||||
Vector3 textureSize = {dicom->Width(), dicom->Height(), dicom->Depth()};
|
Vector3 textureSize = {dicom->Width(), dicom->Height(), dicom->Depth()};
|
||||||
@@ -170,11 +175,16 @@ void game::setup(TSE::Scene* s, TSE::IWindow* wnd)
|
|||||||
for(int sz = 0; sz < smallDicomDevider; sz++)
|
for(int sz = 0; sz < smallDicomDevider; sz++)
|
||||||
{
|
{
|
||||||
Color c;
|
Color c;
|
||||||
Vector3 pos = Vector3(x * 8 + sx, y * 8 + sy, z * 8 + sz);
|
Vector3 pos = Vector3(x * smallDicomDevider + sx, y * smallDicomDevider + sy, z * smallDicomDevider + sz);
|
||||||
if(pos.x < dicom->Width() && pos.y < dicom->Height() && pos.z < dicom->Depth())
|
if(pos.x < dicom->Width() && pos.y < dicom->Height() && pos.z < dicom->Depth())
|
||||||
{
|
{
|
||||||
dicom->GetPixel(pos, c);
|
dicom->GetPixel(pos, c);
|
||||||
value = fmax(value, c.r);
|
ushort index = (ushort)(c.r * 65536.0f);
|
||||||
|
int x = index & 0xFF;
|
||||||
|
int y = index >> 8;
|
||||||
|
|
||||||
|
lutTexture->GetPixel(x, y, c);
|
||||||
|
value = fmax(c.a, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,8 +195,6 @@ void game::setup(TSE::Scene* s, TSE::IWindow* wnd)
|
|||||||
}
|
}
|
||||||
dicomSmall->Apply();
|
dicomSmall->Apply();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//s->AddLayer(&characterLayer);
|
//s->AddLayer(&characterLayer);
|
||||||
|
|
||||||
Transformable* player = new Transformable("Player");
|
Transformable* player = new Transformable("Player");
|
||||||
@@ -256,12 +264,14 @@ void game::setup(TSE::Scene* s, TSE::IWindow* wnd)
|
|||||||
Material* canvasMat = new Material("canvasMat", ShaderRegistry::GetShader("DICOMShader"));
|
Material* canvasMat = new Material("canvasMat", ShaderRegistry::GetShader("DICOMShader"));
|
||||||
canvasMat->SetValue<float>("threshold", 0.4f);
|
canvasMat->SetValue<float>("threshold", 0.4f);
|
||||||
canvasMat->SetValue<float>("stepSize", 0.01f);
|
canvasMat->SetValue<float>("stepSize", 0.01f);
|
||||||
|
canvasMat->SetValue<float>("brickSize", smallDicomDevider);
|
||||||
canvasMat->SetValue<Vector3>("texSize", textureSize);
|
canvasMat->SetValue<Vector3>("texSize", textureSize);
|
||||||
canvasMat->SetValue<Vector3>("smallTexSize", smallTextureSize);
|
canvasMat->SetValue<Vector3>("smallTexSize", smallTextureSize);
|
||||||
Vector3 objectScale = Vector3(1,1,1);
|
Vector3 objectScale = Vector3(1,1,1);
|
||||||
canvasMat->SetValue<Vector3>("ObjectScale", objectScale);
|
canvasMat->SetValue<Vector3>("ObjectScale", objectScale);
|
||||||
canvasMat->SetValue<ITexture*>("DICOM", dicom);
|
canvasMat->SetValue<ITexture*>("DICOM", dicom);
|
||||||
canvasMat->SetValue<ITexture*>("DICOMsmall", dicomSmall);
|
canvasMat->SetValue<ITexture*>("DICOMsmall", dicomSmall);
|
||||||
|
canvasMat->SetValue<ITexture*>("LUT", lutTexture);
|
||||||
// canvasMat->SetValue<uint>("heightTextureID", rt->GetTextureId(1));
|
// canvasMat->SetValue<uint>("heightTextureID", rt->GetTextureId(1));
|
||||||
// canvasMat->SetValue<uint>("depthTextureID", rt->GetTextureId(2));
|
// canvasMat->SetValue<uint>("depthTextureID", rt->GetTextureId(2));
|
||||||
// canvasMat->SetValue<uint>("colorTexture2ID", rtProps->GetTextureId(0));
|
// canvasMat->SetValue<uint>("colorTexture2ID", rtProps->GetTextureId(0));
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ void DICOMShader::Init(float width, float height)
|
|||||||
instance->Enable();
|
instance->Enable();
|
||||||
instance->SetUniform("DICOMTexture", 0);
|
instance->SetUniform("DICOMTexture", 0);
|
||||||
instance->SetUniform("SmallDICOMTexture", 1);
|
instance->SetUniform("SmallDICOMTexture", 1);
|
||||||
|
instance->SetUniform("LUTTexture", 2);
|
||||||
instance->SetUniform("Threshold", 0.5f);
|
instance->SetUniform("Threshold", 0.5f);
|
||||||
instance->SetUniform("TexSize", &Vector3::zero);
|
instance->SetUniform("TexSize", &Vector3::zero);
|
||||||
instance->SetUniform("SmallTexSize", &Vector3::zero);
|
instance->SetUniform("SmallTexSize", &Vector3::zero);
|
||||||
@@ -68,13 +69,15 @@ void DICOMShader::OnFlush()
|
|||||||
glBindTexture(GL_TEXTURE_3D, DICOM->GetTextureId());
|
glBindTexture(GL_TEXTURE_3D, DICOM->GetTextureId());
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_3D, SmallDICOM->GetTextureId());
|
glBindTexture(GL_TEXTURE_3D, SmallDICOM->GetTextureId());
|
||||||
|
glActiveTexture(GL_TEXTURE2);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, LUT->GetTextureId());
|
||||||
SetUniform("Threshold", Threshold);
|
SetUniform("Threshold", Threshold);
|
||||||
if(stepSize < 0.001f) stepSize = 0.001f;
|
if(stepSize < 0.001f) stepSize = 0.001f;
|
||||||
SetUniform("StepSize", stepSize);
|
SetUniform("StepSize", stepSize);
|
||||||
SetUniform("TexSize", &size);
|
SetUniform("TexSize", &size);
|
||||||
SetUniform("SmallTexSize", &smallSize);
|
SetUniform("SmallTexSize", &smallSize);
|
||||||
SetUniform("ObjectScale", &scale);
|
SetUniform("ObjectScale", &scale);
|
||||||
SetUniform("BrickScale", 8.0f);
|
SetUniform("BrickScale", brickSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DICOMShader::OnDrawCall(int indexCount)
|
void DICOMShader::OnDrawCall(int indexCount)
|
||||||
@@ -93,12 +96,16 @@ void DICOMShader::OnSubmit(const TSE::Transformable &t, float *&target, TSE::Tra
|
|||||||
if(!r->GetMaterial()->HasValue("DICOMsmall")) return;
|
if(!r->GetMaterial()->HasValue("DICOMsmall")) return;
|
||||||
if(!r->GetMaterial()->HasValue("stepSize")) return;
|
if(!r->GetMaterial()->HasValue("stepSize")) return;
|
||||||
if(!r->GetMaterial()->HasValue("ObjectScale")) return;
|
if(!r->GetMaterial()->HasValue("ObjectScale")) return;
|
||||||
|
if(!r->GetMaterial()->HasValue("LUT")) return;
|
||||||
|
if(!r->GetMaterial()->HasValue("brickSize")) return;
|
||||||
Threshold = r->GetMaterial()->GetValue<float>("threshold");
|
Threshold = r->GetMaterial()->GetValue<float>("threshold");
|
||||||
stepSize = r->GetMaterial()->GetValue<float>("stepSize");
|
stepSize = r->GetMaterial()->GetValue<float>("stepSize");
|
||||||
|
brickSize = r->GetMaterial()->GetValue<float>("brickSize");
|
||||||
size = r->GetMaterial()->GetValue<Vector3>("texSize");
|
size = r->GetMaterial()->GetValue<Vector3>("texSize");
|
||||||
smallSize = r->GetMaterial()->GetValue<Vector3>("smallTexSize");
|
smallSize = r->GetMaterial()->GetValue<Vector3>("smallTexSize");
|
||||||
scale = r->GetMaterial()->GetValue<Vector3>("ObjectScale");
|
scale = r->GetMaterial()->GetValue<Vector3>("ObjectScale");
|
||||||
DICOM = r->GetMaterial()->GetValue<ITexture*>("DICOM");
|
DICOM = r->GetMaterial()->GetValue<ITexture*>("DICOM");
|
||||||
|
LUT = r->GetMaterial()->GetValue<ITexture*>("LUT");
|
||||||
SmallDICOM = r->GetMaterial()->GetValue<ITexture*>("DICOMsmall");
|
SmallDICOM = r->GetMaterial()->GetValue<ITexture*>("DICOMsmall");
|
||||||
|
|
||||||
const Vector3* verts = r->GetVertices();
|
const Vector3* verts = r->GetVertices();
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ private:
|
|||||||
static DICOMShader* instance;
|
static DICOMShader* instance;
|
||||||
TSE::ITexture* DICOM;
|
TSE::ITexture* DICOM;
|
||||||
TSE::ITexture* SmallDICOM;
|
TSE::ITexture* SmallDICOM;
|
||||||
|
TSE::ITexture* LUT;
|
||||||
TSE::Vector3 size;
|
TSE::Vector3 size;
|
||||||
TSE::Vector3 smallSize;
|
TSE::Vector3 smallSize;
|
||||||
TSE::Vector3 scale;
|
TSE::Vector3 scale;
|
||||||
float Threshold;
|
float Threshold;
|
||||||
float stepSize;
|
float stepSize;
|
||||||
|
float brickSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static DICOMShader* Instance();
|
static DICOMShader* Instance();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ inline const char* fragDICOM = R"(
|
|||||||
|
|
||||||
uniform sampler3D DICOMTexture;
|
uniform sampler3D DICOMTexture;
|
||||||
uniform sampler3D SmallDICOMTexture;
|
uniform sampler3D SmallDICOMTexture;
|
||||||
|
uniform sampler2D LUTTexture;
|
||||||
|
|
||||||
uniform vec3 CamPos;
|
uniform vec3 CamPos;
|
||||||
uniform vec3 CamRight;
|
uniform vec3 CamRight;
|
||||||
@@ -49,6 +50,8 @@ inline const char* fragDICOM = R"(
|
|||||||
|
|
||||||
uniform float BrickScale;
|
uniform float BrickScale;
|
||||||
|
|
||||||
|
const float EPSILON = 1e-6;
|
||||||
|
|
||||||
in DATA
|
in DATA
|
||||||
{
|
{
|
||||||
vec2 uv_out;
|
vec2 uv_out;
|
||||||
@@ -85,7 +88,7 @@ inline const char* fragDICOM = R"(
|
|||||||
rayDir = CamForward;
|
rayDir = CamForward;
|
||||||
}
|
}
|
||||||
|
|
||||||
float TraverseFineBlock(vec3 rayOrigin, vec3 rayDir, float blockTEnter, float blockTExit, ivec3 brickCoord, float brickScaleF, ivec3 gridSize)
|
vec4 TraverseFineBlock(vec3 rayOrigin, vec3 rayDir, float blockTEnter, float blockTExit, ivec3 brickCoord, float brickScaleF, ivec3 gridSize, vec4 currColor)
|
||||||
{
|
{
|
||||||
int brickSize = int(brickScaleF);
|
int brickSize = int(brickScaleF);
|
||||||
|
|
||||||
@@ -120,16 +123,25 @@ inline const char* fragDICOM = R"(
|
|||||||
|
|
||||||
int maxIters = brickSize * 3 + 8;
|
int maxIters = brickSize * 3 + 8;
|
||||||
|
|
||||||
float hits = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < maxIters; ++i)
|
for (int i = 0; i < maxIters; ++i)
|
||||||
{
|
{
|
||||||
if (t > blockTExit)
|
if (t > blockTExit)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
float density = texelFetch(DICOMTexture, voxel, 0).r;
|
float density = texelFetch(DICOMTexture, voxel, 0).r;
|
||||||
if (density >= Threshold)
|
uint v = uint(density * 65535.0 + 0.5);
|
||||||
hits++;
|
uint x = v & 0xFFu;
|
||||||
|
uint y = v >> 8u;
|
||||||
|
|
||||||
|
vec4 lutValue = texelFetch(LUTTexture, ivec2(x, y), 0);
|
||||||
|
if (lutValue.a > EPSILON)
|
||||||
|
{
|
||||||
|
currColor.xyz += (1.0 - currColor.w) * lutValue.rgb * lutValue.a;
|
||||||
|
currColor.w += (1.0 - currColor.w) * lutValue.a;
|
||||||
|
|
||||||
|
if (currColor.w > 0.98)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (tMax.x <= tMax.y && tMax.x <= tMax.z)
|
if (tMax.x <= tMax.y && tMax.x <= tMax.z)
|
||||||
{
|
{
|
||||||
@@ -154,7 +166,7 @@ inline const char* fragDICOM = R"(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hits;
|
return currColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 RenderVoxelDDA(vec3 rayOrigin, vec3 rayDir)
|
vec4 RenderVoxelDDA(vec3 rayOrigin, vec3 rayDir)
|
||||||
@@ -211,6 +223,8 @@ inline const char* fragDICOM = R"(
|
|||||||
|
|
||||||
float increment = StepSize;
|
float increment = StepSize;
|
||||||
|
|
||||||
|
vec4 colorAcum = vec4(0.0);
|
||||||
|
|
||||||
for (int i = 0; i < maxIters; ++i)
|
for (int i = 0; i < maxIters; ++i)
|
||||||
{
|
{
|
||||||
if (t > tExit)
|
if (t > tExit)
|
||||||
@@ -221,11 +235,12 @@ inline const char* fragDICOM = R"(
|
|||||||
float cellTExit = min(min(tMax.x, tMax.y), tMax.z);
|
float cellTExit = min(min(tMax.x, tMax.y), tMax.z);
|
||||||
cellTExit = min(cellTExit, tExit);
|
cellTExit = min(cellTExit, tExit);
|
||||||
|
|
||||||
if (brickDensity >= Threshold)
|
if (brickDensity >= EPSILON)
|
||||||
{
|
{
|
||||||
float hits = TraverseFineBlock(rayOrigin, rayDir, t, cellTExit, brick, brickScaleF, gridSize);
|
colorAcum = TraverseFineBlock(rayOrigin, rayDir, t, cellTExit, brick, brickScaleF, gridSize, colorAcum);
|
||||||
count += hits * increment;
|
|
||||||
if(count >= 1) break;
|
if (colorAcum.w > 0.98)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tMax.x <= tMax.y && tMax.x <= tMax.z)
|
if (tMax.x <= tMax.y && tMax.x <= tMax.z)
|
||||||
@@ -250,9 +265,8 @@ inline const char* fragDICOM = R"(
|
|||||||
tMax.z += tDelta.z;
|
tMax.z += tDelta.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count = clamp(count, 0.0, 1.0);
|
|
||||||
|
|
||||||
return vec4(count, count, count, 1.0);
|
return vec4(colorAcum.x, colorAcum.y, colorAcum.z, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
Reference in New Issue
Block a user