Board index FlightGear Development Effects and shaders

Fragment shader questions

An exciting "new" option in FlightGear, that includes reflections, lightmaps, the particle system etc.. A lot is yet to be discovered/implemented!

Fragment shader questions

Postby Necolatis » Sat Jan 02, 2016 5:28 am

I am curious and have therefore been looking at the Ubershader (the non-Rembrandt version) and have some questions.

Gamma correction

I might not have looked right, but I see no gamma correction taking place in the fragment shader. And is the textures assumed to be gamma corrected, IE. loaded with GL_RGBA?
If I would like to experiment with setting the textures to being GL_SRGB_ALPHA, do I change the <internal-format>normalized</internal-format> to something else, and what?

gl_color and no ambient or emissive contribution

If I leave ambient_correction at 0.0 there seems to be no ambient component computed, but I clearly see ambient light in Flightgear. Also there seem to be no emissive component computed, except for the lightmap. Does these come from gl_color? And gl_color is then the output from the fixed pipeline? So if that's true it means that the ubershader is really a mix between fixed pipeline and per pixel shading? Or am I misunderstanding this completely.

Getting materials

If I want to get the material values in the fragment shader, should I just get them from gl_FrontMaterial?

diffuseColor

Is diffuseColor in the fragment shader coming from the vertex shader, which I see does compute a diffuseColor?
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: Fragment shader questions

Postby Thorsten » Sat Jan 02, 2016 8:45 am

If I leave ambient_correction at 0.0 there seems to be no ambient component computed, but I clearly see ambient light in Flightgear. Also there seem to be no emissive component computed, except for the lightmap. Does these come from gl_color? And gl_color is then the output from the fixed pipeline? So if that's true it means that the ubershader is really a mix between fixed pipeline and per pixel shading? Or am I misunderstanding this completely.


I guess partially the last... :-)

The vertex shader handles all non-directional light already, there you'll find a line like

Code: Select all
gl_FrontColor = gl_FrontMaterial.emission + gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);


which ultimately encodes the correct balance of emissive and ambient light modulated by materials in gl_FrontColor - which then, dependent on face, arrives as gl_Color in the fragment shader where directional light is added, cf. e.g.

Code: Select all
    vec4 color = gl_Color + Diffuse * gl_FrontMaterial.diffuse;


In this context, ambient_correction is just that - a correction to the ambient light.

Is diffuseColor in the fragment shader coming from the vertex shader, which I see does compute a diffuseColor?


No, the diffuse channel is in fact the only of the three that actually is computed in the fragment shader, see above.

If I want to get the material values in the fragment shader, should I just get them from gl_FrontMaterial?


Seems to do the trick for the diffuse channel :-)

I might not have looked right, but I see no gamma correction taking place in the fragment shader


I'm not sure about default, but ALS definitely has a mapping between intensity and color values in place which is partially what a gamma correction does, so I personally would not want to combine that with any fixed pipeline function. I don't quite know how to switch it on, you might need to look into the effect readme in Docs/ - but personally I'd always prefer to code it myself (more control...)
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: Fragment shader questions

Postby Necolatis » Sat Jan 02, 2016 9:29 pm

Thanks for the answers.

I just figured out that ALS uses its own ultra shader. Spent hours trying to mess with the ubershader and did not understand why I didn't see any change (had ALS on). :)

How do I see error output from shaders? Do I have to set FG error logger to something else than INFO?
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: Fragment shader questions

Postby Thorsten » Sun Jan 03, 2016 8:28 am

I just figured out that ALS uses its own ultra shader. Spent hours trying to mess with the ubershader and did not understand why I didn't see any change (had ALS on).


Ah - the classic... (been there more than I care to admit).

Quick thing you can do - insert gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0); as the very last line before the closing } into the fragment shader. See if the thing you're working on renders bright red. If not, you're busy with the wrong shader and should probably be working on the effect declaration file.

How do I see error output from shaders? Do I have to set FG error logger to something else than INFO?


--log-level=warn writes them to the console as they occur, otherwise they appear in the log file, search for anything containing 'fragment' or 'vertex'
Thorsten
 
Posts: 12490
Joined: Mon Nov 02, 2009 9:33 am

