raytracer.c


SUBMITTED BY: okpalan86

DATE: May 23, 2024, 6:40 p.m.

FORMAT: C

SIZE: 7.8 kB

HITS: 312

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #define M_PI 3.14159265358979323846
  5. typedef struct {
  6. float x, y, z;
  7. } Vec3;
  8. Vec3 Vec3_create(float x, float y, float z) {
  9. Vec3 v;
  10. v.x = x;
  11. v.y = y;
  12. v.z = z;
  13. return v;
  14. }
  15. Vec3 Vec3_add(Vec3 v1, Vec3 v2) {
  16. Vec3 result;
  17. result.x = v1.x + v2.x;
  18. result.y = v1.y + v2.y;
  19. result.z = v1.z + v2.z;
  20. return result;
  21. }
  22. Vec3 Vec3_subtract(Vec3 v1, Vec3 v2) {
  23. Vec3 result;
  24. result.x = v1.x - v2.x;
  25. result.y = v1.y - v2.y;
  26. result.z = v1.z - v2.z;
  27. return result;
  28. }
  29. Vec3 Vec3_multiply(Vec3 v, float scalar) {
  30. Vec3 result;
  31. result.x = v.x * scalar;
  32. result.y = v.y * scalar;
  33. result.z = v.z * scalar;
  34. return result;
  35. }
  36. Vec3 Vec3_multiply_componentwise(Vec3 v1, Vec3 v2) {
  37. Vec3 result;
  38. result.x = v1.x * v2.x;
  39. result.y = v1.y * v2.y;
  40. result.z = v1.z * v2.z;
  41. return result;
  42. }
  43. float Vec3_dot(Vec3 v1, Vec3 v2) {
  44. return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  45. }
  46. float Vec3_length2(Vec3 v) {
  47. return v.x * v.x + v.y * v.y + v.z * v.z;
  48. }
  49. float Vec3_length(Vec3 v) {
  50. return sqrt(Vec3_length2(v));
  51. }
  52. Vec3 Vec3_normalize(Vec3 v) {
  53. float nor2 = Vec3_length2(v);
  54. if (nor2 > 0) {
  55. float invNor = 1 / sqrt(nor2);
  56. v.x *= invNor;
  57. v.y *= invNor;
  58. v.z *= invNor;
  59. }
  60. return v;
  61. }
  62. typedef struct {
  63. Vec3 center;
  64. float radius, radius2;
  65. Vec3 surfaceColor, emissionColor;
  66. float transparency, reflection;
  67. } Sphere;
  68. Sphere Sphere_create(Vec3 center, float radius, Vec3 surfaceColor, float reflection, float transparency, Vec3 emissionColor) {
  69. Sphere s;
  70. s.center = center;
  71. s.radius = radius;
  72. s.radius2 = radius * radius;
  73. s.surfaceColor = surfaceColor;
  74. s.emissionColor = emissionColor;
  75. s.transparency = transparency;
  76. s.reflection = reflection;
  77. return s;
  78. }
  79. int Sphere_intersect(Sphere s, Vec3 rayorig, Vec3 raydir, float* t0, float* t1) {
  80. Vec3 l = Vec3_subtract(s.center, rayorig);
  81. float tca = Vec3_dot(l, raydir);
  82. if (tca < 0) return 0;
  83. float d2 = Vec3_dot(l, l) - tca * tca;
  84. if (d2 > s.radius2) return 0;
  85. float thc = sqrt(s.radius2 - d2);
  86. *t0 = tca - thc;
  87. *t1 = tca + thc;
  88. return 1;
  89. }
  90. float mix(float a, float b, float mix) {
  91. return b * mix + a * (1 - mix);
  92. }
  93. Vec3 trace(Vec3 rayorig, Vec3 raydir, Sphere* spheres, int numSpheres, int depth) {
  94. float tnear = INFINITY;
  95. Sphere* sphere = NULL;
  96. for (int i = 0; i < numSpheres; ++i) {
  97. float t0 = INFINITY, t1 = INFINITY;
  98. if (Sphere_intersect(spheres[i], rayorig, raydir, &t0, &t1)) {
  99. if (t0 < 0) t0 = t1;
  100. if (t0 < tnear) {
  101. tnear = t0;
  102. sphere = &spheres[i];
  103. }
  104. }
  105. }
  106. if (!sphere) return Vec3_create(2, 2, 2);
  107. Vec3 surfaceColor = Vec3_create(0, 0, 0);
  108. Vec3 phit = Vec3_add(rayorig, Vec3_multiply(raydir, tnear));
  109. Vec3 nhit = Vec3_subtract(phit, sphere->center);
  110. nhit = Vec3_normalize(nhit);
  111. float bias = 1e-4;
  112. int inside = 0;
  113. if (Vec3_dot(raydir, nhit) > 0) {
  114. nhit = Vec3_multiply(nhit, -1);
  115. inside = 1;
  116. }
  117. if ((sphere->transparency > 0 || sphere->reflection > 0) && depth < 5) {
  118. float facingratio = -Vec3_dot(raydir, nhit);
  119. float fresneleffect = mix(pow(1 - facingratio, 3), 1, 0.1);
  120. Vec3 refldir = Vec3_subtract(raydir, Vec3_multiply(nhit, 2 * Vec3_dot(raydir, nhit)));
  121. refldir = Vec3_normalize(refldir);
  122. Vec3 reflection = trace(Vec3_add(phit, Vec3_multiply(nhit, bias)), refldir, spheres, numSpheres, depth + 1);
  123. Vec3 refraction = Vec3_create(0, 0, 0);
  124. if (sphere->transparency) {
  125. float ior = 1.1, eta = (inside) ? ior : 1 / ior;
  126. float cosi = -Vec3_dot(nhit, raydir);
  127. float k = 1 - eta * eta * (1 - cosi * cosi);
  128. Vec3 refrdir = Vec3_add(Vec3_multiply(raydir, eta), Vec3_multiply(nhit, eta * cosi - sqrt(k)));
  129. refrdir = Vec3_normalize(refrdir);
  130. refraction = trace(Vec3_subtract(phit, Vec3_multiply(nhit, bias)), refrdir, spheres, numSpheres, depth + 1);
  131. }
  132. surfaceColor = Vec3_multiply_componentwise(Vec3_add(Vec3_multiply(reflection, fresneleffect), Vec3_multiply(refraction, (1 - fresneleffect) * sphere->transparency)), sphere->surfaceColor);
  133. } else {
  134. for (int i = 0; i < numSpheres; ++i) {
  135. if (spheres[i].emissionColor.x > 0) {
  136. Vec3 transmission = Vec3_create(1, 1, 1);
  137. Vec3 lightDirection = Vec3_subtract(spheres[i].center, phit);
  138. lightDirection = Vec3_normalize(lightDirection);
  139. for (int j = 0; j < numSpheres; ++j) {
  140. if (i != j) {
  141. float t0, t1;
  142. if (Sphere_intersect(spheres[j], Vec3_add(phit, Vec3_multiply(nhit, bias)), lightDirection, &t0, &t1)) {
  143. transmission = Vec3_create(0, 0, 0);
  144. break;
  145. }
  146. }
  147. }
  148. surfaceColor = Vec3_add(surfaceColor, Vec3_multiply_componentwise(Vec3_multiply_componentwise(sphere->surfaceColor, transmission), Vec3_create(fmax(0, Vec3_dot(nhit, lightDirection)), fmax(0, Vec3_dot(nhit, lightDirection)), fmax(0, Vec3_dot(nhit, lightDirection)))));
  149. }
  150. }
  151. }
  152. return Vec3_add(surfaceColor, sphere->emissionColor);
  153. }
  154. void render(Sphere* spheres, int numSpheres) {
  155. unsigned int width = 640, height = 480;
  156. Vec3* image = (Vec3*)malloc(width * height * sizeof(Vec3));
  157. Vec3* pixel = image;
  158. float invWidth = 1 / (float)width;
  159. float invHeight = 1 / (float)height;
  160. float fov = 30;
  161. float aspectratio = width / (float)height;
  162. float angle = tan(M_PI * 0.5 * fov / 180.);
  163. for (unsigned int y = 0; y < height; ++y) {
  164. for (unsigned int x = 0; x < width; ++x, ++pixel) {
  165. float xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
  166. float yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
  167. Vec3 raydir = Vec3_create(xx, yy, -1);
  168. raydir = Vec3_normalize(raydir);
  169. *pixel = trace(Vec3_create(0, 0, 0), raydir, spheres, numSpheres, 0);
  170. }
  171. }
  172. FILE* file = fopen("untitled.ppm", "wb");
  173. fprintf(file, "P6\n%d %d\n255\n", width, height);
  174. for (unsigned int i = 0; i < width * height; ++i) {
  175. fprintf(file, "%c%c%c", (unsigned char)(fmin(1, image[i].x) * 255), (unsigned char)(fmin(1, image[i].y) * 255), (unsigned char)(fmin(1, image[i].z) * 255));
  176. }
  177. fclose(file);
  178. free(image);
  179. }
  180. int main(int argc, char** argv) {
  181. srand(13);
  182. int numSpheres = 6;
  183. Sphere* spheres = (Sphere*)malloc(numSpheres * sizeof(Sphere));
  184. spheres[0] = Sphere_create(Vec3_create(0.0, -10004, -20), 10000, Vec3_create(0.20, 0.20, 0.20), 0, 0.0, Vec3_create(0, 0, 0));
  185. spheres[1] = Sphere_create(Vec3_create(0.0, 0, -20), 4, Vec3_create(1.00, 0.32, 0.36), 1, 0.5, Vec3_create(0, 0, 0));
  186. spheres[2] = Sphere_create(Vec3_create(5.0, -1, -15), 2, Vec3_create(0.90, 0.76, 0.46), 1, 0.0, Vec3_create(0, 0, 0));
  187. spheres[3] = Sphere_create(Vec3_create(5.0, 0, -25), 3, Vec3_create(0.65, 0.77, 0.97), 1, 0.0, Vec3_create(0, 0, 0));
  188. spheres[4] = Sphere_create(Vec3_create(-5.5, 0, -15), 3, Vec3_create(0.90, 0.90, 0.90), 1, 0.0, Vec3_create(0, 0, 0));
  189. spheres[5] = Sphere_create(Vec3_create(0.0, 20, -30), 3, Vec3_create(0.00, 0.00, 0.00), 0, 0.0, Vec3_create(3, 3, 3));
  190. render(spheres, numSpheres);
  191. free(spheres);
  192. return 0;
  193. }

comments powered by Disqus