{"id":6,"date":"2025-11-01T20:45:05","date_gmt":"2025-11-01T20:45:05","guid":{"rendered":"https:\/\/blog.metu.edu.tr\/e217202\/?p=6"},"modified":"2025-11-01T20:45:55","modified_gmt":"2025-11-01T20:45:55","slug":"hw1-blog","status":"publish","type":"post","link":"https:\/\/blog.metu.edu.tr\/e217202\/2025\/11\/01\/hw1-blog\/","title":{"rendered":"Hw1 Blog"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">I wanted to be able to see my progress as I write the code, so I decided to start by implementing the simplest renderer possible that would let me somewhat see what&#8217;s going on in the see. Firstly, I wrote the parser. Once everything was successfully loaded from the .json, I computed the necessary vectors and coordinates(m, u, v, q etc.) to get the ray equations. Secondly, I loaded the vertices and the shapes. After the shapes were loaded, I wrote the hitRay functions for each shape, so that I can calculate ray-shape intersections. I shaded every ray that hit an object fully white, which let me finally see some results.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim.png\" alt=\"\" class=\"wp-image-8\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">simple.png<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"512\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-1.png\" alt=\"\" class=\"wp-image-9\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-1.png 512w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-1-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-1-150x150.png 150w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><figcaption class=\"wp-element-caption\">bunny.png<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It was relatively straightforward to implement ambient shading since all I had to do was a single multiplication:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-2.png\" alt=\"\" class=\"wp-image-10\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-2.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-2-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-2-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-2-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cornellbox.png ambient<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Coding diffuse shading was the next step. On intersections, I looped through point lights and calculated the diffuse values and added them to the already calculated ambient values.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"720\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-3.png\" alt=\"\" class=\"wp-image-11\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-3.png 720w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-3-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-3-150x150.png 150w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><figcaption class=\"wp-element-caption\">spheres.png diffuse<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">While I had made good progress, I also realized that my objects were coming out horizontally stretched. After some debugging, I found that this was happening because I forgot to normalize u before using it in calculations.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"720\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-4.png\" alt=\"\" class=\"wp-image-12\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-4.png 720w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-4-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-4-150x150.png 150w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><figcaption class=\"wp-element-caption\">spheres.png with normalized u<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Adding specular lighting wasn&#8217;t much different that adding diffuse lighting, I just added in the phong shading values to the loop I previously mentioned.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"720\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-5.png\" alt=\"\" class=\"wp-image-13\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-5.png 720w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-5-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-5-150x150.png 150w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><figcaption class=\"wp-element-caption\">spheres.png with specular lighting<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">It was time to implement mirror materials now. On intersections with such materials, I recursively shot new rays in the reflection direction, with an origin moved a bit along the surface normal, until maximum recursion depth was reached.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"720\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-6.png\" alt=\"\" class=\"wp-image-14\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-6.png 720w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-6-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-6-150x150.png 150w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><figcaption class=\"wp-element-caption\">spheres_mirror.png after implementing mirror<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The next type of material to implement was conductors. This was extremely similar to shading mirror objects. I just had to calculate reflection ratio alongside with the reflected ray&#8217;s shading.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-7.png\" alt=\"\" class=\"wp-image-15\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-7.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-7-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-7-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-7-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cornellbox_recursive.png with conductors<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Implementing dielectrics proved to be the most tricky. I first coded the reflected component of dielectrics.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-8.png\" alt=\"\" class=\"wp-image-16\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-8.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-8-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-8-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-8-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cornellbox_recursive.png with reflected dielectrics<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Adding in the refracted light however, was not so simple. I kept getting nonsensical results even though I was sure that my transmission ratio was correct.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-9.png\" alt=\"\" class=\"wp-image-17\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-9.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-9-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-9-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-9-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cornellbox_recursive.png with errorneus dielectric refractions<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">After debugging and reading lecture slides for a good while, I realized that this was happening because I did not handle the rays traveling within dielectrics correctly. Namely, I needed to flip the surface normals before shading them.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-10.png\" alt=\"\" class=\"wp-image-18\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-10.png 800w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-10-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-10-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-10-768x768.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">cornellbox_recursive.png with dielectrics<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">My last step was to implement smoothly shaded meshes. I calculated vertex normals according to the formulas, but I just kept getting images that were pretty much identical to flatly shaded ones.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-11.png\" alt=\"\" class=\"wp-image-19\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-11.png 1024w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-11-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-11-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-11-768x768.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">low_poly_scene_smooth.png with incorrect smooth shading<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">My error here was calculating vertex normals seperately for each individual mesh when I needed to calculate vertex normals by just looking at the vertices themselves, without considering the meshes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-12.png\" alt=\"\" class=\"wp-image-20\" srcset=\"https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-12.png 1024w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-12-300x300.png 300w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-12-150x150.png 150w, https:\/\/blog.metu.edu.tr\/e217202\/files\/2025\/11\/resim-12-768x768.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">low_poly_scene_smooth.png smoothly shaded<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">With this, I was pretty much done. I wrote a Makefile to build the binary and tested it on ineks then submitted my code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to be able to see my progress as I write the code, so I decided to start by implementing the simplest renderer possible that would let me somewhat see what&#8217;s going on in the see. Firstly, I wrote the parser. Once everything was successfully loaded from the .json, I computed the necessary vectors [&hellip;]<\/p>\n","protected":false},"author":9477,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[],"class_list":["post-6","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/posts\/6","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/users\/9477"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/comments?post=6"}],"version-history":[{"count":0,"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/posts\/6\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/media?parent=6"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/categories?post=6"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e217202\/wp-json\/wp\/v2\/tags?post=6"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}