POV-Ray : Newsgroups : povray.binaries.tutorials : TerraPOV - Sky system - Atmosphere - Part3, A Blue Sky : TerraPOV - Sky system - Atmosphere - Part3, A Blue Sky Server Time
9 Nov 2024 10:58:21 EST (-0500)
  TerraPOV - Sky system - Atmosphere - Part3, A Blue Sky  
From: Bruno Cabasson
Date: 6 May 2009 07:23:10
Message: <op.uth9wqlmm1sclq@pignouf>
Hello, It's me again.

After the general considerations, we now enter the core of the physical  
model of TerraPOV's Sky System: Getting a 'real' blue sky by Rayleigh  
scattering. In a previous article, I recommended the reader to refer to  
the web for Rayleigh scattering and blue sky. However, I feel like I can  
briefly expose the principle.

1) Rayleigh scattering
----------------------
Small particles have a physical property towards light that depends on the  
wavelength of the light and the size (and shape) of the said particles,  
and this property is called scattering. An incident ray of light is  
scattered in all directions according to a specific pattern as a  
consequence of the corresponding formula (Rayleigh). Air molecules have  
the property of scattering in the visible spectrum, and more in the short  
wavelengths (blue) than in longer wavelengths (red), by the 4th power of  
the ratio of wavelength. POV-Ray implements this type of scattering with  
type 4 (RAYLEIGH_SCATTERING in consts.inc), but only implements the  
pattern and is not wavelength-dependant. TerraPOV will do that through the  
chosen scaterring color by defining the amount of scattering of the 3  
red/green/blue components.

Now let's draw a white light ray through a medium that has Rayleigh  
scattering properties. The spectrum of the light constains more or less  
all wavelengths in the visible spectrum. What happens? The short  
wavelengths are scattered much more in other directions than the incident,  
and more than longer wavelengths. In the incident direction, the remainig  
spectrum has less short wavelengths than longer ones. That is: contains  
less blue than red. It becomes yellowish. In the other directions, it is  
the counterpart: it contains more blue that the other wavelentghs.

So, we have: in the direction of light (sun) blue has been reduced, the  
'white' sun light becomes yellowish (very bright ...), in all the other  
directions we see the blue rays that were scattered by the air molecules.  
As the light encounters more molecules during its travel (combination of  
path length and density of the medium, ie integration), its spectrum loses  
more and more short wavelengths: blue at first, then green, etc... At low  
elevations of the sun, he light travels longer through denser medium, and  
the sky near the horizon becomes red.

2) Density
----------
We saw in a previous article that the density d of the athmosphere  
descreases with altitude h by a function that can be expressed like:

    d = Dmax*exp(-k*h/T)

where Dmax is the density at level y=0, T is the considered thickness of  
atmosphere, and k is a factor.

TerraPOV will valuate Dmax = 1, T = 50*km, and k = 6.7,, but all are  
controllable.

In order to have more flexibility over the k factor which is very  
important in the result, TerraPOV splits k into a base factor of 6.7, and  
a multiplying factor defauted to 1 that expresses the 'distance' to  
'normality'.

The altitude h is NOT the y-coordinate, but indeed the vertical distance  
to the surface.

So we can write the following in our previous code:

#declare TP_BASE_RAYLEIGH_POWER = 6.7;  // Constant
#declare TP_RAYLEIGH_FACTOR = 1; // User defined
#declare _tp_rayleigh_power = TP_BASE_RAYLEIGH_POWER*TP_RAYLEIGH_FACTOR;

#declare TP_ATMO_THICKNESS = 50*km;
#declare TP_RAYLEIGH_DENSITY_MAX = 1;

#declare _tp_rayleigh_density = density
{
     function
     {
        
TP_RAYLEIGH_DENSITY_MAX*exp(-_tp_rayleigh_power*(sqrt(x*x+(y+TP_EARTH_RADIUS)*(y+TP_EARTH_RADIUS)+z*z)
 
- TP_EARTH_RADIUS)/TP_ATMO_THICKNESS)
     }
}

3) Scattering color
-------------------
As mentionned above, the amount of scattering is a function of the  
wavelength, or of a ratio of wavelengths. Scattering is more important for  
blue, less for green, and less for red. We take the blue as reference and  
take into account the fact that Rayleigh scattering is proportionnal to  
the 4th power of the ratio in wavelengths. This implies that we define  
wavelengths for our primary colors:

#declare TP_LAMBDA_RED = 650;   // nanometres
#declare TP_LAMBDA_GREEN = 555; // nanometres
#declare TP_LAMBDA_BLUE = 460;  // nanometres

#declare TP_RAYLEIGH_SCATTERING_COLOR = rgb  
<pow(TP_LAMBDA_BLUE/TP_LAMBDA_RED, 4), pow(TP_LAMBDA_BLUE/TP_LAMBDA_GREEN,  
4), 1>;

