mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-01 01:01:37 -06:00
125 lines
3.5 KiB
Common Lisp
125 lines
3.5 KiB
Common Lisp
// Needs to mirror struct on host
|
|
struct KernelConstants {
|
|
float stepSize;
|
|
float intensity;
|
|
int aDim;
|
|
int bDim;
|
|
int cDim;
|
|
};
|
|
|
|
// Linearly interpolate between two values. Distance
|
|
// is assumed to be normalized.
|
|
float Lerp(float _v0, float _v1, float _d) {
|
|
return _v0*(1.0 - _d) + _v1*_d;
|
|
}
|
|
|
|
|
|
// Turn normalized [0..1] cartesian coordinates
|
|
// to normalized spherical [0..1] coordinates
|
|
float3 CartesianToSpherical(float3 _cartesian) {
|
|
// Put cartesian in [-1..1] range first
|
|
_cartesian = (float3)(-1.0) + 2.0* _cartesian;
|
|
float r = length(_cartesian);
|
|
float theta, phi;
|
|
if (r == 0.0) {
|
|
theta = phi = 0.0;
|
|
} else {
|
|
theta = acospi(_cartesian.z/r);
|
|
phi = (M_PI + atan2(_cartesian.y, _cartesian.x)) / (2.0*M_PI);
|
|
}
|
|
r = r / native_sqrt(3.0);
|
|
// Sampler ignores w component
|
|
return (float3)(r, theta, phi);
|
|
}
|
|
|
|
float4 TransferFunction(__global __read_only float *_tf, float _i) {
|
|
// TODO remove hard-coded value and change to 1D texture
|
|
int i0 = (int)floor(1023.0*_i);
|
|
int i1 = (i0 < 1023) ? i0+1 : i0;
|
|
float di = _i - floor(_i);
|
|
|
|
float tfr0 = _tf[i0*4+0];
|
|
float tfr1 = _tf[i1*4+0];
|
|
float tfg0 = _tf[i0*4+1];
|
|
float tfg1 = _tf[i1*4+1];
|
|
float tfb0 = _tf[i0*4+2];
|
|
float tfb1 = _tf[i1*4+2];
|
|
float tfa0 = _tf[i0*4+3];
|
|
float tfa1 = _tf[i1*4+3];
|
|
|
|
float tfr = Lerp(tfr0, tfr1, di);
|
|
float tfg = Lerp(tfg0, tfg1, di);
|
|
float tfb = Lerp(tfb0, tfb1, di);
|
|
float tfa = Lerp(tfa0, tfa1, di);
|
|
|
|
return (float4)(tfr, tfg, tfb, tfa);
|
|
}
|
|
|
|
__kernel void
|
|
Raycaster(__global __read_only image2d_t _cubeFront,
|
|
__global __read_only image2d_t _cubeBack,
|
|
__global __write_only image2d_t _output,
|
|
__global __read_only image3d_t _voxelData,
|
|
__constant struct KernelConstants *_constants,
|
|
__global __read_only float *_tf) {
|
|
|
|
|
|
int3 dimensions = (int3)(_constants->aDim,
|
|
_constants->bDim,
|
|
_constants->cDim);
|
|
|
|
// Kernel should be launched in 2D with one work item per pixel
|
|
int idx = get_global_id(0);
|
|
int idy = get_global_id(1);
|
|
int2 intCoords = (int2)(idx, idy);
|
|
|
|
// Sampler for texture reading
|
|
const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE;
|
|
const sampler_t volumeSampler = CLK_FILTER_LINEAR |
|
|
CLK_NORMALIZED_COORDS_TRUE |
|
|
CLK_ADDRESS_CLAMP_TO_EDGE;
|
|
|
|
// Read from textures
|
|
float4 cubeFrontColor = read_imagef(_cubeFront, sampler, intCoords);
|
|
float4 cubeBackColor = read_imagef(_cubeBack, sampler, intCoords);
|
|
|
|
// Figure out the direction
|
|
float3 direction = (cubeBackColor-cubeFrontColor).xyz;
|
|
float maxDistance = length(direction);
|
|
direction = normalize(direction);
|
|
|
|
// Keep track of distance traversed
|
|
float traversed = 0.0;
|
|
|
|
// Sum colors
|
|
float stepSize = _constants->stepSize;
|
|
float3 samplePoint = cubeFrontColor.xyz;
|
|
float4 spherical;
|
|
float4 color = (float4)(0.0, 0.0, 0.0, 0.0);
|
|
|
|
while (traversed < maxDistance) {
|
|
spherical.xyz = CartesianToSpherical(samplePoint);
|
|
spherical.w = 1.0;
|
|
|
|
// Texture stores intensity in R channel
|
|
float i = read_imagef(_voxelData, volumeSampler, spherical).x;
|
|
|
|
// Front-to-back compositing
|
|
float4 tf = TransferFunction(_tf, i);
|
|
color += (1.0 - color.w)*tf;
|
|
|
|
// color += (float4)(i, i, i, 1.0);
|
|
samplePoint += direction * stepSize;
|
|
traversed += stepSize;
|
|
}
|
|
|
|
// Output
|
|
float intensity = _constants->intensity;
|
|
color *= intensity*stepSize;
|
|
|
|
// Write to image
|
|
write_imagef(_output, intCoords, color);
|
|
|
|
}
|
|
|