The below openCL code works pretty good and pretty fast, but I have the impression that I'm missing something in terms of openCL barrier and in therm of index mix; I know that is not very easy to understand, it is the kernel of a CBCT reconstruction I'm working on; the finale image (ReturnMatrice looks a little confused).
__kernel void
ReconstructionGPU(
__global float* Matrice,
__global float* ReturnMatrice,
__global short* ReturnCheckImage,
__constant float* _dLocArraiAngoliSen,
__constant float* _dLocArraiAngoliCos,
__constant float* Cos_Tilt_in_Rad,
__constant float* Sin_Tilt_in_Rad,
__constant float* iTilt,
__constant float* _iOffsetU,
__constant float* _iOffsetV,
__constant int* iSizeX,
__constant int* iSizeY,
__constant int* iSizeZ,
__constant int* iSizeImgX,
__constant int* iSizeImgY,
__constant float* _fDSO,
__constant float* _fDSD,
__constant float* m_fSizeVoxelX,
__constant float* m_fSizeVoxelY,
__constant float* m_fPixelSensoreDim,
__constant int* Loop,
__constant int* Axial,
__constant int* Padding
)
{
private int _iLocSizeX = iSizeX[0]; // Detector X
private int _iLocSizeY = iSizeY[0]; // Detector Y
private int _iLocSizeImage = _iLocSizeX * _iLocSizeY; // Dimensione Immagine
private int _iSizeMezziX; // EmiMatrix X
_iSizeMezziX = (iSizeX[0] / 2 );
private int _iSizeMezziY;
_iSizeMezziY = (iSizeY[0] / 2 ); // EmiMatrix Y
private int _iSizeMezziDetX; // Emidetector X
_iSizeMezziDetX = (iSizeImgX[0] / 2 );
private int _iSizeMezziDetY;
_iSizeMezziDetY = (iSizeImgY[0] / 2 ); // Emidetector Y
private float _iSizeMezziYQuadro = ((_iSizeMezziX - Padding[0]) * (_iSizeMezziY - Padding[0])); //Border
private float kySen = 0;
private float kyCos = 0;
private float CoordY_Piu_OffsetU = 0;
private float CoordZ_Piu_OffsetV = 0;
private float fDist_Y_inMmObj = 0;
private float fDist_Z_inMmObj = 0;
private float fDSDinMmY = 0;
private float fDSDinMmZ = 0;
private float fDSDinMmYPiu_AngoloTilt = 0;
private float fDSDinMmZPiu_AngoloTilt = 0;
private float _ValImage = 0;
private int ValY = 0;
private int ValZ = 0;
private int _iTempx = 0;
private int _iTempy = 0;
private int _Index = 0;
private int z = 0;
private int zMenoAxial0 = 0;
private float zPerIlockSizeImage = 0;
private float TempYPerIlockSizeX = 0;
private float zPiuTyLoc = 0;
private float zMenoAxTyLoc = 0;
private int m_y;
private int m_x;
private int y;
private int x;
private int m_z = get_global_id(2);
z = m_z + Axial[0];
m_y = get_global_id(1);
m_x = get_global_id(0);
y = (m_y - _iSizeMezziY ) ;
x = (m_x - _iSizeMezziX) ;
CoordZ_Piu_OffsetV = -_iSizeMezziX + z + _iOffsetV[0];
fDist_Z_inMmObj = CoordZ_Piu_OffsetV * m_fSizeVoxelX[0];
zMenoAxial0 = (z - Axial[0] ) * _iLocSizeImage ;
zPerIlockSizeImage = z * _iLocSizeImage;
kySen = (_dLocArraiAngoliSen[Loop[0]] * (y)) ;
kyCos = (_dLocArraiAngoliCos[Loop[0]] * (y)) ;
CoordY_Piu_OffsetU = y - _iOffsetU[0];
fDist_Y_inMmObj = (CoordY_Piu_OffsetU * m_fSizeVoxelY[0]); // Distanza Y in millimetri del voxel in esame nel volume ricostruito
fDSDinMmY = 0;
fDSDinMmYPiu_AngoloTilt = 0;
ValY = 0;
fDSDinMmZ = 0;
fDSDinMmZPiu_AngoloTilt = 0;
ValZ = 0;
_iTempx = ((_iSizeMezziX + (_dLocArraiAngoliCos[Loop[0]] * x) - kySen)); // Calcolo coordinate X
_iTempy = ((_iSizeMezziY + (_dLocArraiAngoliSen[Loop[0]] * x) + kyCos)); // Calcolo coordinate Y
// Calcoli salti per assegnazione matrice ricostruita
TempYPerIlockSizeX = _iTempy * iSizeX[0];
zPiuTyLoc = zPerIlockSizeImage + TempYPerIlockSizeX;
zMenoAxTyLoc = zMenoAxial0 + TempYPerIlockSizeX;
if (_iTempy >= iSizeY - Padding[0] || _iTempx >= iSizeX - Padding[0] || _iTempy< 0 || _iTempx< 0 ||
(((_iTempx - _iSizeMezziX) * (_iTempx - _iSizeMezziX)) + ((_iTempy - _iSizeMezziY) * (_iTempy - _iSizeMezziY))) > _iSizeMezziYQuadro)
{ }
else
{
//float fKval = (_fDSO[0] - (x * m_fSizeVoxelX[0]));
float fKval = (_fDSO[0] - (x * m_fPixelSensoreDim[0]));
fDSDinMmY = ((fDist_Y_inMmObj* _fDSD[0]) / fKval); // Distanza Y del pixel in esame rapportata a DSD in millimetri
fDSDinMmZ = ((fDist_Z_inMmObj* _fDSD[0]) / fKval); // Distanza DSD in millimetri
if (iTilt != 0)
{
fDSDinMmYPiu_AngoloTilt = (fDSDinMmY * Cos_Tilt_in_Rad[0] +0.5f); // Calcolo della Coordinata che tiene conto anche dell'angolo di inclinazione del sensore
ValY = (((fDSDinMmYPiu_AngoloTilt / m_fPixelSensoreDim[0] ) + _iSizeMezziDetX)+0.5f); // Distanza in pixel del pixel in esame sul detector
fDSDinMmZPiu_AngoloTilt = (fDSDinMmZ + (fDSDinMmZ * Sin_Tilt_in_Rad[0])+0.5f); // Calcolo della Coordinata che tiene conto anche dell'angolo di inclinazione del sensore
ValZ = (((fDSDinMmZPiu_AngoloTilt / m_fPixelSensoreDim[0]) + _iSizeMezziDetY)+0.5f); // Distanza in pixel del pixel in esame sul detector
}
else
{
ValY = ((fDSDinMmY / m_fPixelSensoreDim[0]) + _iSizeMezziDetX+0.5f); // Distanza in pixel del pixel in esame sul detector
ValZ = ((fDSDinMmZ / m_fPixelSensoreDim[0]) + _iSizeMezziDetY+0.5f); // Distanza in pixel del pixel in esame sul detector
}
if (ValY >= 0 && ValY < iSizeImgX[0] && ValZ >= 0 && ValZ < iSizeImgY[0])
{
_Index = ((ValZ * iSizeImgX[0]) + ValY);
_ValImage = (float)Matrice[_Index];// Pixel dell'immagine con coordinate calcolate da ValX e ValY
}
else
{
_ValImage = 0; // Pixel dell'immagine con coordinate calcolate da ValX e ValY
}
barrier(CLK_LOCAL_MEM_FENCE);
ReturnMatrice[(int)zMenoAxTyLoc + _iTempx] += _ValImage; //ValImgPesato
_ValImage = 0;
}
}
Related
I try to generate a video with a timebase more precise than the 1/fps (camera frame rate are not constant). But the generated AVI does not seem to take into account the framerate that I indicate.
#include <iostream>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
constexpr int TIMEFACTOR = 10;
static void encodeFrame(AVCodecContext *avctx, AVFormatContext *ctx, AVFrame* frame)
{
int ret = avcodec_send_frame(avctx, frame);
AVPacket packet;
av_init_packet(&packet);
ret = 0;
while (ret >= 0) {
ret = avcodec_receive_packet(avctx, &packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return; // nothing to write
};
//packet.pts = (frame) ? frame->pts : packet.pts;
av_packet_rescale_ts(&packet, avctx->time_base, ctx->streams[0]->time_base);
packet.duration = TIMEFACTOR;
av_interleaved_write_frame(ctx, &packet);
av_packet_unref(&packet);
}
}
static void fill_yuv_frame(AVFrame* frame, int width, int height, int frameId)
{
// Y
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
frame->data[0][y * frame->linesize[0] + x] = x + y + frameId * 3;
}
}
// Cb and Cr
for (int y = 0; y < height / 2; y++) {
for (int x = 0; x < width / 2; x++) {
frame->data[1][y * frame->linesize[1] + x] = 128 + y + frameId * 2;
frame->data[2][y * frame->linesize[2] + x] = 64 + x + frameId * 5;
}
}
}
int main(int argc, char** argv)
{
const char filename[] = "output.avi";
const char encoder[] = "mpeg4";
constexpr int WIDTH = 640;
constexpr int HEIGHT = 480;
av_log_set_level(AV_LOG_DEBUG);
//delete file because libavcodec reload file
remove(filename);
AVFormatContext* ofmtCtx;
int ret = avformat_alloc_output_context2(&ofmtCtx, NULL, "avi", filename);
AVCodec* avcodec = avcodec_find_encoder_by_name(encoder);
AVCodecContext* avctx = avcodec_alloc_context3(avcodec);
avctx->width = WIDTH ;
avctx->height = HEIGHT ;
avctx->sample_aspect_ratio = { 1, 1 };
avctx->pix_fmt = AV_PIX_FMT_YUV420P; //Do not work with other type
avctx->codec_id = AV_CODEC_ID_MPEG4;
avctx->bit_rate = 4 * 1000 * 1000;
avctx->time_base = av_make_q(1, 25 * TIMEFACTOR);
avctx->framerate = av_make_q(25, 1);
avctx->ticks_per_frame = TIMEFACTOR;
avctx->gop_size = 10;
avctx->max_b_frames = 1;
AVStream* m_outStream = avformat_new_stream(ofmtCtx, NULL);
ret = avcodec_open2(avctx, avcodec, NULL);
ret = avcodec_parameters_from_context(m_outStream->codecpar, avctx);
m_outStream->time_base = avctx->time_base;
m_outStream->r_frame_rate = avctx->framerate;
m_outStream->avg_frame_rate = avctx->framerate;
ret = avio_open(&(ofmtCtx->pb),
filename,
AVIO_FLAG_WRITE);
ret = avformat_write_header(ofmtCtx, NULL);
av_dump_format(ofmtCtx, 0, filename, 1);
AVFrame * avframe = av_frame_alloc();
avframe->format = avctx->pix_fmt;
avframe->width = avctx->width;
avframe->height = avctx->height;
ret = av_frame_get_buffer(avframe, 0);
ret = av_frame_make_writable(avframe);
for (int i = 0; i < 25; ++i) {
fflush(stdout);
fill_yuv_frame(avframe, avctx->width, avctx->height, i);
avframe->pts = i * TIMEFACTOR;
encodeFrame(avctx, ofmtCtx, avframe);
}
encodeFrame(avctx, ofmtCtx, NULL);
av_write_trailer(ofmtCtx);
return 0;
}
And this is dump output :
[mpeg4 # 000002AA64FA1880] intra_quant_bias = 0 inter_quant_bias = -64
[file # 000002AA64F69AC0] Setting default whitelist 'file,crypto'
[avi # 000002AA64F73400] reserve_index_space:0 master_index_max_size:256
[avi # 000002AA64F73400] duration_est:36000.000, filesize_est:18.4GiB, master_index_max_size:256
Output #0, avi, to 'output.avi':
Metadata:
ISFT : Lavf58.12.100
Stream #0:0, 0, 1/250: Video: mpeg4, 1 reference frame (FMP4 / 0x34504D46), yuv420p, 640x480 (0x0) [SAR 1:1 DAR 4:3], 0/1, q=2-31, 4000 kb/s, 25 fps, 25 tbr, 250 tbn
But if I open the video in ffmpeg command line fps is 250, and video content 250 frames, with many dropframe.
I wanted to add some lighting to the 3D mesh so that the back surface is visible. But when I added Ambient Light to it, some of the minor details of the graph became invisible. How can I add some lighting to the mesh so that the back surface is visible but the minor details don't vanish away?
Before adding light:
After adding light:
import java.util.logging.Logger;
import javafx.scene.DepthTest;
import javafx.scene.image.Image;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
public class Fx3DPlotMesh extends MeshView {
private static final int SIZE = 500;
private static float AMPLIFI = 130;
private int rtResolution;
private int mzResolution;
private static final Logger LOG = Logger
.getLogger(Fx3DPlotMesh.class.getName());
public Fx3DPlotMesh(Dataset dataset) {
rtResolution = dataset.getRtResolution();
mzResolution = dataset.getMzResolution();
TriangleMesh mesh = new TriangleMesh();
int[][] peakListIndices = new int[rtResolution][mzResolution];
float factorX = (float) SIZE / rtResolution;
float factorZ = (float) SIZE / mzResolution;
float[][] intensityValues = dataset.getIntensityValues();
for (int x = 0; x < rtResolution; x++) {
for (int z = 0; z < mzResolution; z++) {
mesh.getPoints().addAll((float) x * factorX,-intensityValues[x][z] * AMPLIFI ,(float) z * factorZ);
}
}
int rtLength = rtResolution;
int mzLength = mzResolution;
float rtTotal = rtLength;
float mzTotal = mzResolution;
for (float x = 0; x < rtLength - 1; x++) {
for (float y = 0; y < mzLength - 1; y++) {
float x0 = x / rtTotal;
float y0 = y / mzTotal;
float x1 = (x + 1) / rtTotal;
float y1 = (y + 1) / mzTotal;
mesh.getTexCoords().addAll( //
x0, y0, // 0, top-left
x0, y1, // 1, bottom-left
x1, y0, // 2, top-right
x1, y1 // 3, bottom-right
);
}
}
// faces
for (int x = 0; x < rtLength - 1; x++) {
for (int z = 0; z < mzLength - 1; z++) {
int tl = x * mzLength + z; // top-left
int bl = x * mzLength + z + 1; // bottom-left
int tr = (x + 1) * mzLength + z; // top-right
int br = (x + 1) * mzLength + z + 1; // bottom-right
int offset = (x * (mzLength - 1) + z) * 8 / 2; // div 2 because
// we have u AND
// v in the list
// working
mesh.getFaces().addAll(bl, offset + 1, tl, offset + 0, tr,
offset + 2);
mesh.getFaces().addAll(tr, offset + 2, br, offset + 3, bl,
offset + 1);
}
}
LOG.info("Plot mesh is ready.");
setMesh(mesh);
setCullFace(CullFace.NONE);
setDrawMode(DrawMode.FILL);
setDepthTest(DepthTest.ENABLE);
}
}
This code produces the mesh shown in the above image. I just wanted to add some more lighting to this mesh. I tried adding some light using the code below but it didn't worked. Please help!
Light.Spot light = new Light.Spot();
light.setX(250);
light.setY(500);
light.setZ(250);
light.setPointsAtX(250);
light.setPointsAtY(0);
light.setPointsAtZ(250);
light.setSpecularExponent(2);
Lighting lighting = new Lighting();
lighting.setLight(light);
lighting.setSurfaceScale(5.0);
meshView.setEffect(lighting);
I have sample code but it completely leaves out what my (void*)should_be!
I setup a cl_image_desc, cl_image_format, buffer, origin, and region:
cl_image_desc desc;
desc.image_type = CL_MEM_OBJECT_IMAGE2D;
desc.image_width = width;
desc.image_height = height;
desc.image_depth = 0;
desc.image_array_size = 0;
desc.image_row_pitch = 0;
desc.image_slice_pitch = 0;
desc.num_mip_levels = 0;
desc.num_samples = 0;
desc.buffer = NULL;
cl_image_format format;
format.image_channel_order = CL_R;
format.image_channel_data_type = CL_FLOAT;
cl_mem bufferSourceImage = clCreateImage(context, CL_MEM_READ_ONLY, &format, &desc, NULL, NULL);
size_t origin[3] = {0, 0, 0};
size_t region[3] = {width, height,1};
In this next snippet sourceImage is a void pointer to my image. But what is my image? For every pixel there are r, g, b, a, x, and y values.
clEnqueueWriteImage(queue, bufferSourceImage, CL_TRUE, origin, region, 0, 0, sourceImage, 0, NULL, NULL);
How do I turn my image (a bunch of (r,g,b,a,x,y)'s) into a suitable array?
This is the kernel they provide:
__kernel void convolution(__read_only image2d_t sourceImage, __write_only image2d_t outputImage, int rows, int cols, __constant float* filter, int filterWidth, sampler_t sampler)
{
int column = get_global_id(0);
int row = get_global_id(1);
int halfWidth = (int)(filterWidth/2);
float4 sum = {0.0f, 0.0f, 0.0f, 0.0f};
int filterIdx = 0;
int2 coords;
for(int i = -halfWidth; i <= halfWidth; i++)
{
coords.y = row + i;
for(int i2 = -halfWidth; i2 <= halfWidth; i2++)
{
coords.x = column + i2;
float4 pixel;
pixel = read_imagef(sourceImage, sampler, coords);
sum.x += pixel.x * filter[filterIdx++];
}
}
if(myRow < rows && myCol < cols)
{
coords.x = column;
coords.y = row;
write_imagef(outputImage, coords, sum);
}
}
Set up the cl_image_format as you like and then you just have to follow that format what you selected. Currently your channel (R, G, B, A) data should be represented as "single precision floating-point value" - image_channel_data_type = CL_FLOAT, and you can take only one channel of those and feed it into the expected R channel (image_channel_order = CL_R).
Your kernel expect float:
float4 pixel;
pixel = read_imagef(sourceImage, sampler, coords);
Ive been through every resource and cant fix my problem.
My host code calls the rgb2hsl kernel, then calls the hsl2rgb kernel. I should end up with the same image that I started with, but I do not. My new image hue is off in certain areas.
The red areas should not be there.
Here is the screen shot of what happens:
Here is the original picture
Here is the code:
#define E .0000001f
bool fEqual(float x, float y)
{
return (x+E > y && x-E < y);
}
__kernel void rgb2hsl(__global float *values, int numValues)
{
// thread index and total
int idx = get_global_id(0);
int idxVec3 = idx*3;
float3 gMem;
if (idx < numValues)
{
gMem.x = values[idxVec3];
gMem.y = values[idxVec3+1];
gMem.z = values[idxVec3+2];
}
barrier(CLK_LOCAL_MEM_FENCE);
gMem /= 255.0f; //convert from 256 color to float
//calculate chroma
float M = max(gMem.x, gMem.y);
M = max(M, gMem.z);
float m = min(gMem.x, gMem.y);
m = min(m, gMem.z);
float chroma = M-m; //calculate chroma
float lightness = (M+m)/2.0f;
float saturation = chroma/(1.0f-fabs(2.0f*lightness-1.0f));
float hue = 0;
if (fEqual(gMem.x, M))
hue = (int)((gMem.y - gMem.z)/chroma) % 6;
if (fEqual(gMem.y, M))
hue = (((gMem.z - gMem.x))/chroma) + 2;
if (fEqual(gMem.z, M))
hue = (((gMem.x - gMem.y))/chroma) + 4;
hue *= 60.0f;
barrier(CLK_LOCAL_MEM_FENCE);
if (idx < numValues)
{
values[idxVec3] = hue;
values[idxVec3+1] = saturation;
values[idxVec3+2] = lightness;
}
}
__kernel void hsl2rgb(__global float *values, int numValues)
{
// thread index and total
int idx = get_global_id(0);
int idxVec3 = idx*3;
float3 gMem;
if (idx < numValues)
{
gMem.x = values[idxVec3];
gMem.y = values[idxVec3+1];
gMem.z = values[idxVec3+2];
}
barrier(CLK_LOCAL_MEM_FENCE);
float3 rgb = (float3)(0,0,0);
//calculate chroma
float chroma = (1.0f - fabs( (float)(2.0f*gMem.z - 1.0f) )) * gMem.y;
float H = gMem.x/60.0f;
float x = chroma * (1.0f - fabs( fmod(H, 2.0f) - 1.0f ));
switch((int)H)
{
case 0:
rgb = (float3)(chroma, x, 0);
break;
case 1:
rgb = (float3)(x, chroma, 0);
break;
case 2:
rgb = (float3)(0, chroma, x);
break;
case 3:
rgb = (float3)(0, x, chroma);
break;
case 4:
rgb = (float3)(x, 0, chroma);
break;
case 5:
rgb = (float3)(chroma, 0, x);
break;
default:
rgb = (float3)(0, 0, 0);
}
barrier(CLK_LOCAL_MEM_FENCE);
rgb += gMem.z - .5f*chroma;
rgb *= 255;
if (idx < numValues)
{
values[idxVec3] = rgb.x;
values[idxVec3+1] = rgb.y;
values[idxVec3+2] = rgb.z;
}
}
The problem was this line:
hue = (int)((gMem.y - gMem.z)/chroma) % 6;
It should be
hue = fmod((gMem.y - gMem.z)/chroma, 6.0f);
I did some more changes to remove artifacts:
#define E .0000001f
bool fEqual(float x, float y)
{
return (x+E > y && x-E < y);
}
__kernel void rgb2hsl(__global float *values, int numValues)
{
// thread index and total
int idx = get_global_id(0);
int idxVec3 = idx*3;
float3 gMem;
if (idx < numValues)
{
gMem.x = values[idxVec3];
gMem.y = values[idxVec3+1];
gMem.z = values[idxVec3+2];
}
barrier(CLK_LOCAL_MEM_FENCE);
gMem /= 255.0f; //convert from 256 color to float
//calculate chroma
float M = max(gMem.x, gMem.y);
M = max(M, gMem.z);
float m = min(gMem.x, gMem.y);
m = min(m, gMem.z);
float chroma = M-m; //calculate chroma
float lightness = (M+m)/2.0f;
float saturation = chroma/(1.0f-fabs(2.0f*lightness-1.0f));
float hue = 0;
if (fEqual(gMem.x, M))
hue = fmod((gMem.y - gMem.z)/chroma, 6.0f);
if (fEqual(gMem.y, M))
hue = (((gMem.z - gMem.x))/chroma) + 2;
if (fEqual(gMem.z, M))
hue = (((gMem.x - gMem.y))/chroma) + 4;
hue *= 60.0f;
barrier(CLK_LOCAL_MEM_FENCE);
if (M == m)
hue = saturation = 0;
barrier(CLK_GLOBAL_MEM_FENCE);
if (idx < numValues)
{
//NOTE: ARTIFACTS SHOW UP if we do not cast to integer!
values[idxVec3] = (int)hue;
values[idxVec3+1] = saturation;
values[idxVec3+2] = lightness;
}
}
I am trying to draw the Mandelbox using my own ray marching on the CPU.
I have a width*height bitmap to render to.
For each pixel, I want to march towards the cube:
static float eye = 0.0f; eye = glm::clamp(eye+0.005f,0.0f,1.0f); // animate
const glm::mat4 projection = glm::perspective(35.0f, (float)width/height, 0.1f, 10.0f),
modelview = glm::lookAt(glm::vec3(cos(eye),sin(eye),-1),glm::vec3(0,0,0),glm::vec3(0,0,1));
const float epsilon = sqrt(1.0f/std::max(width,height))/2.0f;
for(int y=0; y<height; y++) {
for(int x=0; x<width; x++) {
glm::vec3 p = glm::unProject(glm::vec3(x,y,0),modelview,projection,glm::vec4(0,0,width,height)),
dir = glm::unProject(glm::vec3(x,y,1),modelview,projection,glm::vec4(0,0,width,height))-p,
P0 = p;
//std::cout << x << "," << y << " " << p.x << "," << p.y << "," << p.z << " " << dir.x << "," << dir.y << "," << dir.z << std::endl;
float D = 0;
for(int i=0; i<MAX_ITER; i++) {
const float d = DE(p);
D += d;
if(d<epsilon) {
depth_bmp[y*width+x] = 255.0f/i;
break;
}
p = dir*D + P0;
}
}
}
My distance estimator function is a very literal translation and looks like this:
float DE(glm::vec3 p) {
const float Scale = -1.77f, fixedRadius2 = 1.0f, minRadius2 = (0.5f*0.5f);
const glm::vec3 p0 = p;
float dr = 1.0f;
for(int n = 0; n < 13; n++) {
// Reflect
p = (glm::clamp(p,-1.0f,1.0f) * 2.0f) - p;
// Sphere Inversion
const float r2 = glm::dot(p,p);
if(r2<minRadius2) {
const float t = (fixedRadius2/minRadius2);
p *= t;
dr *= t;
} else if(r2<fixedRadius2) {
const float t = (fixedRadius2/r2);
p *= t;
dr *= t;
}
// Scale & Translate
p = p * Scale + p0;
dr = dr * abs(Scale) + 1.0f;
}
return glm::length(p)/abs(dr);
}
And the output looks completely unbox-like:
How do I set the eye transform up so I see the cube properly?
The issue is that the length of the ray must be normalised:
glm::vec3 p = glm::unProject(glm::vec3(x,y,0),modelview,projection,glm::vec4(0,0,width,height)),
dir = glm::unProject(glm::vec3(x,y,1),modelview,projection,glm::vec4(0,0,width,height))-p;
const float len = glm::length(dir);
dir = glm::normalise(dir);
float D = 0;
for(int i=0; i<MAX_ITER; i++) {
const float d = DE(p + dir*D);
D += d;
if(D > len) break;
...
You can use the method outlined here to generate the correct rays (and their lengths).