4) Media
--------
Who says media in POV, says sampling parameters. Let's make them TerraPOV  
parameters.

#declare TP_ATMO_INTERVALS = 3; // Necessary for good integration
#declare TP_ATMO_SAMPLES = 3;
#declare TP_ATMO_METHOD = 3; // Adaptive

Theses values will later be controlled by a global quality/preview switch.  
But for now, this is OK. The color used for the media controls the amount  
of scattering. As the density is normalized to 1 (TP_RAYLEIGH_DENSITY_MAX  
= 1 by default), and the light travels through TP_ATMO_THICKNESS media, we  
must compensate by dividing the amount by some normalizing value, and  
TP_ATMO_THICKNESS itself is a good candidate. We use a specific  
multiplying parameter to adjust the amount of scattering, and default it  
to 1.

#declare TP_RAYLEIGH_AMOUNT = 1;

The TerraPOV's media for the Rayleigh aspect can be written as:

#declare _tp_rayleigh_media = media
{
     method TP_ATMO_METHOD
     intervals TP_ATMO_INTERVALS
     samples TP_ATMO_SAMPLES = 3
     scattering
     {
	RAYLEIGH_SCATTERING
	color TP_RAYLEIGH_AMOUNT*TP_RAYLEIGH_SCATTERING_COLOR/TP_ATMO_THICKNESS
	extinction 1 // The only physically accurate value
     }
     density {_tp_rayleigh_density}
}

5)Atmophere's shell
--------------------
TerraPOV uses a spherical shell around the Earth for the atmosphere. This  
container is filled with our atmospheric media we just defined. The shell  
has a defined thikness (TP_ATMO_THICKNESS) and assumes it starts at level  
0. We can add a parameter to control the bottom altitude of the  
atmosphere. This allows, among other things, to prevent coincident surface  
artifact between Earth and atmosphere, and to put the camera outside the  
container. This forces us to redefine a bit the density  
_tp_rayleigh_density.

#declare TP_ATMO_BOTTOM = -1*m;
#declare _tp_rayleigh_density = density
{
     function
     {
        
TP_RAYLEIGH_DENSITY_MAX*exp(-_tp_rayleigh_power*(sqrt(x*x+(y+TP_EARTH_RADIUS)*(y+TP_EARTH_RADIUS)+z*z)
 
- TP_EARTH_RADIUS - TP_ATMO_BOTTOM)/TP_ATMO_THICKNESS)
     }
}

The shell is made of differenced spheres, filled with our media:

#declare _tp_rayleigh_atmosphere = difference
{
     sphere {0, TP_EARTH_RADIUS + TP_ATMO_BOTTOM + TP_ATMO_THICKNESS  
translate -TP_EARTH_RADIUS*y}
     sphere {0, TP_EARTH_RADIUS + TP_ATMO_BOTTOM translate  
-TP_EARTH_RADIUS*y}
     hollow
     pigment {rgbt 1}
     interior {media{_tp_rayleigh_media}}
}

6) Render
---------
We just add this statement

object {_tp_rayleigh_atmosphere}

and run ...

Yessssss!!!!

We get the attached image. It is the result without any tuning and  
refinement for a PURE atmosphere, made only of air molecules, and taking  
into account only the Rayleigh scattering effect, without anything else.  
The true atmosphere is more complex. We have still a long way to go before  
we can say that we are arrived to a good model. But even though this model  
in still basic, it is quite satisfactory.

Next article will play with the parameters and try to draw guidelines for  
improvements: TerraPOV - Sky system - Atmosphere - Part4, A Better model


Bruno


PS: Here is the code.

#include "colors.inc"
#include "consts.inc"

global_settings
{
     #if (version < 3.7) assumed_gamma 1 #end
     max_trace_level 20
}

// Units
#declare m = 0.1; // A value of 1 makes the sun's distance ouside POV's  
numerical domain.
#declare km = 1000*m;
#declare mm = 0.001*m;

//    -------------
// -- | Parameters | ------
//    -------------
// Earth parameters
#declare TP_EARTH_RADIUS = 6378.137*km;

// Sun parameters
#declare TP_SUN_HEADING = 0;
#declare TP_SUN_ELEVATION = 15;
#declare TP_BRIGHTNESS = 1;
#declare TP_SUN_COLOR = White;
#declare TP_SUN_APPARENT_APERTURE = 0.5; // Commonly admitted value

// Atmosphere parameters
#declare TP_ATMO_BOTTOM = -1*m;

#declare TP_RAYLEIGH_FACTOR = 1;
#declare TP_RAYLEIGH_DENSITY_MAX = 1;
#declare TP_RAYLEIGH_AMOUNT = 1;

