当前位置: 动力学知识库 > 问答 > 编程问答 >

three.js - Atmosphere Scattering for Earth from space and on the ground

问题描述:

Please provide prompt how to make the atmosphere of the Earth so that it is visible from space and from the ground (as shown in the image)

a model of the earth:

Earth = new THREE.Mesh(new THREE.SphereGeometry(6700,32,32),ShaderMaterialEarth);

model of the cosmos:

 cosmos= new THREE.Mesh(new THREE.SphereGeometry(50000,32,32),ShaderMaterialCosmos);

and a light source:

sun = new THREE.DirectionalLight();

where to start, just I do not know. Perhaps this should do ShaderMaterialCosmos, where to pass position of the camera, and calculate how should be painted pixel. But how?

I tried using the following but get zero vectors at the entrance of the fragment shader

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html

vertexShader:

#define M_PI 3.1415926535897932384626433832795

const float ESun=1.0;

const float Kr = 0.0025;

const float Km = 0.0015;

const int nSamples = 2;

const float fSamples = 1.0;

const float fScaleDepth = 0.25;

varying vec2 vUv;

varying vec3 wPosition;

varying vec4 c0;

varying vec4 c1;

varying vec3 t0;

uniform vec3 v3CameraPos; , // The camera's current position

uniform vec3 v3LightDir; // Direction vector to the light source

uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for RGB

uniform float fCameraHeight; // The camera's current height

const float fOuterRadius=6500.0; // The outer (atmosphere) radius

const float fInnerRadius=6371.0; // The inner (planetary) radius

const float fKrESun=Kr*ESun; // Kr * ESun

const float fKmESun=Km*ESun; // Km * ESun

const float fKr4PI=Kr*4.0*M_PI; // Kr * 4 * PI

const float fKm4PI=Km*4.0*M_PI; // Km * 4 * PI

const float fScale=1.0/(fOuterRadius-fInnerRadius); // 1 / (fOuterRadius - fInnerRadius)

const float fScaleOverScaleDepth= fScale / fScaleDepth; // fScale / fScaleDepth

const float fInvScaleDepth=1.0/0.25;

float getNearIntersection(vec3 v3Pos, vec3 v3Ray, float fDistance2, float fRadius2)

{

float B = 2.0 * dot(v3Pos, v3Ray);

float C = fDistance2 - fRadius2;

float fDet = max(0.0, B*B - 4.0 * C);

return 0.5 * (-B - sqrt(fDet));

}

float scale(float fCos)

{

float x = 1.0 - fCos;

return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));

}

void main() {

// Get the ray from the camera to the vertex and its length (which

// is the far point of the ray passing through the atmosphere)

vec3 v3Pos = position.xyz;

vec3 v3Ray = v3Pos - v3CameraPos;

float fFar = length(v3Ray);

v3Ray /= fFar;

// Calculate the closest intersection of the ray with

// the outer atmosphere (point A in Figure 16-3)

float fNear = getNearIntersection(v3CameraPos, v3Ray, fCameraHeight*fCameraHeight, fOuterRadius*fOuterRadius);

// Calculate the ray's start and end positions in the atmosphere,

// then calculate its scattering offset

vec3 v3Start = v3CameraPos + v3Ray * fNear;

fFar -= fNear;

float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;

float fStartDepth = exp(-fInvScaleDepth);

float fStartOffset = fStartDepth * scale(fStartAngle);

// Initialize the scattering loop variables

float fSampleLength = fFar / fSamples;

float fScaledLength = fSampleLength * fScale;

vec3 v3SampleRay = v3Ray * fSampleLength;

vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

// Now loop through the sample points

vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);

for(int i=0; i<nSamples; i++) {

float fHeight = length(v3SamplePoint);

float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));

float fLightAngle = dot(v3LightDir, v3SamplePoint) / fHeight;

float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;

float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) * scale(fCameraAngle)));

vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));

v3FrontColor += v3Attenuate * (fDepth * fScaledLength);

v3SamplePoint += v3SampleRay;

}

wPosition = (modelMatrix * vec4(position,1.0)).xyz;

c0.rgb = v3FrontColor * (v3InvWavelength * fKrESun);

c1.rgb = v3FrontColor * fKmESun;

t0 = v3CameraPos - v3Pos;

vUv = uv;

}

fragmentShader:

float getMiePhase(float fCos, float fCos2, float g, float g2){

return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);

}

// Rayleigh phase function

float getRayleighPhase(float fCos2){

//return 0.75 + 0.75 * fCos2;

return 0.75 * (2.0 + 0.5 * fCos2);

}

varying vec2 vUv;

varying vec3 wPosition;

varying vec4 c0;

varying vec4 c1;

varying vec3 t0;

uniform vec3 v3LightDir;

uniform float g;

uniform float g2;

void main() {

float fCos = dot(v3LightDir, t0) / length(t0);

float fCos2 = fCos * fCos;

gl_FragColor = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;

gl_FragColor = c1;

}

网友答案:

Chapter 16 of GPU Gem 2 has nice explanation and illustration for achieving your goal in real time.

Basically you need to perform ray casting through the atmosphere layer and evaluate the light scattering.

分享给朋友:
您可能感兴趣的文章:
随机阅读: