OpenGL Demos
OpenGL Misc
MSG Board
Megabyte Softworks
C++, OpenGL, Algorithms

Current series: OpenGL 3.3
(Return to list of OpenGL 3.3 tutorials)

Download (2.13 MB)
4339 downloads. 30 comments
12.) Fog Outside

Welcome to the 12th OpenGL 3.3 tutorial! This time we'll discuss fog and how to program it using shaders. Fog is really nice and simple effect, which is often used in games not only to give a flavour to it, but also because it eliminates need of far clipping plane, because we won't see things far from us, because they are covered by fog anyway. So let's get started.


Fog is a collection of liquid water droplets or ice crystals suspended in the air at or near the Earth's surface. While fog is a type of stratus cloud, the term "fog" is typically... just Wikipedia definition. But I think there's no need to explain to anyone what is a fog, we all know that LULZ. We are going right to its implementation using shaders.

The basic idea behind fog should be something like that - the further object from camera is, the more covered in fog it should be. And we won't be calculating just how far objects are, but we'll do it for every single fragment in final image, because that's what modern GPU programming paradigms allows us. So the main idea is to calculate each fragment's distance from camera (it's reffered to as fogCoordinate, and then apply some function, which will calculate the fogFactor - how much fog to add to this fragment. Our fog will also have its color, so depending on fogFactor, we'll calculate final fragment color by mixing it with fog's color.

There are 3 basic functions, that calculate fog factor depending on fog coordinate. These are:

We'll go through each of these equations now.

Linear equation

There's not much to think of here. Simply fog factor should be linear interpolation between fog start and fog end, so the equation looks like this:

which can be easily written in GLSL as:
fogFactor = 1.0-clamp( (fogEnd-fogCoord)/(fogEnd-fogStart), 0.0, 1.0)
Graph will help you understand it even better:

Exp equation

This is my favourite equation, I think it gives nicest results. It takes one additional parameter - fog density. It should be a number ranging somewhere between 0.0 and 0.1, beyond these numbers fog is too dense or none (you can try to play with this value in application). It looks like this:

The distribution now isn't linear, but exponential, and as you can see in application, it seems a lot better than linear fog. The graph of this function looks like this (it's for density 0.04, but you should get an idea of how it looks):

There is a function exp in GLSL, that raises e to a specified power, so it's easy to write in GLSL:
fogFactor = 1.0-clamp( exp(-fogDensity*fogCoord), 0.0, 1.0)

Exp2 equation

The third and the last fog equation that is commonly used is exp2 equation. It looks like this:

Again, the power to 2 changes game a little. The density is even more sensible, so optimal range is somewhere between the 0.0 and 0.05, otherwise fog gets too intense (again, play with this value in demo so that you will see it). The graph of function looks like this (it's for density 0.03):

In GLSL, we can write with exp and pow functions (pow takes two parameters - number to raise, and number to raise to):
fogFactor = 1.0-clamp(exp(-pow(fogDensity*fogCoord, 2.0)), 0.0, 1.0)

Calculating fog coordinate

This is a key to success in order to program fog. But luckily, it's very easy. I would even say unbelievable easy LULZ. You just need to calculate eye space position of every vertex (we already know that), and then send it to fragment shader interpolated between every fragment to get eye space position of every fragment. We are interested in how deep or how far from us it is, so we are interested in z value. And since the eye space position is in homogeneous coordinates (we discussed it in 4th tutorial), we divide it with its w coordinate to obtain cartesian coordinates. And to top of all, we make an absolute value from it, because the result of these operations seems to be negative.

Here is a vertex shader for this:

#version 330

uniform struct Matrices
   mat4 projectionMatrix;
   mat4 modelViewMatrix;
   mat4 normalMatrix;
} matrices;

layout (location = 0) in vec3 inPosition;
layout (location = 1) in vec2 inCoord;
layout (location = 2) in vec3 inNormal;

smooth out vec2 texCoord;
smooth out vec3 vNormal;
smooth out vec4 vEyeSpacePos;

void main()
   vec4 vEyeSpacePosVertex = matrices.modelViewMatrix*vec4(inPosition, 1.0);
   gl_Position = matrices.projectionMatrix*vEyeSpacePosVertex;
   texCoord = inCoord;
   vec4 vRes = matrices.normalMatrix*vec4(inNormal, 0.0);
   vNormal = vRes.xyz;
   vEyeSpacePos = vEyeSpacePosVertex;   

