%
% `Sky.tex' -- describes the sky rendering procedure
%
%  Written by Curtis Olson.  Started December, 1997.
%
% $Id: robot.tex,v 1.20 1996/12/05 19:35:04 clolson Exp $
%------------------------------------------------------------------------


\documentclass[12pt]{article}

\usepackage{anysize}
\papersize{11in}{8.5in}
\marginsize{1in}{1in}{1in}{1in}

\usepackage{amsmath}

\usepackage{epsfig}

\usepackage{setspace}
\onehalfspacing

\usepackage{url}


\begin{document}


\title{
  Flight Gear Sky Representation and Rendering.
}


\author{
    Curtis L. Olson\\ 
    (\texttt{curt@me.umn.edu})
}


\maketitle


\section{Introduction}

No flight simulator should be without a nice sky that smoothly
transitions into haze at the horizon.  Such a sky should also be able
to render sunrise and sunset effects.  This document describes how we
have implemented such a sky.

\section{Overview}

The sky is represent as a 12 sided dome (or upside down bowl if you
prefer.)  Figure \ref{fig:dome} shows how a 6 sided dome might be
constructed.

\begin{figure}[hbt]
  \centerline{                   
      \psfig{file=dome.eps}
  }
  \caption{Simplified (6 Sided) Sky Dome}
  \label{fig:dome}
\end{figure}

The center section can be constructed with a triangle fan.  The inner
and outer ``skirts'' can be constructed with triangle strips.

The colors of each vertex can be independently controlled to achieve
sky to haze transitions, sunrise/sunset effects with a pinkish/oranges
glow, and one side of the sky can easily be made brighter than the
other.  By enabling smooth shading in OpenGL, the colors will be
blended together for a very nice effect.


\section{Implementation}

This sections describes how the sky has been implemented in OpenGL.

\subsection{Vertex Generation}

The sky dome structure is intended to be centered over the current
view point at sea level.  This way we could paste cloud textures on
the dome if we liked.  So, we simply have to generate vertices for a
fixed dome, and then use OpenGL calls to transform and rotate it to
the desired place.  Please refer to the actual code
(.../Src/Scenery/sky.c) for specifics, but
to generate the vertices we simply create a 12 element array for the
inner set of vertices, another 12 element array for the middle set of
vertices and a last 12 element array for the outer set of vertices.

\subsection{Vertex Coloring}

For each vertex position array, there is a corresponding vertex color
array.  This way we don't have to compute each vertex color every
iteration.  Also, by being able to individually control the color at
each vertex, we can do all sorts of nice sky to haze blending with
dusk and dawn effects.  Again, please refer to the source
(.../Src/Scenery/sky.c) for specific details on how the coloring is
implemented.  However, here's the quick overview.

\subsubsection{Day and Night Coloring}

For the general middle of the day, or middle of the night sky, we
already know the desired sky color, and the haze color.  This is
computed elsewhere based on the current sun position.  During the
night these colors are both nearly black.  During the dawn they are
smoothly transitioned to day time colors.  And, during the dusk they
are smoothly transitioned back to night time colors.

The center of the dome is assigned the current sky color.  The color
of the first inner ring of vertices is weighted 70\% towards the sky
color and 30\% towards the fog color.

Then color of the middle ring of vertices is weighted 10\% towards the
sky color and 90\% towards the fog color.

The the outer ring of vertices are assigned the current fog color.

\subsubsection{Dusk and Dawn Effects}

Dusk and dawn effects can be accomplished by controlling the color of
the vertices.  Rather than trying to figure out which vertices are
near the current sun position, I just rotate the dome so the 0'th
vertex of each ring (and the center fan) align with the sun.  This
makes it easier to calculate vertex colors.  But, there is a fair
amount of work involved in calculating the proper dome rotation.

\begin{figure}[hbt]
  \centerline{                   
      \psfig{file=earth.eps}
  }
  \caption{Overview of Earth}
  \label{fig:earth}
\end{figure}

Figure \ref{fig:earth} shows an overview of the setup.  $P$, the
current view position, and $\mathbf{n}$, the local ``up'' vector,
define the plane which is tangent to the Earth's surface at point $P$.
Just for a quick review of your linear algebra, given $\mathbf{v_0}$,
the position vector of $P$ and $\mathbf{v}$, the position vector of
some other arbitrary point on the plane, and $\mathbf{n}$, the normal
to the plane, then the vector $\mathbf{n}$ and the vector $(\mathbf{v}
- \mathbf{v_0})$ are orthogonal (perpendicular.)  If the two vectors
are orthogonal then their dot product will be zero, so the following
must be true:

\begin{equation}
  \mathbf{n} \cdot ( \mathbf{v} - \mathbf{v_0} ) = 0
\end{equation}

This is the vector equation of the plane and can be rewritten as:

\begin{align}
  a(x - x_0) + b(y - y_0) + c(z - z_0) &= 0 \\
  ax + by + cz - (\mathbf{n} \cdot \mathbf{v_0}) &= 0
\end{align}

We want to find a vector $\mathbf{v}$ representing the
direction along the current tangent plane towards the position on the
Earth where the Sun is directly overhead.  The vector $\mathbf{u}$ is
defined as $\vec{\mathbf{PS}}$.

\begin{figure}[hbt]
  \centerline{                   
      \psfig{file=local.eps}
  }
  \caption{Vectors and Points in Local Coordinate System}
  \label{fig:local}
\end{figure}

Figure \ref{fig:local} shows a more detailed ``local'' view of the
points and vectors involved.  The point, $P$, is the current view
point.  The vector, $\mathbf{n}$, is the local up vector.  $S$
represents the current position on the Earth's surface where the Sun
is directly overhead.  We want to find the vector, $\mathbf{v}$ which
is a projection of $\mathbf{u}$ onto the plane defined by $P$ and
$\mathbf{n}$.

To do this we first calculate $\mathbf{u_1}$ which is the shortest
distance from point $S$ to the tangent plane.

\begin{equation}
  \mathbf{u_1} = \frac { \mathbf{n} \cdot \mathbf{u} }
             { {\| \mathbf{n} \|}^2 } \mathbf{n}
\end{equation}

Armed with $\mathbf{u_1}$ we can now calculate
$\mathbf{v}$ which is the local surface direction on the tangent
plane towards the sun, $S$.

\begin{equation}
  \mathbf{v} = \mathbf{v_0} + \mathbf{u} - \mathbf{u_1}
\end{equation}

Ok, so now we have $\mathbf{v}$, but the fun doesn't stop here.  Now
we need to calculate a rotation angle $\theta$ about $\mathbf{n}$ to
align our dome with $\mathbf{v}$.  The origin of the dome always
aligns with a vector pointing directly South.  So, we need to repeat
the above procedure to map a vector pointing straight down $( 0, 0,
-\mathbf{z} )$ onto our tangent plane to produce the local, surface,
south vector $\mathbf{w}$.  We then take the $\arccos()$ of the dot product
of $\mathbf{v}$ with $\mathbf{w}$.

\begin{equation}
  \theta = \arccos( \mathbf{v} \cdot \mathbf{w} )
\end{equation}

Whew, that gives us the angle we want.  Well almost, not quite.  The
problem is that the dot product returns a number in the range of
$(-1.0 \ldots 1.0)$. Thus, the $\arccos()$ function returns a $\theta$
in the range of $(0.0 \ldots 180.0)$.  But this is not enough
information to determine if $\mathbf{v}$ is in the east hemisphere or
west hemisphere and if this angle should be positive or negative.

So, to get that last piece of information we need, we can rotate the
vector $\mathbf{w}$ by 90 degrees about $\mathbf{n}$.  This gives us
the local surface east vector on the tangent plane.  Taking the dot
product of $\mathbf{v}$ and the local east vector tells us which
hemisphere $\mathbf{v}$ is in.  And, from this, we can uniquely
determine the proper angle for the sky dome rotation.

\end{document}


%------------------------------------------------------------------------
% $Log: Makefile,v $
