[video output=day584 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Enabling Infinite-Bounce Lighting" vod_platform=youtube id=gCZL4SWJYAI annotator=Miblo]
[0:02][Recap and set the stage for the day][:speech]
[1:13][Describe the problem with black gaps in the light map][:lighting :run]
[1:57][Describe the indexing discrepancy between BuildDiffuseLightMaps() and ComputeLightPropagationWork()][:lighting :research]
[4:36][Fix ComputeLightPropagationWork() to look up into the light map correctly][:lighting]
[5:17][See the correct :lighting of our world, but not of the hero, and the misaligned simulation region][:run]
[8:32][Determine to enable infinite-bounce :lighting][:run]
[9:15][Switch to TEST_SPHERE in ComputeLightPropagationWork()][:lighting]
[9:29][Check out our sphere fall-off :lighting][:run]
[10:36][Let CompileZBiasProgram() clamp the light to brighter values][:lighting]
[11:51][Check out our brighter :lighting][:run]
[12:23][Let CompileZBiasProgram() clamp the light to further brighter values][:lighting]
[12:28][Check out our brighter :lighting with the determination to enable bounce lighting][:run]
[13:56][Toggle off TEST_SPHERE in ComputeLightPropagationWork() and fix it to pass Work to FullCast()][:lighting]
[14:43][Check out our full bright, slower ray-cast :lighting][:run]
[16:33][Prepare to enable distributive ray-casting in FullCast()][:lighting :research]
[17:22][Blank out the MoonColor in FullCast()][:lighting]
[17:42][See no difference, except that the light map appears to be accumulating to full brightness][:lighting :run]
[17:57][Consult the casting code in FullCast()][:lighting :research]
[19:14][Prevent FullCast() from biasing towards the light source][:lighting]
[19:36][Check out our :lighting without biasing towards the light source][:run]
[19:42][Correctly prevent FullCast() from biasing towards the light source][:lighting]
[20:00][Check out our :lighting without biasing towards the light source][:run]
[20:15][Try blanking out the TransferPPS in FullCast()][:lighting]
[21:15][See a black world][:lighting :run]
[21:18][Try setting a TransferPPS of a quarter full bright white in FullCast()][:lighting]
[21:30][Check out our lit world, noting that the high brightness of the light][:lighting :run]
[23:03][Switch to TEST_CAST in ComputeLightPropagationWork()][:lighting]
[23:51][Check out our test cast :lighting][:run]
[23:57][Try making TestCast() output a known grey light][:lighting]
[24:19][See the light fade][:lighting :run]
[24:27][Try making TestCast() call UpdateVoxel() many times][:lighting]
[24:30][See no difference][:lighting :run]
[24:36][Remove the multiple calls to UpdateVoxel() in TestCast(), and toggle off TEST_CAST in ComputeLightPropagationWork()][:lighting]
[25:08][See our bright light][:lighting :run]
[25:14][Consider the problem to be in pulling light from multiple octahedral offsets][:lighting :research]
[26:39][Check BuildDiffuseLightMaps() for possible bugs][:lighting :research]
[28:17][Break in to FullCast() and inspect the DiffuseWeightMap][:lighting :run]
[31:35][Diffuse Map :Filtering][:blackboard :lighting]
[35:39][Directional reflection bounce][:blackboard :lighting]
[39:37][Consider BuildDiffuseLightMaps() to be handling bounce direction correctly][:lighting :research]
[40:23][See if CompileZBiasProgram() samples light based on its direction][:lighting :research :sampling]
[43:00][Diffuse :sampling of cosine-weighted directional light][:blackboard :lighting]
[48:56][Make SumLight() in CompileZBiasProgram() just use the surface normal as the reflection vector when :sampling Lambertian (ideally diffuse) surfaces][:lighting]
[50:23][Switch to TEST_CAST in ComputeLightPropagationWork()][:lighting]
[50:42][See our darkly lit world][:lighting :run]
[50:45][Prevent TestCast() from outputting a known grey light][:lighting]
[50:59][Check out the test ray cast :lighting][:run]
[51:15][Switch to TEST_SPHERE in ComputeLightPropagationWork()][:lighting]
[51:25][Check out the correct sphere light][:lighting :run]
[52:34][Toggle off TEST_SPHERE in ComputeLightPropagationWork()][:lighting]
[53:00][Check out the full ray cast :lighting, wondering where falloff comes into it][:run]
[53:40][Reduce the TransferPPS from ×0.25f to ×0.1f in FullCast()][:lighting]
[53:54][See the dimmer light][:lighting :run]
[53:58][Further reduce the TransferPPS from ×0.1f to ×0.01f in FullCast()][:lighting]
[54:01][See the unlit world, despite the light map containing non-zero values][:lighting :run]
[54:32][Increase the TransferPPS from ×0.01f to ×0.02f in FullCast()][:lighting]
[54:38][See the world lighten, and recall that we clamp the :lighting down][:run]
[54:48][Further increase the TransferPPS from ×0.02f to ×0.03f in FullCast()][:lighting]
[54:50][Consider our :lighting transfer clamping to be okay][:run]
[55:05][Prevent FullCast() from post-modifying the TransferPPS, and try commenting out the ray hit computations][:lighting]
[55:55][See no :lighting][:run]
[56:06][Prevent FullCast() from blanking out the MoonColor][:lighting]
[56:21][Check out the moonlit world][:lighting :run]
[56:46][Scrutinise the moonlighting code in FullCast()][:lighting :research]
[58:03][Negate the EmissionDirection in the TransferPPS computation for the moon in FullCast()][:lighting]
[58:18][See more expected moonlight][:lighting :run]
[58:25][Respecify MoonP as MoonDir in FullCast()][:lighting]
[1:00:17][Check out our slowly moonlit world][:lighting :run]
[1:00:35][Darken the moon from ×3 to ×1 in FullCast()][:lighting]
[1:00:43][Watch the moonlight darken][:lighting :run]
[1:00:48][Further darken the moon from ×1 to ×0.2 in FullCast()][:lighting]
[1:00:57][Watch the moonlight darken further][:lighting :run]
[1:01:22][Further darken the moon from ×0.2 to ×0.1 in FullCast()][:lighting]
[1:01:28][Watch the moonlight darken further, and spot a shadow cast by our (unlit) light sources][:lighting :run]
[1:02:04][Work on the handling of ray cast bounces in FullCast(), respecifying ComputeVoxelIrradianceAt() to take an Outgoing vector][:lighting]
[1:07:14][Watch the light emerge with style (exploding to bright, before settling)][:lighting :run]
[1:07:39][Wonder why we are getting more light than expected][:lighting :research]
[1:09:09][Try making ComputeVoxelIrradianceAt() produce a known value][:lighting]
[1:09:29][See :lighting, without the over-brightness][:run]
[1:11:00][Blank out the MoonColor in FullCast()][:lighting]
[1:11:11][See the single-bounce :lighting][:run]
[1:11:55][Prevent FullCast() from blanking out the MoonColor][:lighting]
[1:12:00][Consider our :lighting to look right][:run]
[1:12:04][Scrutinise ComputeVoxelIrradianceAt()][:lighting :research]
[1:14:55][Try making CompileZBiasProgram() reduce the VoxUVW by half, in line with ComputeVoxelIrradianceAt()][:lighting]
[1:15:07][See the light disappear completely][:lighting :run]
[1:15:11][Revert VoxUVW and try making CompileZBiasProgram() reduce the VoxR by half][:lighting]
[1:15:44][See that the light is now centred properly, and the moonlight cannot reach downstairs][:lighting :run]
[1:17:06][Continue to scrutinise ComputeVoxelIrradianceAt()][:lighting :research]
[1:18:20][Try making ComputeVoxelIrradianceAt() reduce the real result by ×0.01f][:lighting]
[1:18:36][Watch the light emerge again with style (exploding to bright)][:lighting :run]
[1:18:42][Try making ComputeVoxelIrradianceAt() further reduce the real result from ×0.01f to ×0.001f][:lighting]
[1:18:55][See the light hover without exploding][:lighting :run]
[1:19:02][Try making ComputeVoxelIrradianceAt() increase the real result from ×0.001f to ×0.002f][:lighting]
[1:19:09][Watch the light slowly explode][:lighting :run]
[1:19:49][Try making ComputeVoxelIrradianceAt() decrease the real result from ×0.002f to ×0.0015f][:lighting]
[1:20:02][Watch the light slowly explode][:lighting :run]
[1:20:24][Try making ComputeVoxelIrradianceAt() decrease the real result from ×0.0015f to ×0.00125f][:lighting]
[1:20:32][Watch the light explode a little][:lighting :run]
[1:20:47][Conceptualising photons per second][:lighting :research]
[1:22:27][Assert in FullCast() that Emission is <= 1.0f][:lighting]
[1:22:46][Happily fail to hit that Emission <= 1.0f assertion in FullCast()][:lighting :run]
[1:22:58][Remove that Emission <= 1.0f assertion in FullCast(), and instead assert that the SampleRefColor values are all <= 1.0f][:lighting]
[1:24:47][Happily fail to hit those SampleRefColor <= 1.0f assertions in FullCast()][:lighting :run]
[1:24:48][Remove those SampleRefColor <= 1.0f assertions in FullCast()][:lighting]
[1:25:49][Try blanking out the Emission of hit rays in FullCast()][:lighting]
[1:26:04][See our moonlit world][:lighting :run]
[1:26:20][Prevent ComputeVoxelIrradianceAt() from modifying its result][:lighting]
[1:26:27][Watch the light explode, even with such dim moonlight][:lighting :run]
[1:27:58][Assert in ComputeVoxelIrradianceAt() that the Result values are <= 0.5f][:lighting]
[1:28:24][Happily hit our Result <= 0.5f assertions in ComputeVoxelIrradianceAt()][:lighting :run]
[1:28:48][:Run to ComputeVoxelIrradianceAt() and inspect its values, to find that the UVW is garbage][:lighting]
[1:33:29][Separate out the UVW computation in ComputeVoxelIrradianceAt(), and remove VoxCellDim from the BCoord computation][:lighting]
[1:35:03][Step in to ComputeVoxelIrradianceAt() and inspect its values, to find a more expected UVW][:lighting :run]
[1:36:11][Check the moonlit world in release mode][:lighting :run]
[1:36:48][Prevent FullCast() from blanking out the Emission][:lighting]
[1:36:59][See a more sanely and stably lit world][:lighting :run]
[1:38:01][Hit a read access violation in ComputeVoxelIrradianceAt()][:lighting :run]
[1:39:09][Make a note in ComputeVoxelIrradianceAt() to fix the :sampling error][:lighting]
[1:39:16][Q&A][:speech]
[1:39:55][@uplinkcoder][Q: The :UI is drawn at Z levels less than -999 so to disable the :lighting just compare the Z to -999. Can you quickly re-enable it?]
[1:40:24][Make CompileZBiasProgram() only light surfaces that are above Z -999][:lighting :ui]
[1:41:09][Check out our unlit :UI][:lighting :run]
[1:41:57][Make FullCast() be a TIMED_FUNCTION][:"debug system"]
[1:43:57][Check the CPU usage of FullCast() (73%) and ComputeLightPropagationWork() (21%)][:lighting :performance :run]
[1:44:32][Try preventing ComputeVoxelIrradianceAt() from blending the whole :lighting hierarchy]
[1:44:57][FullCast() still uses 73% of our CPU cycles][:lighting :performance :run]
[1:45:19][Make ComputeVoxelIrradianceAt() be a TIMED_FUNCTION][:"debug system" :lighting]
[1:45:54][Hit a write access violation][:"debug system" :lighting :run]
[1:46:06][Prevent ComputeVoxelIrradianceAt() from being a TIMED_FUNCTION][:"debug system" :lighting]
[1:46:30][Try preventing FullCast() from calling ComputeVoxelIrradianceAt()][:lighting]
[1:47:21][FullCast() uses 67% of our CPU cycles][:performance :run]
[1:48:05][Toggle on the ComputeVoxelIrradianceAt() call in FullCast()][:lighting]
[1:48:09][FullCast() uses 73% of our CPU cycles][:performance :run]
[1:48:17][Remove that ComputeVoxelIrradianceAt() toggle in FullCast(), and consider the ray cast to be our most expensive consumer][:lighting :performance]
[1:49:10][@x1bzzr][Q: I think you mentioned before that you don't like regular expressions. Can you elaborate on why?]
[1:50:34][@xxthebigfoxx][Q: If we have a probe near a wall and that probe is updated with the color sampled at the wall, the next frame the wall might be brighter due to the new probe color. Couldn't this spiral up to a very bright probe? How does the system prevent this?][:lighting]
[1:52:44][Try reducing our RayBundleCount to 1 in FullCast()][:lighting]
[1:53:24][FullCast() uses 14% of our CPU cycles][:performance :run]
[1:54:05][Try reducing our RayBundleCount from 1 to 4 in FullCast()][:lighting]
[1:54:18][Our :lighting runs not too poorly][:performance :run]
[1:54:46][Let FullCast() use our full RayBundleCount, and try biasing towards the light source][:lighting]
[1:55:02][Hit a read access violation in ComputeVoxelIrradianceAt()][:lighting :run]
[1:55:10][Our Ty and Tx values in ComputeVoxelIrradianceAt() have apparently wrapped, but why?][:lighting :run]
[1:55:58][Try making GetOctahedralOffset() blank out the Dir][:lighting]
[1:56:26][Step in to GetOctahedralOffset() and inspect its values][:lighting :run]
[1:57:22][Introduce ApproxNOUp() for FullCast() to call, and avoid a divide-by-zero in OctahedralFromUnitVector()][:lighting]
[2:00:17][Hit a read access violation in ComputeVoxelIrradianceAt(), and see that its SampleN is zero][:lighting :run]
[2:02:01][Scrutinise RayCast() for HitNormal errors][:lighting :research]
[2:04:50][Try to make RayCast() never produce a zero HitNormal, by always enabling one of the directional masks][:lighting]
[2:06:56][:Run without hitting that read access violation in ComputeVoxelIrradianceAt()][:lighting]
[2:06:58][Make a note in RayCast() to "Verify that this produces correctly only-one-1 normals for all equivalences"][:lighting]
[2:07:44][Admire our light source-biased :lighting][:run]
[2:08:05][Prevent FullCast() from biasing towards the light source][:lighting]
[2:08:20][See minimal difference with light source-biasing][:lighting :run]
[2:08:37][Toggle off the light source-biasing in FullCast()][:lighting]
[2:09:16][Admire our :lighting][:run]
[2:09:38][@x1bzzr][Q: How would you share :memory across functions in a shared :library? I know the user could allocate memory and pass that to the library, but I was wondering how to have the library allocate memory for internal use without the library user having to know anything about it, but that the dll would keep a reference to across library calls. I tried using a global that gets initialized in the dll main with VirtualAlloc, but later when I call a function the library exports the global is zero]
[2:10:44][Wrap it up][:speech]
[/video]
