summaryrefslogtreecommitdiff
path: root/raytrace.cpp
diff options
context:
space:
mode:
authorStephane Marchesin <marchesin@icps.u-strasbg.fr>2009-07-12 16:11:09 +0200
committerStephane Marchesin <marchesin@icps.u-strasbg.fr>2009-07-12 16:11:09 +0200
commita3f015419eb737c6095d88f686312124a86ea74e (patch)
tree0e0e0e74240c2dbfee41f0864af814f57939e6c0 /raytrace.cpp
Import.
Diffstat (limited to 'raytrace.cpp')
-rw-r--r--raytrace.cpp458
1 files changed, 458 insertions, 0 deletions
diff --git a/raytrace.cpp b/raytrace.cpp
new file mode 100644
index 0000000..59f8d02
--- /dev/null
+++ b/raytrace.cpp
@@ -0,0 +1,458 @@
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <math.h>
+#include <SDL.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#define BALLS 4
+
+static PFNGLGETOBJECTPARAMETERIVARBPROC eglGetObjectParameterivARB =NULL;
+static PFNGLGETINFOLOGARBPROC eglGetInfoLogARB =NULL;
+static PFNGLCREATESHADEROBJECTARBPROC eglCreateShaderObjectARB =NULL;
+static PFNGLSHADERSOURCEARBPROC eglShaderSourceARB =NULL;
+static PFNGLCOMPILESHADERARBPROC eglCompileShaderARB =NULL;
+static PFNGLCREATEPROGRAMOBJECTARBPROC eglCreateProgramObjectARB =NULL;
+static PFNGLATTACHOBJECTARBPROC eglAttachObjectARB =NULL;
+static PFNGLLINKPROGRAMARBPROC eglLinkProgramARB =NULL;
+static PFNGLUNIFORM1IARBPROC eglUniform1iARB =NULL;
+static PFNGLUNIFORM3FARBPROC eglUniform3fARB =NULL;
+static PFNGLGETUNIFORMLOCATIONARBPROC eglGetUniformLocationARB =NULL;
+static PFNGLUSEPROGRAMOBJECTARBPROC eglUseProgramObjectARB =NULL;
+
+static void vr_glext_glsl_init_exts()
+{
+ static bool init=false;
+ if (init)
+ return;
+ eglGetObjectParameterivARB=(PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB");
+ eglGetInfoLogARB=(PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB");
+ eglCreateShaderObjectARB=(PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB");
+ eglShaderSourceARB=(PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB");
+ eglCompileShaderARB=(PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB");
+ eglCreateProgramObjectARB=(PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
+ eglAttachObjectARB=(PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB");
+ eglLinkProgramARB=(PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB");
+ eglUniform1iARB=(PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
+ eglUniform3fARB=(PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB");
+ eglGetUniformLocationARB=(PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB");
+ eglUseProgramObjectARB=(PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
+}
+
+
+static void vr_glext_glsl_dump_log(GLhandleARB p,const GLcharARB* shader)
+{
+ vr_glext_glsl_init_exts();
+ GLint log_size;
+ eglGetObjectParameterivARB(p, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size);
+ if (log_size>1)
+ {
+ GLcharARB* s=(GLcharARB*)malloc((log_size+1)*sizeof(GLcharARB));
+ eglGetInfoLogARB(p,log_size,NULL,s);
+ printf("============================================================\n");
+ printf("Faulty ARB program. Log (%d bytes) : \n%s\n",log_size,s);
+ free(s);
+ printf("Faulty ARB program : \n");
+ int lc=0;
+ printf("\n%4d: ",++lc);
+ for(int i=0;i<(int)strlen(shader);i++)
+ {
+ if (shader[i]=='\n')
+ printf("\n%4d: ",++lc);
+ else
+ printf("%c",shader[i]);
+ }
+ printf("\n");
+ printf("============================================================\n");
+ }
+}
+
+bool vr_glext_glsl_create_program(const GLcharARB* vshader,const GLcharARB* fshader,GLhandleARB* res)
+{
+ vr_glext_glsl_init_exts();
+ GLint ok;
+
+ GLhandleARB vs=eglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ GLhandleARB fs=eglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ eglShaderSourceARB(vs, 1, &vshader,NULL);
+ eglShaderSourceARB(fs, 1, &fshader,NULL);
+ eglCompileShaderARB(vs);
+ vr_glext_glsl_dump_log(vs,vshader);
+ eglGetObjectParameterivARB(vs,GL_OBJECT_COMPILE_STATUS_ARB,&ok);
+ if (!ok)
+ {
+ printf("compiling vertex shader\n");
+ return false;
+ }
+ eglCompileShaderARB(fs);
+ vr_glext_glsl_dump_log(fs,fshader);
+ eglGetObjectParameterivARB(fs,GL_OBJECT_COMPILE_STATUS_ARB,&ok);
+ if (!ok)
+ {
+ printf("compiling fragment shader\n");
+ return false;
+ }
+ GLhandleARB p = eglCreateProgramObjectARB();
+ eglAttachObjectARB(p,vs);
+ eglAttachObjectARB(p,fs);
+ eglLinkProgramARB(p);
+ vr_glext_glsl_dump_log(p,"(Linking Stage)");
+ eglGetObjectParameterivARB(p,GL_OBJECT_LINK_STATUS_ARB,&ok);
+ if (!ok)
+ {
+ printf("linking program\n");
+ return false;
+ }
+ *res=p;
+ return true;
+}
+
+char vshader[] =
+"void main()"
+"{"
+" gl_TexCoord[0] = gl_MultiTexCoord0;"
+" gl_Position = ftransform();"
+"}";
+
+char fshader_ray[] =
+"uniform sampler1D spheres_geom; \n"
+"uniform sampler2D wall_texture; \n"
+//"uniform sampler1D spheres_color; \n"
+"uniform vec3 light_pos; \n"
+
+"float intersect(vec3 ray_pos, vec3 ray_vec) \n"
+"{ \n"
+" float i = 0.0; \n"
+" float current = 1.0; \n"
+" for( i=0.0 ; i<1.0 ; i+= 1.0/%d.0) \n"
+" { \n"
+" vec4 sphere_geom = texture1D( spheres_geom, i); \n"
+" vec3 dst = ray_pos - sphere_geom.xyz; \n"
+" float a = dot (ray_vec, ray_vec); \n"
+" float b = 2.0 * dot (dst, ray_vec); \n"
+" float c = dot (dst, dst) - sphere_geom.a*sphere_geom.a; \n"
+" float d = b*b - 4.0*a*c; \n"
+" if ( d > -0.01 ) \n"
+" { \n"
+" float dp = d < 0.0 ? 0.0 : d; \n"
+" if ( (-b - sqrt(dp) ) /(2.0 * a) > 0.0) \n"
+" { \n"
+" if (d > 0.0) \n"
+" current = min(0.2 , current); \n"
+" else \n"
+" current = min(0.2 - d * 80.0 , current); \n"
+" } \n"
+" } \n"
+" } \n"
+" return current; \n"
+"} \n"
+
+
+"void main () \n"
+"{ \n"
+" float i = 0.0; \n"
+" float j = 0.0; \n"
+" const vec3 observer = vec3( 0.5, 0.5, -2.0 ); \n"
+" vec3 reflect; \n"
+" vec3 ray_pos = observer; \n"
+" vec3 ray_vec = gl_TexCoord[0].xyz - ray_pos; \n"
+" ray_vec /= length( ray_vec ); \n"
+
+" vec4 out_color = vec4(0.0); \n"
+" vec3 contact_point = vec3(0.0); \n"
+
+" float bestt, besti; \n"
+" vec3 normal, half_vector; \n"
+" vec3 object_color; \n"
+" \n"
+" for(j = 0.0 ; j < 3.0 ; j += 1.0) \n"
+" { \n"
+" bestt = 1000.0; \n"
+" besti = -1.0; \n"
+// find out which sphere is our first intersection
+" for( i=0.0 ; i<1.0 ; i+= 1.0/%d.0) \n"
+" { \n"
+" vec4 sphere_geom = texture1D( spheres_geom, i); \n"
+" vec3 dst = ray_pos - sphere_geom.xyz; \n"
+" float a = dot (ray_vec, ray_vec); \n"
+" float b = 2.0 * dot (dst, ray_vec); \n"
+" float c = dot (dst, dst) - sphere_geom.a*sphere_geom.a; \n"
+" float d = b*b - 4.0*a*c; \n"
+" if ( d > 0.0 ) \n"
+" { \n"
+" float t1; \n"
+" t1 = (-b - sqrt(d) ) /(2.0 * a); \n"
+" if (t1 < bestt) \n"
+" { \n"
+" bestt = t1; \n"
+" besti = i; \n"
+" contact_point = ray_pos + ray_vec * t1; \n"
+" } \n"
+" } \n"
+" } \n"
+" \n"
+// if we had an intersection
+" if (besti >= 0.0) \n"
+" { \n"
+// find the local normal
+" vec4 sphere_geom = texture1D( spheres_geom, besti); \n"
+" vec3 light_vec = light_pos - contact_point; \n"
+" light_vec /= length (light_vec); \n"
+" normal = contact_point - sphere_geom.xyz; \n"
+" half_vector = (light_vec - ray_vec)/2.0; \n"
+" normal /= length(normal); \n"
+" object_color = vec3(0.2,0.4,0.8); \n"
+// compute lighting
+" float diffuse = dot (normal, light_vec) + 2.0 * pow (dot ( normal, half_vector), 32.0); \n"
+" float ambient = 0.1; \n"
+" float l = intersect(contact_point, light_vec) * (diffuse > 0.0 ? diffuse + ambient : ambient); \n"
+" out_color.rgb += 0.6 * (1.0 - out_color.a) * vec3(l) * object_color; \n"
+" out_color.a += 0.6 * (1.0 - out_color.a); \n"
+// find the reflecction vector
+" reflect = ray_vec - vec3(2.0 * dot ( normal, ray_vec)) * normal; \n"
+" reflect /= length(reflect); \n"
+// new parameters
+" ray_pos = contact_point; \n"
+" ray_vec = reflect; \n"
+" } \n"
+" else \n"
+" { \n"
+" vec3 steps1 = abs((1.0 - ray_pos)/ray_vec); \n"
+" vec3 steps2 = abs((ray_pos)/ray_vec); \n"
+" vec3 steps; \n"
+" vec2 tex_coords; \n"
+" if (ray_vec.x>0.0) \n"
+" steps.x=steps1.x; \n"
+" else \n"
+" steps.x=steps2.x; \n"
+" if (ray_vec.y>0.0) \n"
+" steps.y=steps1.y; \n"
+" else \n"
+" steps.y=steps2.y; \n"
+" if (ray_vec.z>0.0) \n"
+" steps.z=steps1.z; \n"
+" else \n"
+" steps.z=steps2.z; \n"
+" \n"
+" if ( (steps.x <= steps.y) && (steps.x <= steps.z) ) \n"
+" { \n"
+" normal = vec3(1.0, 0.0, 0.0); \n"
+" contact_point = ray_pos + ray_vec * steps.x; \n"
+" tex_coords.xy = contact_point.zy; \n"
+" } \n"
+" else if ( (steps.y <= steps.x) && (steps.y <= steps.z) ) \n"
+" { \n"
+" normal = vec3(0.0, 1.0, 0.0); \n"
+" contact_point = ray_pos + ray_vec * steps.y; \n"
+" tex_coords.xy = contact_point.xz; \n"
+" } \n"
+" else \n"
+" { \n"
+" normal = vec3(0.0, 0.0, 1.0); \n"
+" contact_point = ray_pos + ray_vec * steps.z; \n"
+" tex_coords.xy = contact_point.xy; \n"
+" } \n"
+" vec3 light_vec = light_pos - contact_point; \n"
+" light_vec /= length (light_vec); \n"
+//" half_vector = (light_vec - ray_vec)/2.0; \n"
+" float diffuse = abs(dot (normal, light_vec));"// + 4.0 * pow (dot ( normal, half_vector), 4.0); \n"
+" float ambient = 0.1; \n"
+" float l = intersect(contact_point, light_vec) * (diffuse > 0.0 ? diffuse + ambient : ambient); \n"
+" object_color = texture2D( wall_texture, vec2(tex_coords.xy)).rgb; \n"
+//" object_color = vec3(0.8,0.5,0.2); \n"
+" out_color.rgb += (1.0 - out_color.a) * vec3(l) * object_color; \n"
+" break; \n"
+" } \n"
+" } \n"
+" gl_FragColor.rgb = out_color.rgb; \n"
+"} \n"
+;
+
+int main(int argc, char* argv[])
+{
+ int i,j;
+
+ SDL_Init( SDL_INIT_EVERYTHING );
+ SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
+ SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 0 );
+ SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
+ SDL_SetVideoMode( 1024, 1024, 0, SDL_OPENGL );
+
+ GLhandleARB prog;
+ char fshader[8192];
+ sprintf(fshader, fshader_ray, BALLS, BALLS);
+ if ( !vr_glext_glsl_create_program(vshader,fshader,&prog) )
+ return 0;
+
+ // generate sphere geometry/color
+ srand(42);
+ GLuint tex_spheres_geom;
+ GLuint tex_wall;
+ float spheres_pos[4*BALLS];
+ float spheres_dir[4*BALLS];
+ for( i=0; i<BALLS; i++ )
+ {
+ spheres_pos[4*i + 0] = (rand()%1024)/1024.0;
+ spheres_pos[4*i + 1] = (rand()%1024)/1024.0;
+ spheres_pos[4*i + 2] = (rand()%1024)/1024.0;
+ spheres_pos[4*i + 3] = (rand()%256/10)/256.0+ 0.08;
+
+ float x,y,z,l;
+ x = (rand()%1024)/512.0-0.5;
+ y = (rand()%1024)/512.0-0.5;
+ z = (rand()%1024)/512.0-0.5;
+ l = sqrt( x*x + y*y + z*z );
+
+ spheres_dir[4*i + 0] = x/l;
+ spheres_dir[4*i + 1] = y/l;
+ spheres_dir[4*i + 2] = z/l;
+ }
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho(0.,1., 0.,1.,-1.0,1.0);
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+
+ unsigned char* wall=(unsigned char*)malloc(256*256*3);
+ for(i=0;i<256;i++)
+ for(j=0;j<256;j++)
+ {
+ int index = (i+j*256)*3;
+ unsigned char v = (((i/32)+(j/32))%2)*245+rand()%10;
+ wall[index + 0] = v;
+ wall[index + 1] = v;
+ wall[index + 2] = v;
+ }
+
+ glGenTextures(1,&tex_wall);
+ glActiveTextureARB(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tex_wall);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256,256, 0, GL_RGB, GL_UNSIGNED_BYTE, wall);
+ free(wall);
+
+ glActiveTextureARB(GL_TEXTURE1);
+ glEnable (GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tex_wall);
+ eglUniform1iARB(eglGetUniformLocationARB(prog, "wall_texture"),1);
+
+
+ glGenTextures(1,&tex_spheres_geom);
+
+ i=0;
+ SDL_Event event;
+ int before = SDL_GetTicks();
+ float beta = 0.0;
+ bool quit = false;
+ do
+ {
+ beta += 0.01;
+
+ eglUniform3fARB(eglGetUniformLocationARB(prog, "light_pos"),0.4, 2.0, 0.2);
+
+ for(int ii=0; ii<BALLS; ii++ )
+ {
+ float x = spheres_pos [ 4*ii + 0];
+ float y = spheres_pos [ 4*ii + 1];
+ float z = spheres_pos [ 4*ii + 2];
+ float r = spheres_pos [ 4*ii + 3];
+ float vx = spheres_dir[ 4*ii + 0];
+ float vy = spheres_dir[ 4*ii + 1];
+ float vz = spheres_dir[ 4*ii + 2];
+
+ x += vx * 0.01;
+ y += vy * 0.01;
+ z += vz * 0.01;
+
+ // handle bouncing of the ball against a wall
+ if ( (x - r < 0.0) && (vx < 0.0) )
+ vx = -vx;
+ if ( (x + r > 1.0) && (vx > 0.0) )
+ vx = -vx;
+ if ( (y - r < 0.0) && (vy < 0.0) )
+ vy = -vy;
+ if ( (y + r > 1.0) && (vy > 0.0) )
+ vy = -vy;
+ if ( (z - r < 0.0) && (vz < 0.0) )
+ vz = -vz;
+ if ( (z + r > 1.0) && (vz > 0.0) )
+ vz = -vz;
+
+ spheres_pos [ 4*ii + 0] = x;
+ spheres_pos [ 4*ii + 1] = y;
+ spheres_pos [ 4*ii + 2] = z;
+ spheres_dir[ 4*ii + 0] = vx;
+ spheres_dir[ 4*ii + 1] = vy;
+ spheres_dir[ 4*ii + 2] = vz;
+ }
+
+ eglUseProgramObjectARB(prog);
+ // upload the sphere geometry texture
+ glActiveTextureARB(GL_TEXTURE0);
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_1D);
+ glBindTexture(GL_TEXTURE_1D, tex_spheres_geom);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F_ARB, BALLS, 0, GL_RGBA, GL_FLOAT, spheres_pos);
+
+ glActiveTextureARB(GL_TEXTURE0);
+ glDisable (GL_TEXTURE_2D);
+ glEnable (GL_TEXTURE_1D);
+ glBindTexture(GL_TEXTURE_1D, tex_spheres_geom);
+ eglUniform1iARB(eglGetUniformLocationARB(prog, "spheres_geom"),0);
+
+ glActiveTextureARB(GL_TEXTURE1);
+ glEnable (GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, tex_wall);
+ eglUniform1iARB(eglGetUniformLocationARB(prog, "wall_texture"),1);
+
+
+
+ glBegin(GL_QUADS);
+ glTexCoord3f( 0.0, 0.0, 0.0);
+ glVertex2f( 0.0, 0.0);
+ glTexCoord3f( 0.0, 1.0, 0.0);
+ glVertex2f( 0.0, 1.0);
+ glTexCoord3f( 1.0, 1.0, 0.0);
+ glVertex2f( 1.0, 1.0);
+ glTexCoord3f( 1.0, 0.0, 0.0 );
+ glVertex2f( 1.0, 0.0);
+ glEnd();
+
+ SDL_GL_SwapBuffers();
+
+ i++;
+ while(SDL_PollEvent(&event)>0)
+ {
+ switch(event.type)
+ {
+ case SDL_KEYDOWN:
+ case SDL_QUIT:
+ quit = true;
+ }
+ }
+ }
+ while(!quit);
+ int after = SDL_GetTicks();
+ float time = (after-before)/1000.0;
+ printf("%.2f seconds total (avg %.2f fps)\n",time,i/time);
+
+ SDL_Quit();
+}
+