[video member=cmuratori stream_platform=twitch stream_username=handmade_hero project=ray title="Making a Simple Raycaster" vod_platform=youtube id=pq7dV4sR7lg annotator=Miblo] [0:05][Welcome to the stream, with a few words on the new computers] [4:09][Embark on making a ray tracer, starting with a directory and build.bat] [6:17][ray.cpp: Implement Hello World!] [7:42][Build and run successfully] [8:01][Ray tracer] [9:40][ray.cpp: Introduce struct bitmap_header and a bitmap writer] [13:22][A few words on malloc()] [14:51][ray.cpp: Write colour values into memory, with a few words on our representation of this memory] [18:35][ray.cpp: Initialise a bitmap Header] [23:18][ray.cpp: Write to a file using fwrite()[ref site="cplusplus" page="fwrite" url="http://www.cplusplus.com/reference/cstdio/fwrite/"]] [29:43][ray.cpp: typedef our types] [31:17][Step through the code and try unsuccessfully to read our bitmap image] [32:58][ray.cpp: Fill in the bitmap Header[ref site=Wikipedia page="BMP file format" url=https://en.wikipedia.org/wiki/BMP_file_format]] [37:39][Run successfully, but receive find that our file is not well-formed] [38:18][Step through the code and inspect our header] [38:49][Draw a picture and save it out as a BMP file] [39:45][ray.cpp: Load reference.bmp] [40:23][Step through and inspect the header of the well-formed reference.bmp] [42:02][ray.cpp: Fix up our header to be closer to the well-formed file[ref site=Wikipedia page="BMP file format" url=https://en.wikipedia.org/wiki/BMP_file_format]] [44:29][Run and successfully read our bitmap file] [45:09][ray.cpp: Write to all pixels in the image, and succesfully view it] [45:24][ray.cpp: Add a red band to the image, to emphasise its directionality] [45:52][Run and view our image] [46:30][ray.cpp: Flip the sign of the Header.Height to draw the image from top to bottom] [47:26][ray.cpp: Introduce struct image_32, WriteImage(), GetTotalPixelSize() and AllocateImage()] [53:20][Run our program to recreate the bitmap file] [54:04][Consider the next logical step for our ray tracer] [55:11][ray.h: Pull out our types from ray.cpp and introduce structs material, plane, sphere and world] [1:00:15][ray.cpp: Initialise a world and two materials] [1:03:19][ray_math.h: Pull in structs v2, v3 and v4 from handmade_platform.h, and various functions from handmade_math.h] [1:09:58][ray.cpp: Determine to initialise a plane] [1:10:51][Blackboard: Defining planes, using the inner product] [1:15:03][ray.cpp: Define a plane] [1:15:29][ray.cpp: Introduce the notion of a camera] [1:17:51][Blackboard: Camera axis coordinate system] [1:18:57][ray.cpp: Continue to define the camera] [1:21:35][Step through and inspect the camera values] [1:23:04][ray.cpp: Hard set the CameraZ to 0, 1, 0 and step through to inspect the other axes] [1:24:03][Blackboard: 3D coordinate system, following the right-hand rule] [1:27:37][ray.cpp: Correctly define the camera axes] [1:28:25][Step through and inspect the camera values] [1:28:53][Blackboard: Shooting rays through a plane] [1:30:42][ray.cpp: Convert our pixel positions to ratios across a film plane] [1:34:58][ray.cpp: Shoot rays at our film] [1:37:28][ray.cpp: Introduce RayCast(), testing first that it outputs the colours we expect] [1:40:06][Blackboard: Ray hit detection] [1:41:02][ray.cpp: Continue to implement RayCast()] [1:44:28][Blackboard: Ray intersection] [1:48:02][ray.cpp: Compute our intersection distance] [1:48:48][Blackboard: Parallel ray and plane] [1:49:49][ray.cpp: Make RayCast() test the Denominator against our Tolerance value] [1:50:52][build.bat: Automatically open the image after building] [1:52:22][Build, see our image and check that we are producing what we expect] [1:54:20][Blackboard: Double-check our equations] [1:56:47][ray.cpp: Set one material colour to grey, consider that we are exactly backwards and investigate why] [1:59:05][Blackboard: Camera coordinates] [1:59:32][Continue to investigate our inversion bug] [2:03:27][Blackboard: Producing camera coordinates] [2:04:18][ray.cpp: Set CameraX by crossing 0, 0, 1 and CameraZ the other way] [2:05:20][View our correct image] [2:05:38][ray.cpp: Add a sphere] [2:08:01][ray.cpp: Enable RayCast() to handle spheres] [2:08:48][Blackboard: Sphere Intersection[ref site="Wikipedia" page="Quadratic equation" url="https://en.wikipedia.org/wiki/Quadratic_equation"]] [2:16:10][ray.cpp: Enable RayCast() to compute the nearest sphere interesection point] [2:23:14][Run and view our image] [2:23:36][Blackboard: Sphere origin] [2:24:40][ray.cpp: Make RayCast() correctly account for the sphere origin] [2:27:05][ray.cpp: Correctly compute FilmX] [2:27:30][ray.cpp: Handle the aspect ratio] [2:30:11][Blackboard: Aspect ratio] [2:30:42][View our image in the correct aspect] [2:31:42][ray.cpp: Output stats] [2:32:47][Run our program in the console to see our stats] [2:34:48][ray.cpp: Enable RayCast() to cast multiple rays from different origins] [2:45:05][ray.h: Change the material struct to contain EmitColor and RefColor] [2:46:17][ray.cpp: Enable RayCast() to use both of those material colours] [2:47:22][Blackboard: Attenuating angles] [2:48:30][ray.cpp: Make RayCast() attenuate ray angles to correctly propagate light back to the camera] [2:51:53][View our scene] [2:53:25][Blackboard: Surface reflectance] [2:56:18][ray.h: Add Specular to the material struct] [2:56:46][Blackboard: Reflecting a vector] [2:57:28][ray.cpp: Enable RayCast() to bounce rays randomly (but not unbiased) around the scene, renaming Specular to Scatter] [3:01:22][ray.cpp: Introduce RandomUnilateral() and RandomBilateral()] [3:03:35][View our image, and see black dots around the scene] [3:04:45][ray.cpp: Set RayDirection to PureBounce, and correctly set the NextOrigin] [3:06:10][View our image, consider that it's not quite right and investigate why] [3:07:32][ray.cpp: Correctly set PureBounce and NextNormal] [3:09:57][View our image and consider that the sphere may be below the plane] [3:12:09][ray.cpp: Make RayCast() use the RandomBounce, and view our image] [3:13:25][ray.cpp: Enable RayCast() to cast multiple rays per pixel] [3:14:50][Blackboard: Angular attenuation] [3:15:15][ray.cpp: Enable RayCast() to account for cosine attenuation] [3:17:32][View the image, and consider that it's sort of correct] [3:17:48][ray.cpp: Toggle off the cosine attenuation in RayCast()] [3:18:24][ray.cpp: Add more spheres and materials] [3:21:12][View our image, with spheres reflecting light] [3:22:34][ray.cpp: Handle gamma correct sRGB] [3:23:41][View our gamma correct image] [3:24:08][ray.cpp: Introduce ExactLinearTosRGB()[ref site="Jason Summers's web site" page="A close look at the sRGB formula" url="http://entropymine.com/imageworsener/srgbformula/"]] [3:28:32][ray_math.h: Introduce Pow()] [3:28:54][View our apparently correct sRGB image] [3:29:44][ray.cpp: Add a fourth sphere] [3:30:36][View our image] [3:31:13][ray.cpp: Re-enable RayCast() to perform cosine attenuation, and turn the red sphere into an emitter] [3:32:57][View our image and consider further developments] [3:34:30][ray.cpp: Compute the RayOrigin and RayDirection every time, to facilitate anti-aliasing at higher sampling rates] [3:35:14][View the aliasing where the spheres meet the planes] [3:35:46][ray.cpp: Jitter the ray direction] [3:37:33][View the image with less and less aliasing as the RaysPerPixel increases] [3:38:41][Consider optimisations] [3:39:25][Q&A][:speech] [3:39:50][@mapem_87][Is this series for total beginners in game programming?] [3:40:19][@Kknewkles][Is it possible, or how hard is it, to have a debug system built-into your project that completely eliminates the need for a dedicated side debugger?] [3:40:51][@macielda][Your mic is bouncing on the metal ring on your hood] [3:41:13][@byteblind][So I just saw an old video where it says "Project will go at least until 2016". How far along towards the end are you?] [3:42:02][@drive137][Is this going to be uploaded with the normal Handmade Hero code as well?] [3:42:11][@bestalloys][Bug in the denominator check] [3:42:30][ray.cpp: Fix Denom check] [3:43:22][@bestalloys][Shouldn't you initialize your materials so EmitColor and RefColor are initialized?] [3:43:41][@desuused][Maybe instead of reinventing BRDF (what you call reflectance), use some well-known BRDF, like Disney's? You can look at the implementation of one in e.g. Blender] [3:44:11][@genos3][Could we use ray casting to determine a scene in real time that would allow infinite visibility, like with sparse voxel octree as opposed to a rasterizer?] [3:45:39][@Miblo][Whatever happened to owlbot?] [3:45:44][@siltnamis][why not use std::thread?] [3:45:51][@pythor][Is it just a coincidence that three of the spheres all have their top / bottom line up almost exactly on the horizon? Or is that an artifact of something we're doing?] [3:46:16][@sirslani][Could you just insert pragma omp on the raycaster loop?] [3:46:36][@flyingsolomon][Could you disable windows bells? I hate these sounds] [3:47:04][@macielda][The anti-alias has "roping" artifacts. Why?] [3:48:06][View the anti-aliasing of the image in Paint] [3:49:24][@bouke285][Will the growing popularity of multi-threading make procedural programming harder?] [3:50:08][@bestalloys][Can you make one of the spheres a mirror?] [3:50:23][ray.cpp: Create a mirror ball] [3:52:00][@bluebooger][Is this source code included with $15 for Handmade Hero source?] [3:52:30][@hoshoyo][Materials\[6\] should be 7 now] [3:53:18][@sir_pinecone][Can you share the question prompter code too? I missed some of the stream and would like to see it] [3:53:43][@genos3][I meant before if we could use traditional ray casting like Wolfenstein used to determine mesh visibility in the distance just using diffuse lighting] [3:54:15][View our mirror ball] [3:54:33][That's it, with plans for the future of our raycaster][:speech] [3:58:20][Recommend Physically Based Rendering[ref site="Matt Pharr and Greg Humphreys" page="Physically Based Rendering" url="http://pbrt.org/"]][:research] [3:59:39][Plug @Miblo's Patreon[ref site="Patreon" page="Matt Mascarenhas is creating Annotations for the Handmade.Network" url="https://www.patreon.com/miblo"]][:research] [/video]