|
|
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'
|
|