<div dir="ltr"><div><span style="color:rgb(32,31,30);font-size:14.6667px">My experience implementing some of the PBR v4 features in freewrl:</span></div><span style="color:rgb(32,31,30);font-size:14.6667px"><div>- took 16 days</div><div>- I started by defining the PhysicalMaterial, UnlitMaterial and extending the Material node fields, using Michalis's documetation.</div><div><a href="https://github.com/michaliskambi/x3d-tests/wiki/X3D-version-4:-New-features-of-materials,-lights-and-textures#new-x3dmaterialnode-node-with-emissive-and-normalmap-textures">https://github.com/michaliskambi/x3d-tests/wiki/X3D-version-4:-New-features-of-materials,-lights-and-textures#new-x3dmaterialnode-node-with-emissive-and-normalmap-textures</a><br></div><div>- and internally extended structs in program and shader to hold all the new fields</div><div>- then most of the 2 weeks was getting the information flowing to the shader without breaking current functionality, </div><div>-- appearance.backMaterial - I spent a few days harmonizing TwoMaterialShader and this new approach</div><div>-- for the texture maps I found there ware lots of issues with old code assuming certain scenarios, and I spent about a week refactoring messy old code</div><div>- I found the khronos glTF sample had some interesting hints beyond physical, for example they use getter() functions in frag code that hides/abstracts the issue of whether or not there's a texture map. </div><div><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana"><a href="https://github.com/KhronosGroup/glTF-Sample-Viewer/tree/master/src/shaders" style="color:blue">https://github.com/KhronosGroup/glTF-Sample-Viewer/tree/master/src/shaders</a>
</p>

<p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">- see the metallic-roughness.frag </p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">normal = getNormal(); </p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">And I refactored the frag shader to use getters like they do. </p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">- I spent a few extra hours reading up on normal maps (which I learned are in 'tangent space' so need a transform matrix called TBN applied):</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana"><a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping" style="color:blue">https://learnopengl.com/Advanced-Lighting/Normal-Mapping</a>
</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">