I decided to structurize it a little, because these shader programs get more and more complex, and I don't want it to be a mess. Now almost every logical part of shader programs has at least its own struct. Not only that, if you remember how I have written in 3rd article about shaders, I said that shaders are like single source files, and we create a program and link them together. And that's what we'll use in this tutorial now. Fog will have it's own shader with fog factor calculation function in it, and main fragment shader will only have declaration of these functions and also struct declarations. Unluckily, GLSL doesn't have a support for something like #includefile preprocessor directive, so that we could define "header shader files" and "source shader files". Maybe you ask why not just #include. I read somewhere, that #include is a reserved keyword, I don't know if it's true, so I'd rather wouldn't use it. But it's not difficult to add some preprocessing into our loadShader function. We could add a case there, that if a line begins with word #includefile, we should paste the file there, and then compile it. I will probably do it in later tutorials, but I'm saying this now to give you an idea how linking multiple shader files works. It's good to isolate different shading algorithms into different shaders, and then just create shader programs consisting of their mixes. But for the purpose of this tutorial, we just copy & paste the struct and function declarations from fog shader. The fog shader looks like this:

#version 330

uniform struct FogParameters
   vec4 vFogColor; // Fog color
   float fStart; // This is only for linear fog
   float fEnd; // This is only for linear fog
   float fDensity; // For exp and exp2 equation
   int iEquation; // 0 = linear, 1 = exp, 2 = exp2
} fogParams;

float getFogFactor(FogParameters params, float fFogCoord)
   float fResult = 0.0;
   if(params.iEquation == 0)
      fResult = (params.fEnd-fFogCoord)/(params.fEnd-params.fStart);
   else if(params.iEquation == 1)
      fResult = exp(-params.fDensity*fFogCoord);
   else if(params.iEquation == 2)
      fResult = exp(-pow(params.fDensity*fFogCoord, 2.0));
   fResult = 1.0-clamp(fResult, 0.0, 1.0);
   return fResult;

As you can see, there is only struct containing fog parameters and fog factor calculatiion function. Now if we want to use this function in another shader file, we just need to declare it in it. And with it, also the struct must be declared in that shader file (that's why something like #includefile would be very useful). Of course, you can't forget to add this shader into shader program in initScene function. Now, let's have a look at fragment shader file with main function:

#version 330

smooth in vec2 texCoord;
smooth in vec3 vNormal;
smooth in vec4 vEyeSpacePos;
out vec4 outputColor;

uniform sampler2D gSampler;
uniform vec4 vColor;

uniform struct SimpleDirectionalLight
   vec3 vColor;
   vec3 vDirection;
   float fAmbientIntensity;
} sunLight;

uniform struct FogParameters
   vec4 vFogColor; // Fog color
   float fStart; // This is only for linear fog
   float fEnd; // This is only for linear fog
   float fDensity; // For exp and exp2 equation
   int iEquation; // 0 = linear, 1 = exp, 2 = exp2
} fogParams;

float getFogFactor(FogParameters params, float fFogCoord);

void main()
   vec4 vTexColor = texture2D(gSampler, texCoord);
   float fDiffuseIntensity = max(0.0, dot(normalize(vNormal), -sunLight.vDirection));
   outputColor = vTexColor*vColor*vec4(sunLight.vColor*(sunLight.fAmbientIntensity+fDiffuseIntensity), 1.0);
   // Add fog
   float fFogCoord = abs(vEyeSpacePos.z/vEyeSpacePos.w);
   outputColor = mix(outputColor, fogParams.vFogColor, getFogFactor(fogParams, fFogCoord));

In the end of it, we can see that we are calculating fog coordinate using the interpolated vEyeSpacePos, and then just mix colors depending on fog factor. GLSL function mix just adds two colors together, depending on third parameter factor like this: (1.0-factor)*color1 + factor*color2. One optimization that would save some processing time is not to interpolate whole eye space position, because we are not using x and y coordinates anyway, but rather directly calculate the fog factor in vertex shader, and send it interpolated into fragment shader. You can try it on your own, it should work as well.

In render scene function, fog parameters must be set before rendering. We do it as we always set uniforms:


namespace FogParameters
   float fDensity = 0.04f;
   float fStart = 10.0f;
   float fEnd = 75.0f;
   glm::vec4 vFogColor = glm::vec4(0.7f, 0.7f, 0.7f, 1.0f);
   int iFogEquation = FOG_EQUATION_EXP; // 0 = linear, 1 = exp, 2 = exp2

void renderScene(LPVOID lpParam)
   // ...

   spFogAndLight.setUniform("fogParams.iEquation", FogParameters::iFogEquation);
   spFogAndLight.setUniform("fogParams.vFogColor", FogParameters::vFogColor);

   if(FogParameters::iFogEquation == FOG_EQUATION_LINEAR)
      spFogAndLight.setUniform("fogParams.fStart", FogParameters::fStart);
      spFogAndLight.setUniform("fogParams.fEnd", FogParameters::fEnd);
      spFogAndLight.setUniform("fogParams.fDensity", FogParameters::fDensity);
   // ..

