|
|
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
|
|