Files
OpenSpace/kernels/RaycasterTexture.cl
Hans-Christian Helltegen 658ae13d96 Added flare to OpenSpace
2014-03-19 16:41:12 -04:00

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);
}