Re: Fragment shader questions

Postby Necolatis » Mon Jan 04, 2016 4:07 pm

Thanks for your answers. :)

I assume gl_color in the vertex shader is vertex color, is that correct? And since AC3D does not support vertex color its not that important I guess, is probably always white?

Played around with the shaders:
I have now added gamma correction to the final result and likewise added inverse gamma correction to some of the textures. So that the calculations take place in linear color space.
Also I added support for material diffuse and ambient settings to influence the result, to give the AC3D file more control of how it is shaded.
I have also added a switch to control how reflections is mixed with texel color. Its now easy to avoid darkening and blueing from skybox reflections, at least for smaller reflection strengths, while still having nice reflections and the texture clearly showing. Should maybe experiment of getting that switch into the *.eff file. I like the result most when the switch is set to option 3.
In addition I also multiplied a factor onto the ambient component, to limit its contribution.

If any is curious, here is the files:

ubershader.frag:
Code: Select all
// -*- mode: C; -*-
// UBERSHADER - default forward rendering - fragment shader
// Licence: GPL v2
// Authors: Frederic Bouvier and Gijs de Rooy
// with major additions and revisions by
// Emilian Huminiuc and Vivian Meazza 2011
#version 120

varying   vec4   diffuseColor;
varying   vec3    VBinormal;
varying   vec3    VNormal;
varying   vec3    VTangent;
varying   vec3    rawpos;
varying vec3   eyeVec;
varying vec3   eyeDir;

uniform sampler2D   BaseTex;
uniform sampler2D   LightMapTex;
uniform sampler2D   NormalTex;
uniform sampler2D   ReflGradientsTex;
uniform sampler2D   ReflMapTex;
uniform sampler3D   ReflNoiseTex;
uniform samplerCube   Environment;

uniform int      dirt_enabled;
uniform int      dirt_multi;
uniform int      lightmap_enabled;
uniform int      lightmap_multi;
uniform int      nmap_dds;
uniform int      nmap_enabled;
uniform int      refl_enabled;
uniform   int      refl_dynamic;
uniform int      refl_map;

uniform float   amb_correction;
uniform float   dirt_b_factor;
uniform float   dirt_g_factor;
uniform float   dirt_r_factor;
uniform float   lightmap_a_factor;
uniform float   lightmap_b_factor;
uniform float   lightmap_g_factor;
uniform float   lightmap_r_factor;
uniform float   nmap_tile;
uniform float   refl_correction;
uniform float   refl_fresnel;
uniform float   refl_noise;
uniform float   refl_rainbow;

uniform vec3   lightmap_r_color;
uniform vec3   lightmap_g_color;
uniform vec3   lightmap_b_color;
uniform vec3   lightmap_a_color;

uniform vec3   dirt_r_color;
uniform vec3   dirt_g_color;
uniform vec3   dirt_b_color;

///reflection orientation
uniform mat4   osg_ViewMatrixInverse;
uniform float   latDeg;
uniform float   lonDeg;

///fog include//////////////////////
uniform int fogType;
vec3 fog_Func(vec3 color, int type);
////////////////////////////////////


//////rotation matrices/////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
mat3 rotX(in float angle)
{
   mat3 rotmat = mat3(
                  1.0,   0.0,      0.0,
                  0.0,   cos(angle),   -sin(angle),
                  0.0,   sin(angle),   cos(angle)
   );
   return rotmat;
}

mat3 rotY(in float angle)
{
   mat3 rotmat = mat3(
                  cos(angle),      0.0,   sin(angle),
                  0.0,         1.0,   0.0,
                  -sin(angle),   0.0,   cos(angle)
   );
   return rotmat;
}

mat3 rotZ(in float angle)
{
   mat3 rotmat = mat3(
                  cos(angle),   -sin(angle),   0.0,
                  sin(angle),   cos(angle),      0.0,
                  0.0,      0.0,         1.0
   );
   return rotmat;
}

////////////////////////////////////////////////////////////////////////////////


