vsraytrace.c revision 32001f49
1/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8-unix -*- */ 2/* 3 Copyright (c) 2010 Kristóf Ralovich 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to deal 7 in the Software without restriction, including without limitation the rights 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 copies of the Software, and to permit persons to whom the Software is 10 furnished to do so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 THE SOFTWARE. 22*/ 23 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <GL/glew.h> 28#include "glut_wrap.h" 29#include "shaderutil.h" 30#include <math.h> 31 32static int Win; 33static int WinWidth = 256, WinHeight = 256; 34static GLboolean mouseGrabbed = GL_FALSE; 35static GLuint vertShader; 36static GLuint program; 37float rot[9] = {1,0,0, 0,1,0, 0,0,1}; 38 39static const char* vsSource = 40 "const float INF = 9999.9; \n" 41 "const float EPSILON = 0.00001; \n" 42 "const vec3 lightPos = vec3(0.0, 8.0, 1.0); \n" 43 "const vec4 backgroundColor = vec4(0.2,0.3,0.4,1); \n" 44 " \n" 45 "uniform mat3 rot; \n" 46 " \n" 47 "struct Ray \n" 48 "{ \n" 49 "vec3 orig; \n" 50 "vec3 dir; \n" 51 "}; \n" 52 " \n" 53 "struct Sphere \n" 54 "{ \n" 55 " vec3 c; \n" 56 " float r; \n" 57 "}; \n" 58 " \n" 59 "struct Isec \n" 60 "{ \n" 61 " float t; \n" 62 " int idx; \n" 63 " vec3 hit; \n" 64 " vec3 n; \n" 65 "}; \n" 66 " \n" 67#ifdef __APPLE__ 68 "Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n" 69 "Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n" 70 "Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n" 71 "Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n" 72#else 73 "const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n" 74 "const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n" 75 "const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n" 76 "const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n" 77#endif 78 " \n" 79 "// Mesa intel gen4 generates \"unsupported IR in fragment shader 13\" for\n" 80 "// sqrt, let's work around. \n" 81 "float \n" 82 "sqrt_hack(float f2) \n" 83 "{ \n" 84 " vec3 v = vec3(f2,0.0,0.0); \n" 85 " return length(v); \n" 86 "} \n" 87 " \n" 88 "void \n" 89 "intersect(const in Ray ray, \n" 90 " const in Sphere sph, \n" 91 " const in int idx, \n" 92 " inout Isec isec) \n" 93 "{ \n" 94 " // Project both o and the sphere to the plane perpendicular to d \n" 95 " // and containing c. Let x be the point where the ray intersects \n" 96 " // the plane. If |x-c| < r, the ray intersects the sphere. \n" 97 " vec3 o = ray.orig; \n" 98 " vec3 d = ray.dir; \n" 99 " vec3 n = -d; \n" 100 " vec3 c = sph.c; \n" 101 " float r = sph.r; \n" 102 " float t = dot(c-o,n)/dot(n,d); \n" 103 " vec3 x = o+d*t; \n" 104 " float e = length(x-c); \n" 105 " if(e > r) \n" 106 " { \n" 107 " // no intersection \n" 108 " return; \n" 109 " } \n" 110 " \n" 111 " // Apply Pythagorean theorem on the (intersection,x,c) triangle \n" 112 " // to get the distance between c and the intersection. \n" 113 "#define BUGGY_INTEL_GEN4_GLSL 1 \n" 114 "#ifndef BUGGY_INTEL_GEN4_GLSL \n" 115 " float f = sqrt(r*r - e*e); \n" 116 "#else \n" 117 " float f = sqrt_hack(r*r - e*e); \n" 118 "#endif \n" 119 " float dist = t - f; \n" 120 " if(dist < 0.0) \n" 121 " { \n" 122 " // inside the sphere \n" 123 " return; \n" 124 " } \n" 125 " \n" 126 " if(dist < EPSILON) \n" 127 " return; \n" 128 " \n" 129 " if(dist > isec.t) \n" 130 " return; \n" 131 " \n" 132 " isec.t = dist; \n" 133 " isec.idx = idx; \n" 134 " \n" 135 " isec.hit = ray.orig + ray.dir * isec.t; \n" 136 " isec.n = (isec.hit - c) / r; \n" 137 "} \n" 138 " \n" 139 "Isec \n" 140 "intersect(const in Ray ray, \n" 141 " const in float max_t /*= INF*/) \n" 142 "{ \n" 143 " Isec nearest; \n" 144 " nearest.t = max_t; \n" 145 " nearest.idx = -1; \n" 146 " \n" 147 " intersect(ray, spheres0, 0, nearest); \n" 148 " intersect(ray, spheres1, 1, nearest); \n" 149 " intersect(ray, spheres2, 2, nearest); \n" 150 " intersect(ray, spheres3, 3, nearest); \n" 151 " \n" 152 " return nearest; \n" 153 "} \n" 154 " \n" 155 "vec4 \n" 156 "idx2color(const in int idx) \n" 157 "{ \n" 158 " vec4 diff; \n" 159 " if(idx == 0) \n" 160 " diff = vec4(1.0, 0.0, 0.0, 0.0); \n" 161 " else if(idx == 1) \n" 162 " diff = vec4(0.0, 1.0, 0.0, 0.0); \n" 163 " else if(idx == 2) \n" 164 " diff = vec4(0.0, 0.0, 1.0, 0.0); \n" 165 " else if(idx == 3) \n" 166 " diff = vec4(1.0, 1.0, 0.0, 0.0); \n" 167 " return diff; \n" 168 "} \n" 169 " \n" 170 "vec4 \n" 171 "trace0(const in Ray ray) \n" 172 "{ \n" 173 " Isec isec = intersect(ray, INF); \n" 174 " \n" 175 " if(isec.idx == -1) \n" 176 " { \n" 177 " return backgroundColor; \n" 178 " } \n" 179 " \n" 180 " vec4 diff = idx2color(isec.idx); \n" 181 " \n" 182 " vec3 N = isec.n; \n" 183 " vec3 L = normalize(lightPos-isec.hit); \n" 184 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n" 185 " return dot(N,L)*diff + pow( \n" 186 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n" 187 "} \n" 188 " \n" 189 "vec4 \n" 190 "trace1(const in Ray ray) \n" 191 "{ \n" 192 " Isec isec = intersect(ray, INF); \n" 193 " \n" 194 " if(isec.idx == -1) \n" 195 " { \n" 196 " return backgroundColor; \n" 197 " } \n" 198 " \n" 199 " Ray reflRay = Ray(isec.hit, reflect(ray.dir, isec.n)); \n" 200 " \n" 201 " vec4 reflCol = trace0(reflRay); \n" 202 " \n" 203 " vec4 diff = idx2color(isec.idx) + reflCol; \n" 204 " \n" 205 " vec3 N = isec.n; \n" 206 " vec3 L = normalize(lightPos-isec.hit); \n" 207 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n" 208 " return dot(N,L)*diff + pow( \n" 209 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n" 210 "} \n" 211 " \n" 212 "void main() \n" 213 "{ \n" 214 " const vec3 cameraPos = vec3(0,0,3); \n" 215 " vec3 rayDir = normalize(vec3(gl_Vertex.x, gl_Vertex.y, -1.0) * rot);\n" 216 " Ray ray = Ray(cameraPos, rayDir); \n" 217 " gl_Position = gl_Vertex; \n" 218 " gl_FrontColor = trace1(ray); \n" 219 "}\n"; 220 221 222static 223float 224deg2rad(const float degree) 225{ 226 return( degree * 0.017453292519943295769236907684886F); 227} 228 229static void 230rotate_xy(float* mat3, const float degreesAroundX, const float degreesAroundY) 231{ 232 const float radX = deg2rad(degreesAroundX); 233 const float c1 = cosf(radX); 234 const float s1 = sinf(radX); 235 const float radY = deg2rad(degreesAroundY); 236 const float c2 = cosf(radY); 237 const float s2 = sinf(radY); 238 mat3[0] = c2; mat3[3] = 0.0F; mat3[6] = s2; 239 mat3[1] = s1*s2; mat3[4] = c1; mat3[7] = -s1*c2; 240 mat3[2] = -c1*s2;mat3[5] = s1; mat3[8] = c1*c2; 241} 242 243static void 244identity(float* mat3) 245{ 246 mat3[0] = 1.0F; mat3[3] = 0.0F; mat3[6] = 0.0F; 247 mat3[1] = 0.0F; mat3[4] = 1.0F; mat3[7] = 0.0F; 248 mat3[2] = 0.0F; mat3[5] = 0.0F; mat3[8] = 1.0F; 249} 250 251static void 252Draw(void) 253{ 254 const float w = 0.5F * WinWidth; 255 const float h = 0.5F * WinHeight; 256 int x,y; 257 258 GLint location = glGetUniformLocation(program, "rot"); 259 260 glUseProgram(program); 261 glUniformMatrix3fv(location, 1, 0, rot); 262 glBegin(GL_POINTS); 263 for(y = 0; y < WinHeight; y++) 264 { 265 for(x = 0; x < WinWidth; x++) 266 { 267 const float posx = x / w - 1.0F; 268 const float posy = y / h - 1.0F; 269 glVertex2f(posx, posy); 270 } 271 } 272 glEnd(); 273 glUseProgram(0); 274 275 glutSwapBuffers(); 276 277 { 278 static int frames = 0; 279 static int t0 = 0; 280 static int t1 = 0; 281 float dt; 282 frames++; 283 t1 = glutGet(GLUT_ELAPSED_TIME); 284 dt = (float)(t1-t0)/1000.0F; 285 if (dt >= 5.0F) 286 { 287 float fps = (float)frames / dt; 288 printf("%f FPS (%d frames in %f seconds)\n", fps, frames, dt); 289 frames = 0; 290 t0 = t1; 291 } 292 } 293} 294 295 296static void 297Reshape(int width, int height) 298{ 299 WinWidth = width; 300 WinHeight = height; 301 glViewport(0, 0, width, height); 302 glMatrixMode(GL_PROJECTION); 303 glLoadIdentity(); 304 glMatrixMode(GL_MODELVIEW); 305 glLoadIdentity(); 306} 307 308 309static void 310Key(unsigned char key, int x, int y) 311{ 312 if(key == 27) 313 { 314 glutDestroyWindow(Win); 315 exit(0); 316 } 317 glutPostRedisplay(); 318} 319 320 321static 322void 323drag(int x, int y) 324{ 325 float scale = 1.5F; 326 if(mouseGrabbed) 327 { 328 static GLfloat xRot = 0, yRot = 0; 329 xRot = (float)(x - WinWidth/2) / scale; 330 yRot = (float)(y - WinHeight/2) / scale; 331 identity(rot); 332 rotate_xy(rot, yRot, xRot); 333 glutPostRedisplay(); 334 } 335} 336 337 338static 339void 340mouse(int button, int state, int x, int y) 341{ 342 mouseGrabbed = (state == GLUT_DOWN); 343} 344 345 346static void 347Init(void) 348{ 349 glDisable(GL_DEPTH_TEST); 350 351 if(!ShadersSupported()) 352 { 353 fprintf(stderr, "Shaders are not supported!\n"); 354 exit(-1); 355 } 356 357 vertShader = CompileShaderText(GL_VERTEX_SHADER, vsSource); 358 program = LinkShaders(vertShader, 0); 359 glUseProgram(0); 360 361 if(glGetError() != 0) 362 { 363 fprintf(stderr, "Shaders were not loaded!\n"); 364 exit(-1); 365 } 366 367 if(!glIsShader(vertShader)) 368 { 369 fprintf(stderr, "Vertex shader failed!\n"); 370 exit(-1); 371 } 372 373 if(!glIsProgram(program)) 374 { 375 fprintf(stderr, "Shader program failed!\n"); 376 exit(-1); 377 } 378 379 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 380} 381 382 383int 384main(int argc, char *argv[]) 385{ 386 glutInitWindowSize(WinWidth, WinHeight); 387 glutInit(&argc, argv); 388 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 389 Win = glutCreateWindow(argv[0]); 390 glewInit(); 391 glutReshapeFunc(Reshape); 392 glutKeyboardFunc(Key); 393 glutDisplayFunc(Draw); 394 glutIdleFunc(Draw); 395 glutMouseFunc(mouse); 396 glutMotionFunc(drag); 397 Init(); 398 glutMainLoop(); 399 return 0; 400} 401 402