POV-Ray : Newsgroups : povray.programming : Sample Raytracer from Documentation as Fragment Shader (GPU) Server Time
28 Mar 2024 15:20:57 EDT (-0400)
  Sample Raytracer from Documentation as Fragment Shader (GPU) (Message 1 to 1 of 1)  
From: Roman Reiner
Subject: Sample Raytracer from Documentation as Fragment Shader (GPU)
Date: 11 Mar 2010 09:10:01
Message: <web.4b98f87675aabec01957bb5b0@news.povray.org>
Hello guys,
i implemented the raytracer from the povray documentation
(http://povray.org/documentation/view/3.6.1/125/) as a fragment shader in GLSL.
Just for the fun of it :)

With a recursion level of 5 and at a resolution of 800x600 it is running at 41
FPS on my Geforce GTX 260.

It was a little bit tricky to get the recursion working but i managed to work
around this limitation.

Here's the code in case someone is interested:
[code]
//==================================================================
// A simple GPU raytracer
// Features: Spheres, parallel Lights, Specular Highlights, Shadows, Reflections
// Author: Roman Reiner lim### [at] gmxde
// Based on the code at: http://povray.org/documentation/view/3.6.1/125/
//==================================================================


//==================================================================
// Structs:
//==================================================================

struct sphere {
 vec3 center;
 float radius;
 float reflectivity;
 vec3 color;
 float phong_size;
 float phong_amount;
};

struct light {
 vec3 direction;
 vec3 color;
};

struct ray {
 vec3 start;
 vec3 direction;
 int recLev;
 vec3 color;
};


//==================================================================
// Global settings:
//==================================================================

uniform int ImageWidth;
uniform int ImageHeight;

const int MaxRecLev = 5;
const vec3 AmbientLight = vec3(0.2, 0.2, 0.2);
const vec3 BGColor = vec3(0.0, 0.0, 0.0);

const int MaxDist = 100000;
const int ObjAmnt = 5;//dimension_size(Spheres, 1);
const int LightAmnt = 3;//dimension_size(Lights, 1);

sphere Spheres[5];
light Lights[3];

ray Ray;


//==================================================================
// Trace functions:
//==================================================================
float calcRaySphereIntersection(vec3 P, vec3 D, int sphereInd) {

 vec3 V = P-Spheres[sphereInd].center;
 float R = Spheres[sphereInd].radius;

 float DV = dot(D, V);
 float D2 = dot(D, D);
 float SQ = DV*DV-D2*(dot(V, V)-R*R);

 if(SQ < 0.0) {
  return -1.0;
 } else {
  float SQ = sqrt(SQ);
  float T1 = (-DV+SQ)/D2;
  float T2 = (-DV-SQ)/D2;
  return (T1 < T2 ? T1 : T2);
 }
}

/*
* Contrary to the original version this function now returns the reflected
* ray and stores the color in ray.color
* If no reflection occurs the returned ray has its recursion level set to
* MaxRecLev and will thus not spawn a new ray later.
*/

ray Trace(ray Ray) {
 vec3 P = Ray.start;
 vec3 D = Ray.direction;
 int recLev = Ray.recLev;

 ray NewRay;

 float minT = float(MaxDist);
 int closest = ObjAmnt;

 // Find closest intersection:
 for(int Ind=0; Ind < ObjAmnt; Ind++) {
  float T = calcRaySphereIntersection(P, D, Ind);
  if(T > 0.0) { /*&*/ if(T < minT) {
   minT = T;
   closest = Ind;
  }}
 }

 vec3 Pixel = vec3(0.0);

 // If not found, return background color:
 if(closest==ObjAmnt) {
  Pixel = BGColor;
  NewRay.recLev = MaxRecLev;
 } else {
  // Else calculate the color of the intersection point:
  vec3 IP = P + minT*D;
  float R = Spheres[closest].radius;
  vec3 Normal = (IP-Spheres[closest].center)/R;

  vec3 V = P - IP;
  vec3 Refl = 2.0*Normal*(dot(Normal, V)) - V;

  // Lighting:
  Pixel += AmbientLight;
  for(int Ind=0; Ind<LightAmnt; Ind++) {
   vec3 L = Lights[Ind].direction;

   // Shadowtest:
   bool Shadowed = false;
   for(int Ind2=0; Ind2<ObjAmnt; Ind2++) {
    if(Ind2!=closest) { /*&*/ if(calcRaySphereIntersection(IP, L, Ind2) > 0.0) {
     Shadowed = true;
     break;
    }}
   }

   if(!Shadowed) {
    // Diffuse:
    float Factor = dot(Normal, L);
    if(Factor > 0.0) {
     Pixel += Lights[Ind].color*Spheres[closest].color*Factor;
    }

    // Specular:
    Factor = dot(normalize(Refl), L);
    if(Factor > 0.0) {
     Pixel += Lights[Ind].color*pow(Factor,
Spheres[closest].phong_size)*Spheres[closest].phong_amount;
    }
   }
  }

  // Reflection:
  if(recLev < MaxRecLev) { /*&*/ if(Spheres[closest].reflectivity > 0.0) {
   NewRay.start = IP;
   NewRay.direction = Refl;
   NewRay.recLev = Ray.recLev+1;
  }}
 }

 NewRay.color = Ray.color + Pixel;
 //return Pixel;
 return NewRay;
}