void main (void)
{
   vec3 gamma      = vec3(1.0/2.2);// standard monitor gamma correction
   vec3 gammaInv   = vec3(2.2);
   vec4 texel      = texture2D(BaseTex, gl_TexCoord[0].st);
   vec4 nmap       = texture2D(NormalTex, gl_TexCoord[0].st * nmap_tile);
   vec4 reflmap    = texture2D(ReflMapTex, gl_TexCoord[0].st);
   vec4 noisevec   = texture3D(ReflNoiseTex, rawpos.xyz);
   vec4 lightmapTexel = texture2D(LightMapTex, gl_TexCoord[0].st);

   // Inverse gamma correction, since these images already is gamma corrected
   texel.rgb = pow(texel.rgb, gammaInv);
   lightmapTexel.rgb = pow(lightmapTexel.rgb, gammaInv);

   vec3 mixedcolor;
   vec3 N = vec3(0.0,0.0,1.0);
   float pf = 0.0;

   ///BEGIN bump //////////////////////////////////////////////////////////////////
    if (nmap_enabled > 0 ){
      N = nmap.rgb * 2.0 - 1.0;
      N = normalize(N.x * VTangent + N.y * VBinormal + N.z * VNormal);
      if (nmap_dds > 0)
         N = -N;
    } else {
       N = normalize(VNormal);
    }
   ///END bump ////////////////////////////////////////////////////////////////////
   vec3 viewN    = normalize((gl_ModelViewMatrixTranspose * vec4(N,0.0)).xyz);
   vec3 viewVec = normalize(eyeVec);
   float v      = abs(dot(viewVec, viewN));// Map a rainbowish color
   vec4 fresnel = texture2D(ReflGradientsTex, vec2(v, 0.75));
   vec4 rainbow = texture2D(ReflGradientsTex, vec2(v, 0.25));

   mat4 reflMatrix = gl_ModelViewMatrixInverse;
   vec3 wRefVec   = reflect(viewVec,N);

   ////dynamic reflection /////////////////////////////
   if (refl_dynamic > 0){
      reflMatrix = osg_ViewMatrixInverse;

      vec3 wVertVec   = normalize(reflMatrix * vec4(viewVec,0.0)).xyz;
      vec3 wNormal   = normalize(reflMatrix * vec4(N,0.0)).xyz;

      float latRad = radians(90.-latDeg);
      float lonRad = radians(lonDeg);

      mat3 rotCorrY = rotY(latRad);
      mat3 rotCorrZ = rotZ(lonRad);
      mat3 reflCorr = rotCorrY * rotCorrZ;
      wRefVec   = reflect(wVertVec,wNormal);
      wRefVec = normalize(reflCorr * wRefVec);
   } else {   ///static reflection
      wRefVec = normalize(reflMatrix * vec4(wRefVec,0.0)).xyz;
   }

   vec3 reflection = textureCube(Environment, wRefVec).xyz;

   // Inverse gamma correction, since these images already is gamma corrected
   reflection = pow(reflection, gammaInv);

   vec3 E = eyeDir;
   E = normalize(E);

   vec3 L = normalize((gl_ModelViewMatrixInverse * gl_LightSource[0].position).xyz);
   vec3 H = normalize(L + E);

   N = viewN;

   float nDotVP = dot(N,L);
   float nDotHV = dot(N,H);
   float eDotLV = max(0.0, dot(-E,L));

   //glare on the backside of transparent objects
   if ((gl_Color.a < .999 || texel.a < 1.0) && nDotVP < 0.0) {
      nDotVP = dot(-N, L);
      nDotHV = dot(-N, H);
   }

   nDotVP = max(0.0, nDotVP);
   nDotHV = max(0.0, nDotHV);

   if (nDotVP == 0.0)
      pf = 0.0;
   else
      pf = pow(nDotHV, gl_FrontMaterial.shininess);

   vec4 Diffuse  = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse * nDotVP;
   vec4 Specular = gl_FrontMaterial.specular * gl_LightSource[0].diffuse * pf;

   vec4 color = gl_Color + Diffuse;
   color = clamp( color, 0.0, 1.0 );
   color.a = texel.a * diffuseColor.a;
   ////////////////////////////////////////////////////////////////////
   //BEGIN reflect
   ////////////////////////////////////////////////////////////////////
   if (refl_enabled > 0 ){
      // mixType: 0-1: limit darkening of texture, 2: mix 3: add
      float mixType = 3;
      float reflFactor = 0.0;
      float transparency_offset = clamp(refl_correction, -1.0, 1.0);// set the user shininess offset

      if(refl_map > 0){
         // map the shininess of the object with user input
         reflFactor = reflmap.a + transparency_offset;
      } else if (nmap_enabled > 0) {
         // set the reflectivity proportional to shininess with user input
         reflFactor = gl_FrontMaterial.shininess * 0.0078125 * nmap.a + transparency_offset;
      } else {
         reflFactor = gl_FrontMaterial.shininess* 0.0078125 + transparency_offset;
      }
      reflFactor = clamp(reflFactor, 0.0, 1.0);

      // add fringing fresnel and rainbow effects and modulate by reflection
      vec3 reflcolor = mix(reflection, rainbow.rgb, refl_rainbow * v);
      vec3 reflfrescolor = mix(reflcolor, fresnel.rgb, refl_fresnel  * v);
      vec3 noisecolor = mix(reflfrescolor, noisevec.rgb, refl_noise);
      vec3 raincolor = noisecolor * reflFactor;
      raincolor += Specular.rgb;
      raincolor *= gl_LightSource[0].diffuse.rgb;
      if(mixType <= 1){
         vec3 finalreflectcolor = max(raincolor, texel.rgb * 0.75);
         mixedcolor = mix(texel.rgb, finalreflectcolor, reflFactor);
      } else if (mixType == 2) {
         mixedcolor = mix(texel.rgb, raincolor, reflFactor);
      } else {
         raincolor *= reflFactor;
         texel.rgb *= 1 - reflFactor;
         mixedcolor =  texel.rgb + raincolor;
      }
    } else {
       mixedcolor = texel.rgb;
    }
    /////////////////////////////////////////////////////////////////////
    //END reflect
    /////////////////////////////////////////////////////////////////////

    if (color.a<1.0){
      color.a += .1 * eDotLV;
    }
    //////////////////////////////////////////////////////////////////////
    //begin DIRT
    //////////////////////////////////////////////////////////////////////
    if (dirt_enabled >= 1){
      vec3 dirtFactorIn = vec3 (dirt_r_factor, dirt_g_factor, dirt_b_factor);
      vec3 dirtFactor = reflmap.rgb * dirtFactorIn.rgb;
      mixedcolor.rgb = mix(mixedcolor.rgb, dirt_r_color, smoothstep(0.0, 1.0, dirtFactor.r));
      if (color.a < 1.0) {
         color.a += dirtFactor.r * eDotLV;
      }
      if (dirt_multi > 0) {
         mixedcolor.rgb = mix(mixedcolor.rgb, dirt_g_color, smoothstep(0.0, 1.0, dirtFactor.g));
         mixedcolor.rgb = mix(mixedcolor.rgb, dirt_b_color, smoothstep(0.0, 1.0, dirtFactor.b));
         if (color.a < 1.0) {
            color.a += dirtFactor.g * eDotLV;
            color.a += dirtFactor.b * eDotLV;
         }
      }

   }
   //////////////////////////////////////////////////////////////////////
   //END Dirt
   //////////////////////////////////////////////////////////////////////


   // set ambient adjustment to remove bluiness with user input
   float ambient_offset = clamp(amb_correction, -1.0, 1.0);
   vec4 ambient = gl_LightModel.ambient + gl_LightSource[0].ambient;

   vec3 ambient_Correction = vec3(ambient.rg, ambient.b * 0.6);

   ambient_Correction *= ambient_offset;
   ambient_Correction = clamp(ambient_Correction, -1.0, 1.0);

   vec4 fragColor = vec4(color.rgb * mixedcolor + ambient_Correction.rgb, color.a);

   fragColor += Specular * nmap.a;

   //////////////////////////////////////////////////////////////////////
   // BEGIN lightmap
   //////////////////////////////////////////////////////////////////////
   if ( lightmap_enabled >= 1 ) {
      vec3 lightmapcolor = vec3(0.0);
      vec4 lightmapFactor = vec4(lightmap_r_factor, lightmap_g_factor,
                          lightmap_b_factor, lightmap_a_factor);
      lightmapFactor = lightmapFactor * lightmapTexel;
      if (lightmap_multi > 0 ){
         lightmapcolor = lightmap_r_color * lightmapFactor.r +
                         lightmap_g_color * lightmapFactor.g +
                         lightmap_b_color * lightmapFactor.b +
                         lightmap_a_color * lightmapFactor.a ;
      } else {
         lightmapcolor = lightmapTexel.rgb * lightmap_r_color * lightmapFactor.r;
      }
      fragColor.rgb = max(fragColor.rgb, lightmapcolor * smoothstep(0.0, 1.0, mixedcolor*.5 + lightmapcolor*.5));
   }
   //////////////////////////////////////////////////////////////////////
   // END lightmap
   /////////////////////////////////////////////////////////////////////

   // gamma correction
   fragColor.rgb = pow(fragColor.rgb, gamma);

   fragColor.rgb = fog_Func(fragColor.rgb, fogType);

   gl_FragColor = fragColor;
}

