Today I'm going to comment a small program that it's not fully related to raytrace, but is related to 3D.
It has been some time since I have tried to represent the Markus-Lyapunov fractal. The 3D version extends the exponent computation one dimension. I have used CUDA and OpenGL to represent that.
Thanks to CUDA it's possible do computation using the GPU, so, if you have a good video card, the computation will be quite fast.
The variation of the algorithm is simple. The sequences contain one more letter, in this case C, that represents a point in the Z coordinate (or 'c'). Everything else is similar to the previous algorithm.
In order to do the renders I use two VBOs: One for storing positions and another one to store colors. The positions will be arranged in a volume of 256x256x256 elements. To compute the colors of each voxel I use two kernels. One computes the positions of each point and stores them in one VBO. The other use that positions to compute the color, that is the lyapunov exponent in that point. The points with an exponent greater than zero (or greater than a cut-off value) are moved to a region in order to not disturb. The points with a negative exponent (or lower than the cutoff value) will be drawn with a color proportional to the absolute value of the exponent.
The code for computing the Lyapunov 3D exponent for the sequence ABC is this:
This is the Kernel code for computing the positions of the evaluating points:
It has been some time since I have tried to represent the Markus-Lyapunov fractal. The 3D version extends the exponent computation one dimension. I have used CUDA and OpenGL to represent that.
Thanks to CUDA it's possible do computation using the GPU, so, if you have a good video card, the computation will be quite fast.
The variation of the algorithm is simple. The sequences contain one more letter, in this case C, that represents a point in the Z coordinate (or 'c'). Everything else is similar to the previous algorithm.
In order to do the renders I use two VBOs: One for storing positions and another one to store colors. The positions will be arranged in a volume of 256x256x256 elements. To compute the colors of each voxel I use two kernels. One computes the positions of each point and stores them in one VBO. The other use that positions to compute the color, that is the lyapunov exponent in that point. The points with an exponent greater than zero (or greater than a cut-off value) are moved to a region in order to not disturb. The points with a negative exponent (or lower than the cutoff value) will be drawn with a color proportional to the absolute value of the exponent.
The code for computing the Lyapunov 3D exponent for the sequence ABC is this:
__device__ float evalLyap(float3 p)
{
float sum=0;
float Xn=0.5f;
for (int i = 0; i < 3; i++) {
float rn = i==2 ? p.x : i==1? p.y : p.z;
Xn=rn*Xn*(1-Xn);
}
int iterations=lyapunovParams.iterations;
for (int n=0;n<iterations;n++){
float prod_deriv=1;
for (int i = 0; i < 3; i++) {
float rn = i==2 ? p.x : i==1? p.y : p.z;
Xn=rn*Xn*(1-Xn);
prod_deriv *= rn*(1-2*Xn);
}
float q=log(fabs(prod_deriv));
sum+=q;
}
return sum/(iterations*3);
}
This is the Kernel code for computing the positions of the evaluating points:
__global__ void kernelGeneration(float3 *ptr, int dim)And finaly this is the Kernel code for computing the colors of those points:
{
int xx=threadIdx.x + blockIdx.x*blockDim.x;
int yy=threadIdx.y + blockIdx.y*blockDim.y;
int offset=xx + yy*blockDim.x*gridDim.x;
int res=dim*dim;
int z=truncf(offset/res);
res=offset-z*res;
int y=truncf(res/dim);
int x=res-y*dim;
float fx = x/(float)dim;
float fy = y/(float)dim;
float fz = z/(float)dim;
ptr[offset].x=fx;
ptr[offset].y=fy;
ptr[offset].z=fz;
}
__global__ void kernelComputation(float3 *ptrPos, float4 *ptrCol, int dim)
{
int xx=threadIdx.x + blockIdx.x*blockDim.x;
int yy=threadIdx.y + blockIdx.y*blockDim.y;
int offset=xx + yy*blockDim.x*gridDim.x;
float3 pos=ptrPos[offset];
pos.x*=lyapunovParams.maxX-lyapunovParams.minX;
pos.y*=lyapunovParams.maxY-lyapunovParams.minY;
pos.z*=lyapunovParams.maxZ-lyapunovParams.minZ;
pos.x+=lyapunovParams.minX;
pos.y+=lyapunovParams.minY;
pos.z+=lyapunovParams.minZ;
float lambda=evalLyap(pos);
float alpha=1;
if (lambda<-lyapunovParams.cut_off) {
lambda+=lyapunovParams.cut_off;
float l=-lambda*lyapunovParams.factor;
if (l<0)l=0;
if (l>1)l=1;
ptrCol[offset].x=l;
ptrCol[offset].y=l;
ptrCol[offset].z=l;
ptrCol[offset].w=l;
} else {
ptrCol[offset].x=0;
ptrCol[offset].y=0;
ptrCol[offset].z=0;
ptrCol[offset].w=0;
ptrPos[offset].x=0;
ptrPos[offset].y=0;
ptrPos[offset].z=0;
}
}