[video output=day383 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Fixing Depth Peel Artifacts" vod_platform=youtube id=AHB5J_FPaW4 annotator=Miblo]
[0:22][Recap and set the stage for the day, improving the depth peeling]
[2:14][Run the game, note the rendering artifacts while depth peeling, and consider what may be causing them]
[7:23][handmade_opengl.cpp: Consider how CompilePeelComposite() is computing the ResultColor]
[10:16][handmade_opengl.cpp: Make CompilePeelComposite() clamp the ResultColor to 0 to 1[ref
    site="OpenGL Registry"
    page="The OpenGL Shading Language 1.50 Quick Reference Card"
    url="https://www.khronos.org/files/opengl-quick-reference-card.pdf"]]
[10:57][Run the game to see that that did not improve our situation, but did change our background colour]
[11:43][handmade_opengl.cpp: Investigate how CompilePeelComposite() is drawing the peels]
[15:58][Run the game to determine that the alpha inverse computation is wrong]
[16:44][handmade_opengl.cpp: Prevent CompilePeelComposite() from putting alpha in Peel3]
[17:48][handmade_opengl.cpp: Make CompilePeelComposite() clamp the colours again, and run the game to determine that this part of the composite is not the problem]
[19:16][handmade_opengl.cpp: Make CompilePeelComposite() colour the peels]
[21:10][Run the game to see the coloured peels]
[22:43][handmade_opengl.cpp: Make CompilePeelComposite() multiply the peel colour by its alpha, and run the game to see that the error occurs where many peels overlap]
[25:17][handmade_opengl.cpp: Enable CompileZBiasProgram() to fog pixels out before their alpha is 0]
[26:19][Run the game and erroneously see colour on pixels that should have been fogged completely out]
[28:07][handmade_opengl.cpp: Make CompileZBiasProgram() correctly clip out transparent pixels from the depth peel]
[29:41][Run the game to see that we're a lot better]
[31:47][handmade_opengl.cpp: Try making CompileZBiasProgram() draw Peel3 as bright pink and run the game to see purple where the artifact occurs]
[33:50][Consider how best to mix the peels together]
[36:26][Blackboard: Depth Peel Sandwich]
[40:26][Run the game and think about what's actually happening with the artifact]
[43:24][handmade_opengl.cpp: Enable CompileZBiasProgram() to draw something in the last peel above a given alpha threshold]
[48:18][Run the game to see that that did help]
[50:51][handmade_opengl.cpp: Make OpenGLRenderCommands() clear the alpha to 1, and the shader to undo the premultiplied alpha]
[52:20][Run the game to see that it looks worse]
[52:53][handmade_opengl.cpp: Note that our art asset packer does not handle sRGB]
[55:54][handmade_opengl.cpp: Consider that clamped values cannot be used at the vertex level]
[57:12][Blackboard: Incorrect clamping]
[58:10][handmade_opengl.cpp: Make the FragmentCode itself in CompileZBiasProgram() clamp and compute the fog]
[58:54][Blackboard: Vertex and Fragment Shader Output]
[1:00:23][Run the game, crash in shader compilation and reorganise the code]
[1:01:39][Run the game to see that the effect is very different, and the artifact is gone]
[1:04:38][Note that we probably would still want to use multisampling on fast GPUs]
[1:06:46][handmade_opengl.cpp: Begin to enable OpenGLRenderCommands() to conditionally perform multisampling]
[1:13:08][Consider changing the renderer to draw at the size at which the game is running]
[1:17:07][handmade_opengl.cpp: Change OpenGLRenderCommands() to draw at the correct aspect ratio]
[1:21:06][Run the game to see the correct letterboxing]
[1:21:41][handmade_opengl.cpp: Enable OpenGLBindFramebuffer() to blit to the correct size]
[1:25:11][Run the game to see that it's nice and clean]
[1:25:38][win32_handmade.cpp: Draw to a lower resolution, stretched up]
[1:26:02][Run the game and see some weird artifacts and investigate those artifacts]
[1:28:33][handmade_opengl.cpp: Try to force real sRGB off]
[1:30:07][Run the game and consider that, because the alpha is not computed with sRGB, it does not line up right when stretched]
[1:31:18][handmade_opengl.cpp: Consider that the bilinear filter on the depth peel composite may not be correct]
[1:33:47][handmade_opengl.cpp: Make OpenGLRenderCommands() use a raw texel sample in the depth peel]
[1:34:38][Run the game to see that the fringing while stretching has gone]
[1:35:02][Blackboard: Correctly sampling from texels for stretching]
[1:39:25][handmade_opengl.cpp: Determine to composite to an intermediate framebuffer, and then stretch that to the final image]
[1:42:57][handmade_opengl.cpp: Introduce CompileFinalStretch()]
[1:48:34][handmade_opengl.cpp: Introduce CreateFramebuffer()]
[1:57:03][handmade_opengl.cpp: Enable CreateFramebuffer() to conditionally apply filtering[ref
    site="docs.GL"
    page="glTexParameter"
    url="http://docs.gl/gl3/glTexParameter"]]
[1:58:37][handmade_opengl.cpp: Make OpenGLRenderCommands() create the final GlobalResolveFramebuffer]
[2:02:34][Run the game to admire the correct composite and then stretching]
[2:03:35][win32_handmade.cpp: Draw to decreasingly smaller resolutions]
[2:05:58][Run the game in pixel art mode][quote 577]
[2:07:04][Q&A][:speech]
[2:07:36][@naysayer88][OpenGL sucks]
[2:10:56][@naysayer88][The problem is there is no way for me to know what the "good API" is any more...]
[2:14:30][@jezzi23][In Win32InitOpenGL(), why do you use two different forms for assigning modern OpenGL function pointers, i.e. using Win32GetOpenGLFunction(Name) macro for some but assigning others directly?]
[2:15:01][@serialqwiller][Just so you know, your stream no longer shows up in either the "Game Development" or "Programming" categories on twitch. It's almost a hidden stream now just for those who already followed]
[2:16:10][@nyeecola][I tried your anonymous union and structs trick and the compiler (g++) screams at me saying I need some label in the struct name to conform to the standard. So I looked it up on google and it appears to be undefined behavior to use this trick. Should I be afraid of that?]
[2:19:56][@soysaucethekid][The cursor always seems to be on the loading(?) icon. Is there a way to fix that? (I'm running into this issue and am not sure if there is some windows message I need to process)]
[2:20:18][win32_handmade.cpp: Try to stop the wait cursor displaying once we have finished loading]
[2:28:38][@fr0styninja][You can set the cursor on the WNDCLASS struct .hCursor = LoadCursor(0, IDC_ARROW);]
[2:30:06][@nyeecola][You said on one stream that you don't need header guards because you have only one translation unit. I guess you meant that you're sure you only include each header once? Because even if you only have one translation unit you still can have problems if you include the same header twice]
[2:31:37][@nyeecola][Multiple anonymous unions inside one struct, is that allowed?]
[2:32:37][Wrap it up with a plug of Lysa[ref
    site="Handmade Network"
    page="Lysa"
    url="https://lysa.handmade.network/"]][:research]
[2:35:19][Promote @CaptainKraft's Patreon[ref
    site="Patreon"
    page="CaptainKraft is creating Lysa, the Embeddable Debugger"
    url="https://www.patreon.com/CaptainKraft"]][:research]
[2:37:01][That's about it for today, with a glimpse into the future][:speech]
[/video]
