📄 atmosphericscatteringcomputer.java
字号:
package gov.nasa.worldwind.examples.sunlight;
import gov.nasa.worldwind.geom.*;
import java.awt.*;
/**
* Computes the color of the atmosphere according to the Sun position, the eye position and a direction.
* <p>
* Based on code from Sean O'Neil "Real-Time Atmospheric Scattering" Gamedev article and C++ demo.<br />
* http://www.gamedev.net/reference/articles/article2093.asp<br />
* http://sponeil.net
*
* @author Patrick Murris
* @version $Id: AtmosphericScatteringComputer.java 10406 2009-04-22 18:28:45Z patrickmurris $
*/
public class AtmosphericScatteringComputer
{
private float fInnerRadius;
private float fOuterRadius;
private float fScale;
private int nSamples = 4; // Number of sample rays to use in integral equation
private float Kr = 0.001f; //0.0025f; // Rayleigh scattering constant
private float Kr4PI = Kr * 4.0f * (float)Math.PI;
private float Km = 0.0015f; // Mie scattering constant
private float Km4PI = Km * 4.0f * (float)Math.PI;
private float ESun = 15.0f; // Sun brightness constant
private float g = -0.85f; // The Mie phase asymmetry factor
private float fRayleighScaleDepth = 0.25f;
private float fMieScaleDepth = 0.1f;
private float[] fWavelength = new float[] {0.650f, 0.570f, 0.475f}; // 650nm red, 570nm green, 475nm blue
private float[] fWavelength4 = new float[3];
private float[] fCameraDepth = new float[] { 0, 0, 0, 0 };
private float[] fLightDepth = new float[4];
private float[] fSampleDepth = new float[4];
private float[] fRayleighSum = new float[] { 0, 0, 0 };
private float[] fMieSum = new float[] { 0, 0, 0 };
private float[] fAttenuation = new float[3];
// Optical depth buffer
private float[] opticalDepthBuffer;
private float DELTA = 1e-6f;
private int nChannels = 4;
private int nBufferWidth = 128;
private int nBufferHeight = 128;
private Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0);
public AtmosphericScatteringComputer(double globeRadius, double thickness)
{
// Init
fWavelength4[0] = (float)Math.pow(fWavelength[0], 4.0f);
fWavelength4[1] = (float)Math.pow(fWavelength[1], 4.0f);
fWavelength4[2] = (float)Math.pow(fWavelength[2], 4.0f);
fInnerRadius = (float)globeRadius;
fOuterRadius = (float)(globeRadius + thickness);
fScale = 1.0f / (fOuterRadius - fInnerRadius);
// Init optical depth buffer
this.computeOpticalDepthBuffer();
}
public Color getAtmosphereColor(Vec4 lookAtPoint, Vec4 eyePoint, Vec4 lightDirection)
{
// Find out intersection point on world scattering sphere
Vec4 vRay = lookAtPoint.subtract3(eyePoint);
vRay = vRay.normalize3();
// Calculate the closest intersection of the ray with the outer atmosphere
float B = 2.0f * (float)eyePoint.dot3(vRay);
float C = (float)(eyePoint.dotSelf3() - fOuterRadius * fOuterRadius);
float fDet = B * B - 4.0f * C;
Color color = TRANSPARENT_COLOR;
if (fDet >= 0)
{
// Camera ray intersect atmosphere
float fNear1 = 0.5f * (-B - (float)Math.sqrt(fDet));
float fNear2 = 0.5f * (-B + (float)Math.sqrt(fDet));
if (fNear1 >= 0 || fNear2 >= 0)
{
// largest distance - not sure why...
float fNear = Math.max(fNear1, fNear2);
Vec4 vPos = eyePoint.add3(vRay.multiply3(fNear));
color = getColorForVertex(vPos, eyePoint, lightDirection);
}
}
return color;
}
private Color getColorForVertex(Vec4 vPos, Vec4 vCamera, Vec4 vLightDirection)
{
// Get the ray from the camera to the vertex, and its length (which is the far point of the ray
// passing through the atmosphere)
Vec4 vRay = vPos.subtract3(vCamera);
float fFar = (float)vRay.getLength3();
vRay = vRay.normalize3();
// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point
// of the ray passing through the atmosphere)
float B = 2.0f * (float)vCamera.dot3(vRay);
float C = (float)(vCamera.dotSelf3() - fOuterRadius * fOuterRadius);
float fDet = Math.max(0.0f, B * B - 4.0f * C);
float fNear = 0.5f * (-B - (float)Math.sqrt(fDet));
boolean bCameraAbove = true;
for (int i = 0; i < fCameraDepth.length; i++)
fCameraDepth[i] = 0;
for (int i = 0; i < fLightDepth.length; i++)
fLightDepth[i] = 0;
for (int i = 0; i < fSampleDepth.length; i++)
fSampleDepth[i] = 0;
if (fNear <= 0)
{
// If the near point is behind the camera, it means the camera is inside the atmosphere
fNear = 0;
float fCameraHeight = (float)vCamera.getLength3();
float fCameraAltitude = (fCameraHeight - fInnerRadius) * fScale;
bCameraAbove = fCameraHeight >= vPos.getLength3();
float fCameraAngle = (float)(bCameraAbove ? vRay.getNegative3().dot3(vCamera) : vRay.dot3(vRay)) / fCameraHeight;
interpolate(fCameraDepth, fCameraAltitude, 0.5f - fCameraAngle * 0.5f);
}
else
{
// Otherwise, move the camera up to the near intersection point
vCamera = vCamera.add3(vRay.multiply3(fNear));
fFar -= fNear;
fNear = 0;
}
// If the distance between the points on the ray is negligible, don't bother to calculate anything
if (fFar <= DELTA)
{
return TRANSPARENT_COLOR;
}
// Initialize a few variables to use inside the loop
for (int i = 0; i < fRayleighSum.length; i++)
fRayleighSum[i] = 0;
for (int i = 0; i < fMieSum.length; i++)
fMieSum[i] = 0;
float fSampleLength = fFar / nSamples;
float fScaledLength = fSampleLength * fScale;
Vec4 vSampleRay = vRay.multiply3(fSampleLength);
// Start at the center of the first sample ray, and loop through each of the others
vPos = vCamera.add3(vSampleRay.multiply3(0.5f));
for (int i = 0; i < nSamples; i++)
{
float fHeight = (float)vPos.getLength3();
// Start by looking up the optical depth coming from the light source to this point
float fLightAngle = (float)vLightDirection.dot3(vPos) / fHeight;
float fAltitude = (fHeight - fInnerRadius) * fScale;
interpolate(fLightDepth, fAltitude, 0.5f - fLightAngle * 0.5f);
// If no light light reaches this part of the atmosphere, no light is scattered in at this point
if (fLightDepth[0] > DELTA)
{
// Get the density at this point, along with the optical depth from the light source to this point
float fRayleighDensity = fScaledLength * fLightDepth[0];
float fRayleighDepth = fLightDepth[1];
float fMieDensity = fScaledLength * fLightDepth[2];
float fMieDepth = fLightDepth[3];
// If the camera is above the point we're shading, we calculate the optical depth from the sample point to the camera
// Otherwise, we calculate the optical depth from the camera to the sample point
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -