Physically-Based Rendering and lots of other lighting and materials upgrades (in Castle Game Engine and X3D 4.0)

Posted on


During the last few months, I was working with the Web3D Consortium to bring many material and lighting upgrades to the next version of X3D and of course to our Castle Game Engine.

I’m proud to officially announce the first results of this work, including implementation of many new rendering features in Castle Game Engine!

The initial documentation is summarized on this page – “X3D version 4: New features of materials, lights and textures”. With time, more documentation will appear in CGE, and of course X3D v4 specification will also eventually be available as a definite reference of this. The examples are in my x3d-tests repository, in pbr/ subdirectory.

New features:

  • Physically-based rendering (PBR) using the new PhysicalMaterial node.

  • Ability to render glTF models with physical materials. Test it by opening any glTF 2.0 sample model with any engine tool. You can e.g. try view3dscene from snapshots.

  • Much enhanced classic (Phong) lighting model thanks to the enhanced Material node with lots of new fields for textures (emissiveTexture, normalTexture, specularShininessTexture, ambientTexture),

  • More natural “unlit” rendering using the new UnlitMaterial node (very useful for 2D games, and better than previous approach of “Material with only emissiveColor non-zero”, see Why is UnlitMaterial useful for the detailed reasoning),

  • Image-based lighting using EnvironmentLight node. This is in-progress now (not yet working).

All of this is implemented in CGE. We get latest X3D features in this area, while also becoming a reference implementation of these X3D concepts.

Backward compatibility

This change also pushed many fixes to the existing lighting shaders, to be pretty and 100% correct (in regards to both X3D 3 and X3D 4). This means:

  • SeparateDiffuseTexture is now always “on”. This means that X3D Appearance.texture multiplies only diffuse factor (in Phong shading). So the emissiveColor or specularColor are not affected by the Appearance.texture.

    This was always (in all X3D versions, past and future) required.

    Note that Gouraud shading continues to work as before, because in Gouraud shading there’s technically no other choice: Appearance.texture must multiply everything (the whole result of lighting calculation).

  • Using Material with only emissiveColor non-zero behaves now 100% correctly, following X3D equations.

    Previous it was not only an “optimized case of Material”, it also changed the behavior: Appearance.texture was multiplied with emissiveColor (as opposed to multiplying it by diffuseColor). Even when SeparateDiffuseTexture was true, even when Phong shading was used.

    It’s no longer the case.

    Bottom line:

    1. Appearance.texture now always multiplies diffuse factor of the Material, if possible (IOW in Phong shading). Only in Gouraud shading it behaves differently (as then it has to multiply everything).

    2. Use UnlitMaterial instead of Material to have unlit shapes. In case of UnlitMaterial, Appearance.texture always multiplies the emissiveColor. Other things (Color nodes) also behave more naturally for unlit case.

    So it’s simple now:

    • When using Material (Phong lighting model) -> Appearance.texture multiplies diffuseColor
    • When using UnlitMaterial -> Appearance.texture multiplies emissiveColor
    • When using PhysicalMaterial -> Appearance.texture multiplies baseColor

    Color and ColorRGBA nodes are also correct now. They replace the diffuseColor in case of Material — always. Previously, in case of only emissiveColor non-zero they were multiplied and by emissive factor, which was contradicting 2 points of spec. Now they replace the diffuse factor, always (whether “only emissiveColor is non-zero” or not).

Start the discussion at Castle Game Engine Forum