ubershader.vert:
Code: Select all
// -*- mode: C; -*-
// UBERSHADER - vertex shader
// Licence: GPL v2
// © Emilian Huminiuc and Vivian Meazza 2011
#version 120

varying vec4   diffuseColor;
varying   vec3   VBinormal;
varying   vec3   VNormal;
varying   vec3   VTangent;
varying   vec3   rawpos;
varying vec3    eyeVec;
varying vec3   eyeDir;

attribute   vec3   tangent;
attribute   vec3   binormal;

uniform int        nmap_enabled;
uniform int         rembrandt_enabled;

void   main(void)
{
      rawpos = gl_Vertex.xyz;
      vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
      eyeVec = ecPosition.xyz;
      eyeDir = gl_ModelViewMatrixInverse[3].xyz - gl_Vertex.xyz;

      VNormal = normalize(gl_NormalMatrix * gl_Normal);

      vec3 n = normalize(gl_Normal);

//       generate "fake" binormals/tangents
      vec3 c1 = cross(n, vec3(0.0,0.0,1.0));
      vec3 c2 = cross(n, vec3(0.0,1.0,0.0));
      vec3 tempTangent = c1;

      if(length(c2)>length(c1)){
         tempTangent = c2;
      }

      vec3 tempBinormal = cross(n, tempTangent);

      if (nmap_enabled > 0){
         tempTangent = tangent;
         tempBinormal  = binormal;
      }

      VTangent = normalize(gl_NormalMatrix * tempTangent);
      VBinormal = normalize(gl_NormalMatrix * tempBinormal);

      diffuseColor = gl_Color;
    // Super hack: if diffuse material alpha is less than 1, assume a
   // transparency animation is at work
      if (gl_FrontMaterial.diffuse.a < 1.0)
         diffuseColor.a = gl_FrontMaterial.diffuse.a;

      if(rembrandt_enabled < 1){
      gl_FrontColor = gl_FrontMaterial.emission + vec4(0.375) * gl_FrontMaterial.ambient * gl_Color
                 * (gl_LightModel.ambient + gl_LightSource[0].ambient);
      } else {
        gl_FrontColor = gl_Color;
      }
      
      gl_Position = ftransform();
      gl_ClipVertex = ecPosition;
      gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore
User avatar
Necolatis
 
Posts: 2233
Joined: Mon Oct 29, 2012 1:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2020.3.19
OS: Windows 10

Re: Fragment shader questions

Postby jarl.arntzen » Wed Jan 20, 2016 12:01 am

Necolatis wrote in Mon Jan 04, 2016 4:07 pm:I have now added gamma correction to the final result and likewise added inverse gamma correction to some of the textures. So that the calculations take place in linear color space.


Interesting! Do you have any screenshots?
Frequent Flyer. Occasional Lander.
jarl.arntzen
 
Posts: 106
Joined: Thu Jan 03, 2013 10:43 pm
IRC name: Jarl Arntzen
Version: 2017.1.1
OS: Ubuntu 14.04


Return to Effects and shaders

Who is online

Users browsing this forum: No registered users and 4 guests