</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">- normal map normals are expressed in tangent space</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana"><br></p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">Once I had getters, and had all the info flowing to the frag shader, then it only took a few days to do the metalic-roughness functionality.</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">If you have a loop where you are applying the lights, you probably have something like:</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">diffuse += ...</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">specular += </p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">ambient += </p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">inside the loop.</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">For metalic-roughness, I found I could replace those 3 with</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">shade = getPointShade(pointToLight, materialInfo, normal, view); <br></p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">from the khronos example to make a PBR equivalent light loop.</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana"><br></p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">So in hindsight, it would have been easy to start with the scalar PhyscialMaterial fields, and I could have added the texturemaps to the getters() later.</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana">For those implementing for GLES < 3.0 where texture units are in short supply, the scalar part of PhysicalMaterial should be no problem.</p><p class="MsoNormal" style="margin:0cm 0cm 0.0001pt;font-size:10pt;font-family:Verdana"><br></p></div><div>I still have some minor tinkiering to do -when to apply gamma or its inverse, Michalis has given some answers. And field naming, textureTransform/textureCoordinate 'channel' field conventions, and I haven't attempted EnvironmentLight.</div><div><span style="color:rgb(32,31,30);font-size:14.6667px"><br></span></div><div><span style="color:rgb(32,31,30);font-size:14.6667px">Results:</span></div><div><span style="color:rgb(32,31,30);font-size:14.6667px"><br></span></div>1) PBR physics based rendering via PhysicalMaterial node</span><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px"> - the lighting equations use roughness and metallic with baseColor</span><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px">- (instead of specular, shininess and diffuseColor)</span><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px">- and constrain to physics principle of 'conservation of energy'</span><br style="color:rgb(32,31,30);font-size:14.6667px"><a href="http://dug9.users.sourceforge.net/web3d/tests/PBR/screenshot_pbr_teapots_view3dscene_freewrl.jpg" target="_blank" rel="noopener noreferrer" style="margin:0px;padding:0px;border:0px;font-variant-numeric:inherit;font-variant-east-asian:inherit;font-stretch:inherit;font-size:14.6667px;line-height:inherit;vertical-align:baseline">http://dug9.users.sourceforge.net/web3d/tests/PBR/screenshot_pbr_teapots_view3dscene_freewrl.jpg</a><br style="color:rgb(32,31,30);font-size:14.6667px"><a href="http://dug9.users.sourceforge.net/web3d/tests/PBR/metallic_roughness.x3dv" target="_blank" rel="noopener noreferrer" style="margin:0px;padding:0px;border:0px;font-variant-numeric:inherit;font-variant-east-asian:inherit;font-stretch:inherit;font-size:14.6667px;line-height:inherit;vertical-align:baseline">http://dug9.users.sourceforge.net/web3d/tests/PBR/metallic_roughness.x3dv</a><br style="color:rgb(32,31,30);font-size:14.6667px"><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px">2) extended Material node - supports texture maps for normals, emissive, diffuse, specularShininess, ambient</span><br style="color:rgb(32,31,30);font-size:14.6667px"><a href="http://dug9.users.sourceforge.net/web3d/tests/PBR/screenshot_e_mat_sphere240_view3dscene_freewrl.jpg" target="_blank" rel="noopener noreferrer" style="margin:0px;padding:0px;border:0px;font-variant-numeric:inherit;font-variant-east-asian:inherit;font-stretch:inherit;font-size:14.6667px;line-height:inherit;vertical-align:baseline">http://dug9.users.sourceforge.net/web3d/tests/PBR/screenshot_e_mat_sphere240_view3dscene_freewrl.jpg</a><br style="color:rgb(32,31,30);font-size:14.6667px"><a href="http://dug9.users.sourceforge.net/web3d/tests/PBR/sphere_240_fw.x3dv" target="_blank" rel="noopener noreferrer" style="margin:0px;padding:0px;border:0px;font-variant-numeric:inherit;font-variant-east-asian:inherit;font-stretch:inherit;font-size:14.6667px;line-height:inherit;vertical-align:baseline">http://dug9.users.sourceforge.net/web3d/tests/PBR/sphere_240_fw.x3dv</a><br style="color:rgb(32,31,30);font-size:14.6667px"><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px">The PhysicalMaterial node also supports texturemap for metallicRoughness although I haven't tested.</span><br style="color:rgb(32,31,30);font-size:14.6667px"><br style="color:rgb(32,31,30);font-size:14.6667px"><span style="color:rgb(32,31,30);font-size:14.6667px">3) UnlitMaterial - roughed in plumbing but haven't tested thoroughly - should work and support normal and emissive texture maps</span><br style="color:rgb(32,31,30);font-size:14.6667px"><div><span style="color:rgb(32,31,30);font-size:14.6667px"><br></span></div><div><span style="color:rgb(32,31,30);font-size:14.6667px">freewrl code samples:</span></div><div><a href="https://sourceforge.net/p/freewrl/git/ci/develop/tree/freex3d/src/lib/opengl/Compositing_Shaders.c">https://sourceforge.net/p/freewrl/git/ci/develop/tree/freex3d/src/lib/opengl/Compositing_Shaders.c</a>  </div><div>L.1106 MaterialInfo and gamma functions from Khronos glTF example</div><div>L.1155 getNormal() and getter() farm starts</div><div>L.1300-1340 getting ready for apply_lights_physical</div><div>L.1806 apply_lights_physical code with khronos glTF sample functions, followed by freewrl light loop calling shade = pointShade(...) L.1917</div><div> <a href="https://sourceforge.net/p/freewrl/git/ci/develop/tree/freex3d/src/lib/scenegraph/Component_Shape.c">https://sourceforge.net/p/freewrl/git/ci/develop/tree/freex3d/src/lib/scenegraph/Component_Shape.c</a> <span style="color:rgb(32,31,30);font-size:14.6667px"><br></span></div><div>L.1417 compile_PhysicalMaterial - organizes into internal structs and flags for sending to shader</div></div>