⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atmosphericscatteringcomputer.java

📁 world wind java sdk 源码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
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 + -