PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/raytracer.cs

https://gitlab.com/CurC/dattracer
C# | 267 lines | 223 code | 26 blank | 18 comment | 37 complexity | a564884aaa2c52c83be90dbac3ed344d MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using OpenTK;
  7. namespace Template
  8. {
  9. class Raytracer
  10. {
  11. public Camera cam { get; set; }
  12. public Scene scene { get; set; }
  13. int bounce, maxBounce = 4; // Maximum ray depth
  14. Surface screenData;
  15. bool debugRay = false;
  16. public Raytracer(Surface s)
  17. {
  18. cam = new Camera(new Vector3(0, 0, -2), 1);
  19. scene = new Scene();
  20. screenData = s;
  21. }
  22. // Stuurt een ray per pixel
  23. public void Render(ref Surface screen)
  24. {
  25. screen.Clear(0);
  26. Vector3 trace = Vector3.Zero;
  27. Ray r = new Ray(cam.Origin, cam.V);
  28. float divwidth = 1f / cam.width;
  29. float divheight = 1f / cam.height;
  30. for (float i = 0; i < cam.width; i++)
  31. {
  32. for (float j = 0; j < cam.height; j++)
  33. {
  34. debugRay = false;
  35. if ((j == cam.height / 2) && i % 10 == 0)
  36. {
  37. debugRay = true;
  38. }
  39. trace = Vector3.Zero;
  40. // Anti aliasing switch
  41. if (true)
  42. {
  43. //Supersampling x2
  44. for (float xfrag = i; xfrag < i + 1.0f; xfrag += 0.50f)
  45. {
  46. for (float yfrag = j; yfrag < j + 1.0f; yfrag += 0.50f)
  47. {
  48. bounce = 0;
  49. r.D = ((xfrag * (cam.P2 - cam.P1) * divwidth) + (yfrag * (cam.P3 - cam.P1) * divheight) + cam.P1) - r.O;
  50. trace += Trace(r, ref screen) * 0.25f;
  51. }
  52. }
  53. }
  54. else
  55. {
  56. bounce = 0;
  57. r.D = ((i * (cam.P2 - cam.P1) * divwidth) + (j * (cam.P3 - cam.P1) * divheight) + cam.P1) - r.O;
  58. trace = Trace(r, ref screen);
  59. }
  60. int location = (int) (i + j * screen.width);
  61. screen.pixels[location] = CreateColor(trace);
  62. }
  63. }
  64. // Tekent debug circles
  65. float theta = (2.0f * 3.1415926f) / 100;
  66. float t = (float)Math.Tan(theta);
  67. float rad = (float)Math.Cos(theta);
  68. for (int i = 0; i < scene.SceneObjects.Length; i++)
  69. {
  70. if (scene.SceneObjects[i].ID == "Sphere")
  71. {
  72. float x = scene.SceneObjects[i].Straal;
  73. float y = 0;
  74. for (int j = 0; j < 99; j++)
  75. {
  76. float tx = -y;
  77. float ty = x;
  78. x += tx * t;
  79. y += ty * t;
  80. x *= rad;
  81. y *= rad;
  82. float tx2 = -y;
  83. float ty2 = x;
  84. float x2 = x + tx * t;
  85. float y2 = y + ty * t;
  86. x2 *= rad;
  87. y2 *= rad;
  88. screen.Line(TX(scene.SceneObjects[i].V.X + x), TY(scene.SceneObjects[i].V.Z + y),
  89. TX(scene.SceneObjects[i].V.X + x2), TY(scene.SceneObjects[i].V.Z + y2), CreateColor(scene.SceneObjects[i].Color));
  90. }
  91. }
  92. //screen.Box(TX(scene.SceneObjects[i].V.X) - 1, TY(scene.SceneObjects[i].V.Z) - 1,
  93. //TX(scene.SceneObjects[i].V.X) + 1, TY(scene.SceneObjects[i].V.Z) + 1, CreateColor(scene.SceneObjects[i].Color));
  94. }
  95. // Camera
  96. screen.Box(TX(cam.Origin.X) - 1, TY(cam.Origin.Z) - 1, TX(cam.Origin.X) + 1, TY(cam.Origin.Z) + 1, CreateColor(255, 255, 255));
  97. screen.Line(TX(cam.P1.X), TY(cam.P1.Z), TX(cam.P2.X), TY(cam.P2.Z), CreateColor(255, 255, 255));
  98. //Licht
  99. for (int i = 0; i < scene.light.Length; i++)
  100. {
  101. screen.Box(TX(scene.light[i].pos.X) - 1, TY(scene.light[i].pos.Z) - 1,
  102. TX(scene.light[i].pos.X) + 1, TY(scene.light[i].pos.Z) + 1, CreateColor(255, 255, 0));
  103. }
  104. }
  105. // Bepaalt de kleur van een bepaalde ray door intersectie
  106. public Vector3 Trace(Ray ray, ref Surface s)
  107. {
  108. Intersection I = scene.IntersectScene(ray, float.PositiveInfinity);
  109. if (I == null)
  110. return Vector3.Zero;
  111. if (debugRay && (I.Object.ID == "Sphere" || bounce > 0))
  112. {
  113. // Normals Debug
  114. // s.Line(TX(I.Target.X), TY(I.Target.Z), TX(I.Target.X + I.Normal.X / 2), TY(I.Target.Z + I.Normal.Z / 2), CreateColor(255, 255, 255));
  115. s.Line(TX(ray.O.X), TY(ray.O.Z), TX(I.Target.X), TY(I.Target.Z), bounce > 0 ? bounce > 1 ? CreateColor(0, 255, 255) : CreateColor(255, 255, 0) : 255);
  116. }
  117. if (I.Object.IsMirror && bounce < maxBounce)
  118. {
  119. bounce++;
  120. Vector3 ReflD = Reflect(ray.D, I.Normal);
  121. return Trace(new Ray(I.Target, ReflD), ref s) * 0.00392f * Vector3.One * 255 * I.Object.Specular +
  122. (1 - I.Object.Specular) * Vector3.Clamp(DirectIllum(I, ref s), Vector3.Zero, Vector3.One) * I.Color;
  123. }
  124. else if (I.Object.IsDielectric && bounce < maxBounce)
  125. {
  126. bounce++;
  127. float f = Fresnel(ray.D, I);
  128. Vector3 Refr = Refract(ray.D, I, ref s);
  129. Vector3 Refl = Reflect(ray.D, I.Normal);
  130. return (f * Trace(new Ray(I.Target, Refl), ref s) + (1f - f) * Trace(new Ray(I.Target + 0.001f * Refr, Refr), ref s)) * I.Color;
  131. }
  132. else
  133. {
  134. return Vector3.Clamp(DirectIllum(I, ref s), Vector3.Zero, Vector3.One) * I.Color;
  135. }
  136. }
  137. public float Fresnel(Vector3 D, Intersection I)
  138. {
  139. float ior1 = Vector3.Dot(D, I.Normal) > 0 ? I.Object.IOR : 1;
  140. float ior2 = Vector3.Dot(D, I.Normal) > 0 ? 1 : I.Object.IOR;
  141. float R = (float) Math.Pow((ior1 - ior2) / (ior1 + ior2), 2);
  142. float cos = Vector3.Dot(I.Normal, -D);
  143. return (float) (R + (1 - R) * Math.Pow(1 - cos, 5));
  144. //float alpha = 0.1f;
  145. //return (float)(1f * alpha + (1 - alpha) * Math.Pow(1 - cos, 3));
  146. }
  147. // Refract een ray op basis van de index of refraction van het intersectie object
  148. public Vector3 Refract(Vector3 D, Intersection I, ref Surface s)
  149. {
  150. float ior = Vector3.Dot(D, I.Normal) > 0 ? I.Object.IOR : I.Object.rIOR;
  151. float cos = Vector3.Dot(I.Normal, -D);
  152. float k = 1 - (ior * ior) * (1 - cos * cos);
  153. if (k < 0)
  154. {
  155. return Reflect(D, I.Normal);
  156. }
  157. else
  158. {
  159. return Vector3.Normalize(ior * D + I.Normal * (ior * cos - (float) Math.Sqrt(k)));
  160. }
  161. }
  162. // Geeft een nieuwe vector op basis van een oude en een normaal
  163. public Vector3 Reflect(Vector3 D, Vector3 N)
  164. {
  165. Vector3 R = D - 2f * Vector3.Dot(D, N) * N;
  166. return Vector3.Normalize(R);
  167. }
  168. // Geeft een kleur op basis van een intersectie
  169. public Vector3 DirectIllum(Intersection I, ref Surface s)
  170. {
  171. Vector3 T = Vector3.Zero;
  172. for (int i = 0; i < scene.light.Length; i++)
  173. {
  174. Vector3 L = Vector3.Subtract(scene.light[i].pos, I.Target);
  175. float dist = L.Length;
  176. if (!isVisible(I, L, dist, ref s))
  177. {
  178. continue;
  179. }
  180. L = Vector3.Normalize(L);
  181. float attenuation = 1 / (dist * dist);
  182. float dot = Vector3.Dot(I.Normal, L);
  183. if (dot < 0)
  184. {
  185. dot = 0;
  186. }
  187. //Spotlight
  188. if (scene.light[i] is SpotLight)
  189. {
  190. float angle = Vector3.CalculateAngle(L, scene.light[i].direction);
  191. if (angle > scene.light[i].angle)
  192. {
  193. continue;
  194. }
  195. else
  196. {
  197. T += scene.light[i].color * dot * attenuation;
  198. }
  199. }
  200. else
  201. {
  202. T += scene.light[i].color * dot * attenuation;
  203. }
  204. }
  205. return T;
  206. }
  207. // Kijkt of een bepaald intersectie punt belicht is
  208. public bool isVisible(Intersection I, Vector3 L, float dist, ref Surface s)
  209. {
  210. Ray shad = new Ray(I.Target, Vector3.Normalize(L));
  211. Intersection Is = scene.IntersectScene(shad, L.Length);
  212. if (Is != null && I.Object.Specular != 1 && !I.Object.IsDielectric)
  213. {
  214. if (debugRay)
  215. {
  216. s.Line(TX(I.Target.X), TY(I.Target.Z), TX((L + I.Target).X), TY((L + I.Target).Z), CreateColor(255, 0, 0));
  217. }
  218. return false;
  219. }
  220. return true;
  221. }
  222. public int TX(float t)
  223. {
  224. int x = (int)((t + 4) * (screenData.width * 0.5f / 8f) + (screenData.width / 2));
  225. return x;
  226. }
  227. public int TY(float t)
  228. {
  229. int y = (int)((-t + 4) * (screenData.height * 1f / 8f));
  230. return y;
  231. }
  232. public static int CreateColor(int R, int G, int B)
  233. {
  234. return (R << 16) + (G << 8) + B;
  235. }
  236. public static int CreateColor(Vector3 V)
  237. {
  238. return CreateColor((int) V.X, (int) V.Y, (int) V.Z);
  239. }
  240. }
  241. }