/*
* Recursion workaround
*/

vec4 newTrace (vec3 P, vec3 D, int recLev) {
 ray Ray, NewRay;

 Ray.start = P;
 Ray.direction = D;
 Ray.recLev = recLev;

 for(int Ind=0; Ind<MaxRecLev; Ind++) {
  if(Ray.recLev<MaxRecLev) {
   NewRay = Trace(Ray);
   Ray = NewRay;
  }
 }

 return vec4(NewRay.color, 1.0);
}


void main() {

 //==================================================================
 // Scene definition:
 //==================================================================

 // Sphere information:
 Spheres[0].center = vec3(-1.05, 0.0, 4.0);
 Spheres[0].radius = 1.0;
 Spheres[0].reflectivity = 0.5;
 Spheres[0].color = vec3(1.0, 0.5, 0.25);
 Spheres[0].phong_size = 40.0;
 Spheres[0].phong_amount = 0.8;

 Spheres[1].center = vec3(1.05, 0.0, 4.0);
 Spheres[1].radius = 1.0;
 Spheres[1].reflectivity = 0.5;
 Spheres[1].color = vec3(0.5, 1.0, 0.5);
 Spheres[1].phong_size = 40.0;
 Spheres[1].phong_amount = 0.8;

 Spheres[2].center = vec3(0.0, -3.0, 5.0);
 Spheres[2].radius = 2.0;
 Spheres[2].reflectivity = 0.5;
 Spheres[2].color = vec3(0.25, 0.5, 1.0);
 Spheres[2].phong_size = 30.0;
 Spheres[2].phong_amount = 0.4;

 Spheres[3].center = vec3(-1.0, 2.3, 9.0);
 Spheres[3].radius = 2.0;
 Spheres[3].reflectivity = 0.5;
 Spheres[3].color = vec3(0.5, 0.3, 0.1);
 Spheres[3].phong_size = 30.0;
 Spheres[3].phong_amount = 0.4;

 Spheres[4].center = vec3(1.3, 2.6, 9.0);
 Spheres[4].radius = 1.8;
 Spheres[4].reflectivity = 0.5;
 Spheres[4].color = vec3(0.1, 0.3, 0.5);
 Spheres[4].phong_size = 30.0;
 Spheres[4].phong_amount = 0.4;


 // Light source directions and colors:
 Lights[0].direction = vec3(-1.0, 0.0, -0.5);
 Lights[0].color = vec3(0.8, 0.4, 0.1);

 Lights[1].direction = vec3(1.0, 1.0, -0.5);
 Lights[1].color = vec3(1.0, 1.0, 1.0);

 Lights[2].direction = vec3(0.0, 1.0, 0.0);
 Lights[2].color = vec3(0.1, 0.2, 0.5);


 //==================================================================
 // Raytracing calculations:
 //==================================================================

 for(int Ind=0; Ind<LightAmnt; Ind++) {
  Lights[Ind].direction = normalize(Lights[Ind].direction);
 }

 float CoordX =
((gl_FragCoord.x-0.5)/float(ImageWidth-1)-0.5)*2.0*float(ImageWidth)/float(ImageHeight);
 float CoordY = (gl_FragCoord.y-0.5)/float(ImageHeight-1)*2.0-1.0;

 gl_FragColor = newTrace(vec3(0.0, 0.0,-3.0), vec3(CoordX, CoordY, 3.0), 1);

}
[/code]

Now i'll have to implement it in C++ and see which one is faster :)

Regards Roman


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.