[video output=day651 member=cmuratori stream_platform=twitch stream_username=handmade_hero  project=code title="Fixing Light Feedback" vod_platform=youtube id=h-ueZgo_Txk annotator=Miblo]
[0:00][Recap and set the stage for the day looking into light transport][:blackboard :lighting]
[2:55][Light Transport][:blackboard :lighting]
[3:14][Light Transport: 1. Throwing a light source in a scene, :sampling and the inverse-square law][:blackboard :lighting :sampling]
[16:59][Light Transport: 2. Our lack of a reflectance equation that distributes energy fairly without adding energy to the system][:blackboard :lighting :sampling]
[27:44][Light Transport: Distributing reflected light fairly][:blackboard :lighting :sampling]
[35:14][Drink of water][:admin]
[35:18][:afk]
[35:32][Return and clean the board][:admin]
[36:57][Light Transport: Photon counting, Collection 1 (Direct)][:blackboard :lighting :sampling]
[43:36][Light Transport: Photon counting, Collection 2 (Reflected)][:blackboard :lighting :sampling]
[53:16][Light Transport: Energy conservation and collection of light from other probes][:blackboard :lighting :sampling]
[55:18][:afk]
[55:25][Return][:admin]
[55:35][@spacenaming][@handmade_hero Just wanted to let you know you clipped once during the lightboard session (at the word "max" funnily enough), the rest was fine]
[55:41][Reduce the lightboard scene's audio][:admin]
[56:32][Energy conservation confusion][:lighting :research]
[57:04][@nickito97][So the problem is the probe is measuring the "flow" of light through the probe, and the wall next to he probe is using that value to reflect, despite the fact that "flow" can keep going and be reused by other probes, generating more light from nothing?][:lighting]
[59:09][@recyrillic][We could calculate the amount emitted and the amount received and artificially dampen the emission the next frame. But I am not sure that would fix it as we still would have one frame of latency][:lighting]
[1:00:26][Consider reading about light probes][:lighting :research]
[1:04:15][@evuntech][Propagating light info between light probes doesn't make much sense to me. I think you'd want to interpolate rather than sharing info between them][:lighting]
[1:05:31][Recall the original paper we read on light probes[ref
    author=CES
    title="2013 CES: Dr. Paul E. Jacobs, Qualcomm Inc. Keynote"
    publisher=YouTube
    url=https://youtu.be/Vn8qxSUbOko?t=430]][:lighting :research]
[1:07:15][Consult 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'[ref
        title="Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields"
        author="Jean-Philippe Guertin, Derek Nowrouzezahrai, Morgan McGuire"
        url=http://jcgt.org/published/0008/02/01/]][:lighting :research]
[1:14:05][Reacquaint ourselves with ComputeLightPropagationWork() and BuildDiffuseLightMaps()][:lighting :research]
[1:16:57][Consider ordering Real-Time Rendering[ref
    site="Real-Time Rendering"
    url=http://www.realtimerendering.com/]][:lighting :rendering :research]
[1:18:27][Consult 'Real-Time Global Illumination using Precomputed Light Field Probes'[ref
    author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
    title="Real-Time Global Illumination using Precomputed Light Field Probes"
    url=https://casual-effects.com/research/McGuire2017LightField/]][:lighting :research]
[1:29:48][Demo the light feedback][:lighting :run]
[1:30:10][Darken the glove's light from 3 to 1 in AddPlayer()][:"entity system" :lighting]
[1:30:21][The light does not feed back][:lighting :run]
[1:31:19][Brighten the glove's light from 1 to 2 in AddPlayer()][:"entity system" :lighting]
[1:31:28][The light slowly feeds back][:lighting :run]
[1:31:51][Darken the glove's light from 2 to 1 in AddPlayer()][:"entity system" :lighting]
[1:32:11][The light does not feed back, but why?][:lighting :run]
[1:33:42][@drzool][1.1 * 1.1 = larger than original]
[1:34:48][Consider fixing the occlusion bug][:lighting :run]
[1:35:43][Reacquaint ourselves with the bilinear :filtering code in GridRayCast()][:lighting :research]
[1:39:19][Reacquaint ourselves with our surface colours][:lighting :research]
[1:43:22][Brighten the glove's light from 1 to 1.25 in AddPlayer()][:"entity system" :lighting]
[1:44:15][The light does not feed back][:lighting :run]
[1:44:34][Brighten the glove's light from 1.25 to 1.3 in AddPlayer()][:"entity system" :lighting]
[1:44:48][The light appears not to feed back][:lighting :run]
[1:45:09][Brighten the glove's light from 1.3 to 1.5 in AddPlayer()][:"entity system" :lighting]
[1:45:18][The light appears not to feed back][:lighting :run]
[1:45:30][Brighten the glove's light from 1.5 to 1.75 in AddPlayer()][:"entity system" :lighting]
[1:45:39][The light slowly feeds back][:lighting :run]
[1:47:08][@mariusorc][Q: Is it possible that the color dampening hits some negative values and adds to the :lighting instead?]
[1:48:18][@vaualbus][But did we always have this problem? Like, can be the removal of Z or the walking grid make this happen?][:lighting]
[1:48:41][Decrease tUpdateBlend from 6/60 to 1/60 in UpdateLighting()][:lighting]
[1:48:52][The light appears not to feed back][:lighting :run]
[1:49:12][Brighten the glove's light from 1.75 to 2 in AddPlayer()][:"entity system" :lighting]
[1:49:22][The light slowly feeds back][:lighting :run]
[1:49:34][Increase tUpdateBlend from 1/60 to 6/60 in UpdateLighting()][:lighting]
[1:49:38][The light quickly feeds back][:lighting :run]
[1:50:46][Consider how to progress, possibly applying an exposure curve][:lighting :research]
[1:52:33][Consult LearnOpenGL's HDR article[ref
    site=LearnOpenGL
    page=HDR
    url=https://learnopengl.com/Advanced-Lighting/HDR] for a simple exposure curve][:lighting :research]
[1:53:42][Make CompileZBiasProgram() clamp SurfaceReflect in a single call][:lighting]
[1:53:59][That seems fine][:lighting :run]
[1:54:07][Make CompileZBiasProgram() apply Reinhard tone mapping to the SurfaceReflect][:lighting]
[1:54:55][The light feeds back][:lighting :run]
[1:55:32][Remove Reinhard tone mapping from SurfaceReflect in CompileZBiasProgram()][:lighting]
[1:55:48][@immow][Are beginner questions okay?]
[1:56:03][Eyeball our over-brighting bug][:lighting :run]
[1:57:25][Make GridRayCast() zero out HitRefColor and HitEmission upon walking the distance][:lighting]
[1:58:32][The light feeds back][:lighting :run]
[1:58:53][Make GridRayCast() only zero out HitRefColor and HitEmission upon hitting the SPATIAL_GRID_NODE_TERMINATOR][:lighting]
[1:59:11][The light feeds back][:lighting :run]
[1:59:19][Revert our changes to GridRayCast()][:lighting]
[2:00:12][@vaualbus][Q: Could it be :sampling errors? Like aliasing or some sort of things like that? Also maybe we are not always dealing with normalized numbers, and in the equation we should count normalization values?][:lighting]
[2:02:13][@mallesbixie][Last time I watched, there was sus copy pasta code at the TransferPPSAccum line endings. Can we peak there again?]
[2:02:47][@mallesbixie][Yeah, there, 0 as last args]
[2:03:10][Describe the shuffler code in GridRayCast()][:lighting :research]
[2:08:27][Consider our definition of the light transfer problem to be wrong][:lighting :run]
[2:09:05][Consider working through the light transfer problem on the light board][:lighting :research]
[2:09:58][@mindmark42][What is the normal storing thing the paper[ref
    author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
    title="Real-Time Global Illumination using Precomputed Light Field Probes"
    url=https://casual-effects.com/research/McGuire2017LightField/] was talking about?][:lighting]
[2:10:08][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:10:37][Describe our light probe octahedral values][:"debug visualisation" :lighting :run]
[2:11:23][Darken the glove's light from 2 to 1 in AddPlayer()][:"entity system" :lighting]
[2:11:46][Describe our light probe octahedral values, without feedback][:"debug visualisation" :lighting :run]
[2:13:26][Toggle on GRID_RAY_CAST_DEBUGGING][:lighting]
[2:13:37][Describe the paper's[ref
    author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
    title="Real-Time Global Illumination using Precomputed Light Field Probes"
    url=https://casual-effects.com/research/McGuire2017LightField/] storage of hit surface normal][:lighting :run]
[2:16:34][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[2:17:23][Our glove alone does not contaminate][:lighting :run]
[2:17:48][Make CompileZBiasProgram() multiply the SurfaceReflect by 10][:lighting]
[2:18:45][Our glove is brighter][:lighting :run]
[2:18:56][Make CompileZBiasProgram() multiply the SurfaceReflect by 100][:lighting]
[2:19:01][Our glove is brighter still, and does not feed back][:lighting :run]
[2:19:28][Toggle on room lights in StandardLightingPattern(), and reduce their intensity from 10 to 0.1][:lighting :"procedural generation"]
[2:20:04][Our world is the brightness we'd like, and the light does not feed back][:lighting :run]
[2:20:17][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:20:36][Our world is the brightness we'd like, and the light does not feed back][:lighting :run]
[2:22:06][Darken the glove's light from 1 to 0.2 in AddPlayer()][:"entity system" :lighting]
[2:22:31][Our :lighting looks basically correct][:run]
[2:22:53][Darken the moonlight from 0.2 to 0.025 in GenerateApron()][:lighting :"procedural generation"]
[2:23:26][The exterior light is still quite bright][:lighting :run]
[2:23:30][Darken the moonlight from 0.025 to 0.01 in GenerateApron()][:lighting :"procedural generation"]
[2:23:37][The exterior light is maybe about right][:lighting :run]
[2:23:41][Darken the moonlight from 0.01 to 0.005 in GenerateApron()][:lighting :"procedural generation"]
[2:23:49][The light looks as we'd like][:lighting :run]
[2:24:54][@sagian2005][Gorgeous light that we don't understand][:lighting]
[2:25:09][An unanticipated portion of the system is working as a percentage][:lighting :run]
[2:26:11][Determine to address our occluded light probe darkening problem][:lighting :research]
[2:26:40][Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:27:06][Illustrate our darkened occluded light probe][:lighting :run]
[2:27:37][Make DebugDrawSpatialGrid() colour the leaves with their RefColor][:"debug visualisation" :lighting]
[2:29:09][The spatial grid leaves are all white][:"debug visualisation" :lighting :run]
[2:29:24][Make DebugDrawSpatialGrid() account for Emission when colouring the leaves][:"debug visualisation" :lighting]
[2:30:05][Illustrate our darkened embedded light probes][:lighting :run]
[2:31:19][Describe the code that blackens embedded light probes in FullCast()][:lighting :research]
[2:31:59][Prevent FullCast() from touching embedded light probes][:lighting]
[2:32:13][Light probes no longer darken when occluded by the glove, but neither do they receive its full light contribution][:lighting :run]
[2:33:00][Consider running the occlusion check on every sample][:lighting :research]
[2:35:18][Let FullCast() cast rays from embedded light probes][:lighting]
[2:35:36][The light looks good][:lighting :run]
[2:36:37][Document the embedded light probe ray casting][:lighting]
[2:37:24][The light leaks through walls][:lighting :run]
[2:38:45][Make FullCast() distinguish between emitters and occluders, making only the latter contribute to the IsInside check][:lighting]
[2:42:18][The light no longer leaks through walls][:lighting :run]
[2:43:39][@psarokroketa][Wouldn't IsEmission <= Zero work?][:lighting]
[2:43:44][Reorient the Mask computation around IsOccluder in FullCast()][:lighting]
[2:44:05][Light probes remain not directly lit by overlapping emitters][:lighting :run]
[2:46:07][Toggle off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:46:28][Our octahedron directions may be nonsense][:"debug visualisation" :lighting :run]
[2:47:01][DebugDrawOctahedralValues() isn't nonsense][:"debug visualisation" :lighting :research]
[2:47:32][Consider writing our emission values into the light probes as a pre-pass][:"debug visualisation" :lighting :run]
[2:48:35][@coffeeb4code][Curious what the total size of [~hero Handmade Hero] is (clientside)]
[2:48:52][Consider writing our emission values into the light probes as a pre-pass (cont.)][:"debug visualisation" :lighting :run]
[2:49:40][@coffeeb4code][The binary]
[2:49:55][1 MiB executable size][:admin]
[2:50:39][@coffeeb4code][Without assets? That's so small]
[2:51:18][Consider writing our emission values into the light probes as a pre-pass (cont.)][:"debug visualisation" :lighting :run]
[2:52:45][@gusfrehse][I'd say to the left][:lighting]
[2:54:12][Consider writing the emission value of light volumes into light probes proportional to their overlap][:lighting :run]
[2:58:48][Consider writing the emission value of light volumes into light probes stochastically][:lighting :run]
[3:00:07][Reacquaint ourselves with our use of the specular light atlas][:lighting :research]
[3:03:54][Rename LightDepthSampler to SpecularSampler in the OpenGL renderer][:lighting]
[3:04:15][Consider sampling from the specular map rather than the diffuse map][:lighting :research]
[3:05:39][Yearn for the ability in C++ to #include a file as a string][:language :rant :speech]
[3:07:19][Remove GetIrradiance()][:lighting]
[3:08:41][@wocket251][I think std\:\:embed got killed sadly][:language]
[3:12:28][@youngsterglenn][Enough of those committees and you can work towards eliminating all bad decisions][:language]
[3:13:37][@skaman512][The problem is about embedding a shader in your code? I think inside a constexpr you can read a file and return an array (and do it at compile time)][:language]
[3:14:00][@ryanfleury][I just always have my own path for #embed in my metaprogram, and throw my shaders into metacode][:language :metaprogramming]
[3:14:23][Reacquaint ourselves with SampleLighting()][:lighting :research]
[3:15:12][@nedboulter][If you don't like C++ why are you using C++?][:language]
[3:15:46][Reacquaint ourselves with specular and diffuse map usage in SampleLighting()][:lighting :research]
[3:17:31][Check out our light][:lighting :run]
[3:17:47][Toggle from radial to our manual bilinear interpolation in SampleLighting()][:lighting]
[3:18:02][Our light looks the same][:lighting :run]
[3:18:18][Toggle off our manual interpolation path in CompileZBiasProgram()][:lighting]
[3:18:25][Our light looks the same][:lighting :run]
[3:18:58][Double-check that we call SampleLighting()][:lighting :research]
[3:19:51][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[3:19:56][Our light interpolation looks a little squarer][:lighting :run]
[3:20:53][Toggle on our radial interpolation in SampleLighting9)][:lighting]
[3:20:57][Our light looks the same][:lighting :run]
[3:21:03][Try making SampleLighting() colour the light red][:lighting]
[3:21:25][We're reloading shaders][:lighting :run]
[3:21:30][Let SampleLighting() work as normal, toggling from our radial to the regular bilinear interpolation][:lighting]
[3:21:46][Consider the regular bilinear sampling to be fine][:lighting :run]
[3:22:17][Remove our fancier interpolation code from SampleLighting() and use v3 rather than v4][:lighting]
[3:23:49][Our light looks the same][:lighting :run]
[3:23:59][Fix indentation of SumLight()][:lighting]
[3:24:57][@psarokroketa][Is there really no way to indent multiple lines together in ~4coder?]
[3:25:42][Rename LightColorSampler to DiffuseSampler in the OpenGL renderer][:lighting]
[3:26:18][Our light looks the same][:lighting :run]
[3:26:25][Make SampleLighting() use the SpecularSampler][:lighting]
[3:26:49][Our light now looks unpleasant and shiny][:lighting :run]
[3:27:29][Reacquaint ourselves with the reflection directionality in SumLight()][:lighting :research]
[3:28:48][@psarokroketa][So you can just say move these 10 lines one to the left without it messing it up? This sounds painful]
[3:29:51][Check out our specular light][:lighting :run]
[3:30:09][Switch SumLight() to use the reflection vector][:lighting]
[3:30:50][Check out our actual specular light][:lighting :run]
[3:32:04][@recyrillic][@handmade_hero You can use a macro like '#define shader_code(a) #a' and then on 'char *shader = shader_code(<insert shader here>);' the <shader code> gets auto indented. At least that works for me. (Sorry if you read the previous one and ignored it on purpose)]
[3:33:07][Introduce OctFrom() for SumLight() to call and compute both the specular and diffuse atlases to pass to SampleLighting()][:lighting]
[3:36:34][Our light kind of looks right][:lighting :run]
[3:37:04][Make SampleLighting() sum together the specular and diffuse atlases][:lighting]
[3:37:26][Check out our half-and-half specular / diffuse lighting][:lighting :run]
[3:37:46][Set up SampleLighting() to interpolate between our specular and diffuse atlases using a Material][:lighting]
[3:38:46][Check out our light][:lighting :run]
[3:39:23][#define EmbedShader()][:language]
[3:40:55][Hit a "Shader validation failed" error][:language :run]
[3:42:00][Scour our EmbedShader() calls for syntax errors][:language :research]
[3:42:51][@anelysian][I think the preprocessor isn't going to preserve the #if's]
[3:43:45][Try removing the #if's from our EmbedShader() calls][:language]
[3:44:09][:Run without hitting a "Shader validation failed" error][:language :run]
[3:44:21][Revert our introducing of EmbedShader()][:language]
[3:45:16][Consider our light to be too bright][:lighting :run]
[3:45:47][Prevent CreateOrphanage() from adding light outdoors][:lighting :"procedural generation"]
[3:46:38][Our moonlight is still a little too bright][:lighting :"procedural generation" :run]
[3:47:20][Darken the moonlight from 0.2 to 0.01 in GenerateRoom()][:lighting :"procedural generation"]
[3:47:45][Our moonlight seems better][:lighting :"procedural generation" :run]
[3:48:36][Decrease tUpdateBlend from 6/60 to 3/60 in UpdateLighting()][:lighting]
[3:48:57][Our light doesn't look very flickery][:lighting :run]
[3:49:23][Decrease tUpdateBlend from 3/60 to 1/60 in UpdateLighting()][:lighting]
[3:49:28][Our light still doesn't flicker][:lighting :run]
[3:49:42][Increase tUpdateBlend from 1/60 to 20/60 in UpdateLighting()][:lighting]
[3:49:51][Our light flickers][:lighting :run]
[3:50:03][Decrease tUpdateBlend from 20/60 to 12/60 in UpdateLighting()][:lighting]
[3:50:16][Our light is a little flickery][:lighting :run]
[3:53:00][Increase RayCount from 8 to 16 in GridRayCast()][:lighting]
[3:53:12][Our light minimally flickers][:lighting :run]
[3:54:36][Determine to tackle forward-rasterisation next week][:lighting :research]
[3:54:59][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[3:55:12][Admire our spooky orphanage][:lighting :run]
[3:56:22][Make CreateOrphanage() put a Snake in BedroomA, and darken the light from 5 to 1 in SnakePattern()][:lighting :"procedural generation"]
[3:58:24][Watch the snake in BedroomA][:lighting :"procedural generation" :run]
[3:58:51][Darken the light from 1 to 0.25 in SnakePattern()][:lighting :"procedural generation"]
[3:59:02][@i_am_seabass][I think the glove needs some glowy light emitting particle effects now][:lighting :"particle system"]
[3:59:08][Watch the snake get stuck in the corner][:lighting :"procedural generation" :run]
[3:59:26][Make CreateOrphanage() put Snakes in BedroomB and BedroomC][:lighting :"procedural generation"]
[3:59:57][Our snakes lock up in the corner][:lighting :"procedural generation" :run]
[4:00:30][Prevent CreateOrphanage() from putting snakes in the bedrooms, and make StandardLightingPattern() create dimmer and randomly coloured room lights][:lighting :"procedural generation"]
[4:01:08][Admire our fantastic light][:lighting :run]
[4:02:01][Plan to fix the overlapped emitter and light probe dimming bug, and maybe bundle our rays][:lighting :speech]
[4:02:53][@mindmark42][So we're just ignoring the feedback issue?][:lighting]
[4:04:37][@wylem][Is the feedback thing just because the lighting has a temporal element, kind of turning it into a system where you have energy going in each frame and damping from absorption? And if the energy going in exceeds the damping, you get feedback?][:lighting]
[4:06:34][That's it for today][:speech]
[/video]
