Monday, February 25, 2013

Complex Geometry and Interactive Raytracing




A few screenshots and a video of the interactive CUDA raytracer with added support for OBJ files.






It took me a while to complete the algorithm that extrapolates normals in a triangle. The trick is to compute the area of each triangle defines by the intersection point and the three vertices. Once you get that, just find the weighted mean, and you're done. Here is the code:

float4 v0 = triangle.p0 - intersection;
float4 v1 = triangle.p1 - intersection;
float4 v2 = triangle.p2 - intersection;
float a0 = 0.5f*vectorLength(crossProduct( v1,v2 ));
float a1 = 0.5f*vectorLength(crossProduct( v0,v2 ));
float a2 = 0.5f*vectorLength(crossProduct( v0,v1 ));
normal = (triangle.n0*a0 + triangle.n1*a1 + triangle.n2*a2)/(a0+a1+a2);

As simple as that :-)





Monday, February 4, 2013

Mandelbrot Set as a texture

GPUs are amazing, I tried to use the Mandelbrot set as a texture, because it's amazingly beautiful and easy to implement. The algorithm I used is the following:
__device__ void mandelbrotSet( const SceneInfo& sceneInfo, const float x, const float y, float4& color )
{
   float W = (float)gTextureWidth;
   float H = (float)gTextureHeight;

   float  MinRe               = -2.f;
   float  MaxRe               =       1.f;
   float  MinIm               = -1.2f;
   float  MaxIm               =       MinIm + (MaxRe - MinRe) * H/W;
   float  Re_factor    =       (MaxRe - MinRe) / (W - 1.f);
   double Im_factor    =       (MaxIm - MinIm) / (H - 1.f);
   float  MaxIterations = 20.f+sceneInfo.pathTracingIteration.x;

   float c_im = MaxIm - y*Im_factor;
   float c_re = MinRe + x*Re_factor;
   float Z_re = c_re;
   float Z_im = c_im;
   bool isInside = true;
   unsigned n;
   for( n = 0; isInside && n < MaxIterations; ++n )
   {
      float Z_re2 = Z_re*Z_re;
      float Z_im2 = Z_im*Z_im;
      if ( Z_re2+Z_im2>4.f )
      {
         isInside = false;
      }
      Z_im = 2.f*Z_re*Z_im+c_im;
      Z_re = Z_re2 - Z_im2+c_re;
   }

   color.x += Z_re/64.f;
   color.y += Z_im/64.f;
   color *= (n/MaxIterations);
}

GPUs amaze me for making it possible to enjoy real-time computation of ray-traced images, with the Mandelbrot set... as a texture.













Sunday, February 3, 2013

3D Parametric Curves are cool


3D Parametric Curves are cool because they make it easy to construct beautiful shapes out of simple mathematical formulas. Since I am lazy and not good at modeling 3D scenes, I thought that using these equations was probably the best way to get nice images.

The following curves are made of cylinders, following the paths defined by the parametric curves.














Here are the functions I used to generated the shapes:

void trefoilKnot(float R, float t, float4& p)
{
   p.x = R*(sin(t)+2.f*sin(2.f*t));
   p.y = R*(cos(t)-2.f*cos(2.f*t));
   p.z = R*(-sin(3.f*t));
}

void torus(float R, float t, float4& p )
{
   p.x = R*(3.f*cos(t)+cos(10.f*t)*cos(t));
   p.y = R*(3.f*sin(t)+cos(10.f*t)*sin(t));
   p.z = R*sin(10.f*t);
}

void star(float R, float t, float4& p )
{
   p.x = R*(2.f*sin(3.f*t)*cos(t));
   p.y = R*(2.f*sin(3.f*t)*sin(t));
   p.z = R*sin(3.f*t);
}

void spring(float R, float t, float4& p)
{
   p.x = R*cos(t);
   p.y = R*sin(t);
   p.z = R*cos(t);
}

void heart(float R, float u, float v, float4& p)
{
   p.x = R*4.f*pow(sin(u),3.f);
   p.y = R*0.25f*(13*cos(u)-5*cos(2.f*u)-2.f*cos(3.f*u)-cos(4.f*u));
   p.z = 0.f;
}

void thing(float R, float t, float4 a, float4& p)
{
   p.x = R*(sin(t)+a.x*sin(a.y*t));
   p.y = R*(cos(t)-a.x*cos(a.y*t));
   p.z = R*(-sin(a.z*t));
}

void moebius(float R, float u, float v, float s, float du, float dv, float4& p )
{
   p.x = 2.f*R*(cos(u)+v*cos(u/2)*cos(u));
   p.y = 2.f*R*(sin(u)+v*cos(u/2)*sin(u));
   p.z = 2.f*R*(v*sin(u/2));
}