We just set these parameters, and we're ready to render a scene with fog. There is spiral made of box, it's coded in a minimalistic manner, but it shouldn't be a problem to understand how it works. If it is, let me know.


Result seems to be very nice, see for yourself:

Don't forget to play around with keys 'F', '+', '-', PageUp and PageDown to change fog parameters and see the difference between different equations and their settings.

If you have problems with code compilation, don't forget to update libraries glm and FreeType to their latest versions. I'm trying to use latest versions in these tutorials.

Well, that's all for now, hope you liked it and the fog using shaders has been demystified for you LULZ. See you next time with lighting continued, we'll discuss point lights.

Download (2.13 MB)
4339 downloads. 30 comments


Enter the text from image:


Matthewstets (hsmw54804@first.baburn.com) on 18.08.2017 13:27:01


<a href=http://www.gprs-controladores.es/oakley-radar-path-mujer-432.html>Oakley Radar Path Mujer</a>
<a href=http://www.laslunasdeampudia.es/new-balance-look-mujer-672.html>New Balance Look Mujer</a>
<a href=http://www.probaiedumontsaintmichel.fr/247-new-balance-574-bleu-ciel.php>New Balance 574 Bleu Ciel</a>
<a href=http://www.defunkte.es/polo-ralph-lauren-madrid-tiendas-272.php>Polo Ralph Lauren Madrid Tiendas</a>
<a href=http://www.uffg.es/jordan-flight-2017-para-mujer-720.html>Jordan Flight 2017 Para Mujer</a>
Richarddync (jsrd59589@first.baburn.com) on 14.08.2017 10:44:48


