Search code examples
rgltfrgl

Approximate PBR in old OpenGL 1


As mentioned in my previous question, I am trying to import/export glTF models in R. The R 3d graphics engine that I'm using (rgl) is really old, and the rendering within R is done using OpenGL 1.x methods: material colors like GL_DIFFUSE, GL_AMBIENT, GL_SPECULAR and GL_EMISSION colors, as well as GL_SHININESS. It also uses WebGL 1 in web output.

I need to translate existing code using these parameters into PBR parameters for output to glTF, and translate glTF PBR parameters into the older model when reading.

Currently I have the following:

  • baseColorFactor in material.pbrMetallicRoughness and textures corresponds to the diffuse color.
  • emissiveFactor corresponds to the emission color.

However, I have no idea how to approximate the other material components in the old style.

I'm hoping this has been done before; can anyone provide formulas for the conversions, or a pointer to a source so I can work them out myself?


Solution

  • Unfortunately, there is no direct conversion between PBR and legacy OpenGL material models.

    Maybe the following pseudo-formula might help as a starting point:

    struct PbrMaterial
    {
      vec4  BaseColor; //!< base color + alpha
      vec3  Emission;  //!< emission
      float Metallic;  //!< metalness factor
      float Roughness; //!< roughness factor
    };
    
    struct CommonMaterial
    {
      vec4  Diffuse;   //!< diffuse RGB coefficients + alpha (GL_DIFFUSE)
      vec4  Ambient;   //!< ambient RGB coefficients (GL_AMBIENT)
      vec4  Specular;  //!< glossy  RGB coefficients (GL_SPECULAR)
      vec4  Emission;  //!< material RGB emission (GL_EMISSION)
      float Shininess; //!< shininess (GL_SHININESS in 0..128 range)
    };
    
    CommonMaterial pbrToCommon (const PbrMaterial& thePbr)
    {
      CommonMaterial aCommon;
      aCommon.Diffuse   = thePbr.BaseColor;
      aCommon.Ambient   = thePbr.BaseColor * 0.25;
      aCommon.Specular  = vec4 (thePbr.Metallic, thePbr.Metallic, thePbr.Metallic, 1.0);
      aCommon.Emission  = vec4 (thePbr.Emission, 1.0);
      aCommon.Shininess = 128.0 * (1.0 - thePbr.Roughness);
      return aCommon;
    }
    

    As an extra note, PBR normally (like in glTF) uses linear RGB color values, while legacy OpenGL usually performed rendering without conversion into non-linear sRGB color space used by most of displays. If referred WebGL 1.0 renderer doesn't perform gamma correction, than it could be cheated on conversion into Diffuse/Ambient/Specular/Emission vectors to have more corellated visual results (but still inconsistent a lot)...