#declare TP_ATMO_INTERVALS = 3; // Necessary for good integration
#declare TP_ATMO_SAMPLES = 3;
#declare TP_ATMO_METHOD = 3; // Adaptive

// Default camera parameters
#declare TP_DEFCAM_HEIGHT = 2*m; // Let's be tall
#declare TP_DEFCAM_HEADING = 0;
#declare TP_DEFCAM_ELEVATION = 5; // Let's look up a little
#declare TP_DEFCAM_ANGLE = 40;

//    -------------
// -- |  Engine   | ------
//    -------------

// Earth
#declare _tp_earth = sphere
{
     0, TP_EARTH_RADIUS
     pigment {White} // Could be any predefined texture, but normally, the  
terrain hides the sphere
     finish {ambient 0}
     translate -TP_EARTH_RADIUS*y
}

// Sun
#declare TP_SUN_DISTANCE = 10*TP_EARTH_RADIUS; // Far enough. Actual  
distance in the scene is not very critical, as the light ays are parallel
#declare TP_SUN_RADIUS =  
TP_SUN_DISTANCE*tan(radians(TP_SUN_APPARENT_APERTURE/2));
#declare _tp_basic_sun = light_source
{
   <0, 0, 0>
   color rgb TP_SUN_COLOR*TP_BRIGHTNESS
   looks_like {sphere{0, TP_SUN_RADIUS pigment{Yellow} finish {diffuse 0  
ambient 1}}}
   translate TP_SUN_DISTANCE*z
   parallel point_at -z
   rotate -TP_SUN_ELEVATION*x
   rotate TP_SUN_HEADING*y
}

// Atmosphere: density
#declare TP_BASE_RAYLEIGH_POWER = 6.7;  // Constant
#declare _tp_rayleigh_power = TP_BASE_RAYLEIGH_POWER*TP_RAYLEIGH_FACTOR;
#declare TP_ATMO_THICKNESS = 50*km;
#declare _tp_rayleigh_density = density
{
     function
     {
        
TP_RAYLEIGH_DENSITY_MAX*exp(-_tp_rayleigh_power*(sqrt(x*x+(y+TP_EARTH_RADIUS)*(y+TP_EARTH_RADIUS)+z*z)
 
- TP_EARTH_RADIUS - TP_ATMO_BOTTOM)/TP_ATMO_THICKNESS)
     }
}

// Atmosphere: scattering color
#declare TP_LAMBDA_RED = 650;   // nanometres
#declare TP_LAMBDA_GREEN = 555; // nanometres
#declare TP_LAMBDA_BLUE = 460;  // nanometres
#declare TP_RAYLEIGH_SCATTERING_COLOR = rgb  
<pow(TP_LAMBDA_BLUE/TP_LAMBDA_RED, 4), pow(TP_LAMBDA_BLUE/TP_LAMBDA_GREEN,  
4), 1>;

// Atmosphere: media
#declare _tp_rayleigh_media = media
{
     method TP_ATMO_METHOD
     intervals TP_ATMO_INTERVALS
     samples TP_ATMO_SAMPLES
     scattering
     {
	RAYLEIGH_SCATTERING
	color TP_RAYLEIGH_AMOUNT*TP_RAYLEIGH_SCATTERING_COLOR/TP_ATMO_THICKNESS
	extinction 1 // The only physically accurate value
     }
     density {_tp_rayleigh_density}
}

// Atmosphere: shell
#declare _tp_rayleigh_atmosphere = difference
{
     sphere {0, TP_EARTH_RADIUS + TP_ATMO_BOTTOM + TP_ATMO_THICKNESS  
translate -TP_EARTH_RADIUS*y}
     sphere {0, TP_EARTH_RADIUS + TP_ATMO_BOTTOM translate  
-TP_EARTH_RADIUS*y}
     hollow
     pigment {rgbt 1}
     interior {media{_tp_rayleigh_media}}
}

// Default camera
#declare _tp_default_camera = camera
{
     location 0
     angle TP_DEFCAM_ANGLE
     right     x*image_width/image_height
     look_at   z
     rotate -TP_DEFCAM_ELEVATION*x
     rotate TP_DEFCAM_HEADING*y
     translate TP_DEFCAM_HEIGHT*y // Could use trace() to make sure we are  
above the surface. But no terrain yet ...
}

// Scene
object {_tp_earth}
object {_tp_rayleigh_atmosphere}
object {_tp_basic_sun}
camera {_tp_default_camera}

-- 

http://www.opera.com/mail/


Post a reply to this message


Attachments:
Download 'firstbluesky.png' (14 KB)

Preview of image 'firstbluesky.png'
firstbluesky.png


 

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.