diff options
author | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-07-12 16:11:09 +0200 |
---|---|---|
committer | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-07-12 16:11:09 +0200 |
commit | a3f015419eb737c6095d88f686312124a86ea74e (patch) | |
tree | 0e0e0e74240c2dbfee41f0864af814f57939e6c0 /raytrace.cpp |
Import.
Diffstat (limited to 'raytrace.cpp')
-rw-r--r-- | raytrace.cpp | 458 |
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(); +} + |