/*******************************************************************************
* Copyright 2014 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.layers.atmosphere;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.render.DrawContext;
import java.awt.Color;
import au.gov.ga.earthsci.worldwind.common.util.Util;
/**
* Atmospheric scattering parameters.
* <p/>
* Based on Sean O'Neil's algorithm described in GPU Gems 2 <a
* href="http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html"
* >chapter 16</a>.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class Atmosphere
{
//atmosphere constants
final static float ATMOSPHERE_SCALE = 1.025f;
final static float RAYLEIGH_SCATTERING = 0.0025f;
final static float MIE_SCATTERING = 0.0015f;
final static float SUN_BRIGHTNESS = 18.0f;
final static float MIE_PHASE_ASYMMETRY = -0.990f;
final static float WAVELENGTH[] = new float[] {
0.731f,
0.612f,
0.455f
};
final static float SCALE_DEPTH = 0.25f;
final static float EXPOSURE = 2.0f;
//derived constants
final static float INVWAVELENGTH4[] = new float[] {
1f / (float) Math.pow(WAVELENGTH[0], 4),
1f / (float) Math.pow(WAVELENGTH[1], 4),
1f / (float) Math.pow(WAVELENGTH[2], 4)
};
/**
* Get the color of an object at a point in space, using the atmospheric
* scattering parameters defined by this layer.
*
* @param dc
* Current draw context, from which to get the current globe
* radius and eye point
* @param point
* Point to determine the color of
* @return Color of the object at the given point
*/
public static Color getSpaceObjectColor(DrawContext dc, Vec4 point)
{
double innerRadius = dc.getGlobe().getRadius();
double outerRadius = innerRadius * Atmosphere.ATMOSPHERE_SCALE;
Vec4 eyePoint = dc.getView().getEyePoint();
double cameraHeight = eyePoint.getLength3();
double cameraHeight2 = cameraHeight * cameraHeight;
double outerRadius2 = outerRadius * outerRadius;
Vec4 ray = point.subtract3(eyePoint);
double far = ray.getLength3();
ray = ray.divide3(far);
double B = 2.0 * eyePoint.dot3(ray);
double C = cameraHeight2 - outerRadius2;
double det = Math.max(0.0, B * B - 4.0 * C);
double near = 0.5 * (-B - Math.sqrt(det));
Vec4 start = eyePoint;
if (cameraHeight > outerRadius)
{
start = start.add3(ray.multiply3(near));
}
double scaleOverScaleDepth = (1f / (outerRadius - innerRadius)) / Atmosphere.SCALE_DEPTH;
double height = start.getLength3();
double depth = Math.exp(scaleOverScaleDepth * (innerRadius - cameraHeight));
double angle = ray.dot3(start) / height;
double scatter = depth * scale(angle, Atmosphere.SCALE_DEPTH);
double fKr4PI = Atmosphere.RAYLEIGH_SCATTERING * 4.0 * Math.PI;
double fKm4PI = Atmosphere.MIE_PHASE_ASYMMETRY * 4.0 * Math.PI;
double r = Util.clamp(Math.exp(-scatter * (Atmosphere.INVWAVELENGTH4[0] * fKr4PI + fKm4PI)), 0, 1);
double g = Util.clamp(Math.exp(-scatter * (Atmosphere.INVWAVELENGTH4[1] * fKr4PI + fKm4PI)), 0, 1);
double b = Util.clamp(Math.exp(-scatter * (Atmosphere.INVWAVELENGTH4[2] * fKr4PI + fKm4PI)), 0, 1);
return new Color((float) r, (float) g, (float) b);
}
protected static double scale(double cos, double scaleDepth)
{
double x = 1.0 - cos;
return scaleDepth * Math.exp(-0.00287 + x * (0.459 + x * (3.83 + x * (-6.80 + x * 5.25))));
}
}