<a href=http://www.chokoloskee.fr/ralph-lauren-veste-matelassée-542.php>Ralph Lauren Veste Matelassée</a>
<a href=http://www.or-design.fr/chaussures-fila-annees-90-054.html>Chaussures Fila Annees 90</a>
<a href=http://www.claudegouron.fr/louboutin-sandales-2015-630.php>Louboutin Sandales 2015</a>
<a href=http://www.claudegouron.fr/chaussures-louboutin-femme-nouvelle-collection-451.php>Chaussures Louboutin Femme Nouvelle Collection</a>
<a href=http://www.xavier-massonnaud.fr/site-lunettes-282.php>Site Lunettes</a>
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:42:05
aewfrefdsffdfdsfdf [url=http://vipvoy.activeboard.com/][/url] <a href=http://vipvoy.activeboard.com/></a> dfdgfdgtgbhyjnhnhgmuj
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:41:36
dsfdsavdsvfgrdwr3e [url=http://vipvoy.activeboard.com/][/url] <a href=http://vipvoy.activeboard.com/></a> grgfdfgfdgfdgfdgfdgee
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:41:06
dfdsaffcdcv343sdvg [url=http://gymngym630jpg.blogspot.com/][/url] <a href=/>http://gymngym630jpg.blogspot.com</a> sdfddsfdsfdsfdfdfdfavdfr
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:40:15
dfadsfdsfdsfdfdad6 [url=http://gymngym630jpg.blogspot.com/][/url] <a href=/http://gymngym630jpg.blogspot.com></a> sdfsdafdsfdsdsfdfdffd
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:39:43
3wefdfer4dfdafsaff [url=http://vipvoyeurthongs.blogspot.com/][/url] <a href=http://vipvoyeurthongs.blogspot.com/></a> sdfdsfdsfdsfddfdfdf
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:39:10
egfdgdgvdfgdgfvffg [url=http://vipvoyeurthongs.blogspot.com/][/url] <a href=http://vipvoyeurthongs.blogspot.com/></a> adsfadsfdfdfadfd
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:38:38
rgtregfdgfgfgfgfgf [url=http://milfedup3.blogspot.com/][/url] <a href=http://milfedup3.blogspot.com/></a> afdsfdfdfdvdfrgfgrtad
non rechargeble batteries and adpapter (sexysoffershorts@@gmail.com) on 03.08.2017 02:38:03
dasfewrfwedcdcdvcd [url=http://milfedup3.blogspot.com/][/url] <a href=http://milfedup3.blogspot.com/></a> dffgerdfdfaeasdvdffef
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:37:31
afdsfdfdfdfdfdfdff [url=http://videosewnon.blogspot.com/][/url] <a href=http://videosewnon.blogspot.com/></a> dfadsffdafdffadsfdsfd
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:36:58
wrdasfdsafvdfdsfer [url=http://videosewnon.blogspot.com/][/url] <a href=http://videosewnon.blogspot.com/></a> ssferwerasfdfdfdsfder
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:36:24
adsfdersdfdsdfdfdf [url=http://vipvoy.xmatch.com/][/url] <a href=http://vipvoy.xmatch.com/></a> dsfregthyjufdsered
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:35:51
asfewdsffasfdddfdf [url=http://vipvoy.xmatch.com/][/url] <a href=http://vipvoy.xmatch.com/></a> dfderereafadfreasdf
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:35:08
qwddser5ty67u8i9oj [url=http://vipvoy.com/]vipvoy[/url] <a href=http://vipvoy.com/>vipvoy</a> wrtbnjjmkkiibuv7c
non rechargeble batteries and adpapter (sexysoffershorts@gmail.com) on 03.08.2017 02:34:28

asdfdfgdf23efvfdfv [url=http://vipvoy.com/]vipvoy[/url] <a href=http://vipvoy.com/>vipvoy</a> dafffghytr35sdew3
MerlinBot (fakj43226@rng.marvsz.com) on 24.07.2017 14:16:02
<a href=https://www.isabellabrancolini.it/images/originals/3650-adidas-gazelle-in-offerta.jpg>Adidas Gazelle In Offerta</a>
Take into account alternative sorts of giving blood insulin when you are diabetic person. Daily needle sticks can be unpleasant, which pain can sometimes result in overlooked doses. An insulin push might be a more sensible choice. Insulin inhalers should also be accessible shortly. Discuss these options with the medical professional to discover the one that works for you.

<a href=https://www.isabellabrancolini.it/images/no_picture.gif><img src="https://www.isabellabrancolini.it/images/no_picture.gif"></a>

Ingesting appropriately is probably the best possible actions to take for your skin. If you're consuming plenty of fresh vegatables and fruits, it means you're acquiring the correct quantity of minerals and vitamins. That means your skin ought to remain searching its very best.

<a href=https://www.isabellabrancolini.it/images/originals/14496-adidas-nmd-x-supreme.jpg><img src="https://www.isabellabrancolini.it/images/originals/14496-adidas-nmd-x-supreme.jpg"></a>
Richarddync (bgcc72736@first.baburn.com) on 22.07.2017 13:17:18


<a href=http://www.bancadatigiovani.it/570-adidas-originals-superstar-bianche.php>Adidas Originals Superstar Bianche</a>
<a href=http://www.notcom.it/532-nike-free-rn-distance-grey.html>Nike Free Rn Distance Grey</a>
<a href=http://www.firenzerestauro.it/nike-free-men-770.php>Nike Free Men</a>
<a href=http://www.claudiorussofotografo.it/859-nike-air-max-2016-oro.htm>Nike Air Max 2016 Oro</a>
<a href=http://www.blackbox-online.it/048-nike-cortez-forrest-gump-on-feet.htm>Nike Cortez Forrest Gump On Feet</a>
Curtisst (trrp36973@first.baburn.com) on 18.07.2017 01:53:37


<a href=http://www.debezetting.nl/le-coq-sportif-kinderschoenen-maat-23-731.html>Le Coq Sportif Kinderschoenen Maat 23</a>
<a href=http://www.theloanarrangers.co.uk/adidas-ultra-boost-uncaged-teal-239.php>Adidas Ultra Boost Uncaged Teal</a>
<a href=http://www.wellnessanco.nl/496-adidas-schoenen-maat-25.php>Adidas Maat</a>
<a href=http://www.sparkelecvideo.es/539-tenis-jordan-flight-97.html>Tenis Jordan Flight 97</a>
<a href=http://www.paintballdegrotewielen.nl/jordan-10-london-983.php>Jordan 10 London</a>
Curtisst (scbp44605@first.baburn.com) on 01.07.2017 21:10:35


<a href=http://www.eltotaxi.nl/nike-air-max-1-mid-sneakerboot-041.php>Nike Air Max 1 Mid Sneakerboot</a>
<a href=http://www.pcbodelft.nl/168-nike-sneakers-zwart-roze.html>Nike Sneakers Zwart Roze</a>
<a href=http://www.wallbank-lfc.co.uk/527-adidas-shoes-new-collection-2017.htm>Adidas Shoes New Collection 2017</a>
<a href=http://www.postenblankestijn.nl/609-air-max-1-premium-style-number-512033-404.htm>Air Max 1 Premium Style Number 512033-404</a>
<a href=http://www.adhi.es/botas-de-futbol-adidas-messi-2017-360.php>Botas Futbol</a>
Jump to page:
1 2