summaryrefslogtreecommitdiff
path: root/demo/atmospheric.cpp
blob: a82e228d800b2067a8a894d2db035f8b1d1f4c27 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// This code contains NVIDIA Confidential Information and is disclosed 
// under the Mutual Non-Disclosure Agreement. 
// 
// Notice 
// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES 
// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO 
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT, 
// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. 
// 
// NVIDIA Corporation assumes no responsibility for the consequences of use of such 
// information or for any infringement of patents or other rights of third parties that may 
// result from its use. No license is granted by implication or otherwise under any patent 
// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless 
// expressly authorized by NVIDIA.  Details are subject to change without notice. 
// This code supersedes and replaces all information previously supplied. 
// NVIDIA Corporation products are not authorized for use as critical 
// components in life support devices or systems without express written approval of 
// NVIDIA Corporation. 
// 
// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved.
//
// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
// rights in and to this software and related documentation and any modifications thereto.
// Any use, reproduction, disclosure or distribution of this software and related
// documentation without an express license agreement from NVIDIA Corporation is
// strictly prohibited.
//
 
#include "DXUT.h"
#include "atmospheric.h"

#pragma warning(disable:4127)

//-----------------------------------------------------------------------------
// Mie + Raileigh atmospheric scattering code 
// based on Sean O'Neil Accurate Atmospheric Scattering 
// from GPU Gems 2 
//-----------------------------------------------------------------------------

float scale(float fCos, float fScaleDepth)
{
	float x = 1.0f - fCos;
	return fScaleDepth * exp(-0.00287f + x*(0.459f + x*(3.83f + x*(-6.80f + x*5.25f))));
}

float atmospheric_depth(D3DXVECTOR3 position, D3DXVECTOR3 dir){
	float a = D3DXVec3Dot(&dir, &dir);
	float b = 2.0f*D3DXVec3Dot(&dir, &position);
	float c = D3DXVec3Dot(&position, &position)-1.0f;
	float det = b*b-4.0f*a*c;
	float detSqrt = sqrt(det);
	float q = (-b - detSqrt)/2.0f;
	float t1 = c/q;
	return t1;
}

AtmosphereColorsType CalculateAtmosphericScattering(D3DXVECTOR3 EyeVec, D3DXVECTOR3 VecToLight, float LightIntensity)
{
	AtmosphereColorsType output;
	static const int nSamples = 5;
	static const float fSamples = 5.0;

	D3DXVECTOR3 fWavelength = D3DXVECTOR3(0.65f,0.57f,0.47f);		// wavelength for the red, green, and blue channels
	D3DXVECTOR3 fInvWavelength = D3DXVECTOR3(5.60f,9.47f,20.49f);	// 1 / pow(wavelength, 4) for the red, green, and blue channels
	float fOuterRadius = 6520000.0f;								// The outer (atmosphere) radius
	float fOuterRadius2 = 6520000.0f*6520000.0f;					// fOuterRadius^2
	float fInnerRadius = 6400000.0f;								// The inner (planetary) radius
	float fInnerRadius2 = 6400000.0f*6400000.0f;					// fInnerRadius^2
	float fKrESun = 0.0075f * LightIntensity;						// Kr * ESun	// initially was 0.0025 * 20.0
	float fKmESun = 0.0001f * LightIntensity;						// Km * ESun	// initially was 0.0010 * 20.0;
	float fKr4PI = 0.0075f*4.0f*3.14f;								// Kr * 4 * PI
	float fKm4PI = 0.0001f*4.0f*3.14f;								// Km * 4 * PI
	float fScale = 1.0f/(6520000.0f - 6400000.0f);					// 1 / (fOuterRadius - fInnerRadius)
	float fScaleDepth	= 0.25f;									// The scale depth (i.e. the altitude at which the atmosphere's average density is found)
	float fScaleOverScaleDepth = (1.0f/(6520000.0f - 6400000.0f)) / 0.25f;	// fScale / fScaleDepth
	float G =	-0.98f;												// The Mie phase asymmetry factor
	float G2 = (-0.98f)*(-0.98f);

	// Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere)
	float d = atmospheric_depth(D3DXVECTOR3(0,0,fInnerRadius/fOuterRadius),EyeVec);
	D3DXVECTOR3 Pos = fOuterRadius*EyeVec*d+D3DXVECTOR3(0,0.0,fInnerRadius);
	D3DXVECTOR3 Ray = fOuterRadius*EyeVec*d;
	float  Far = D3DXVec3Length(&Ray);
	Ray /= Far;
	


	// Calculate the ray's starting position, then calculate its scattering offset
	D3DXVECTOR3 Start = D3DXVECTOR3(0,0,fInnerRadius);
	float Height = D3DXVec3Length(&Start);
	float Depth = 1.0;
	float StartAngle = D3DXVec3Dot(&Ray, &Start) / Height;
	float StartOffset = Depth*scale(StartAngle, fScaleDepth);

	// Initialize the scattering loop variables
	float SampleLength = Far / fSamples;
	float ScaledLength = SampleLength * fScale;
	D3DXVECTOR3 SampleRay = Ray * SampleLength;
	D3DXVECTOR3 SamplePoint = Start + SampleRay * 0.5;

	// Now loop through the sample points
	D3DXVECTOR3 SkyColor = D3DXVECTOR3(0.0, 0.0, 0.0);
	D3DXVECTOR3 Attenuate;
	for(int i=0; i<nSamples; i++)
	{
		float Height = D3DXVec3Length(&SamplePoint);
		float Depth = exp(fScaleOverScaleDepth * (fInnerRadius - Height));
		float LightAngle = D3DXVec3Dot(&VecToLight, &SamplePoint) / Height;
		float CameraAngle = D3DXVec3Dot(&Ray, &SamplePoint) / Height;
		float Scatter = (StartOffset + Depth*(scale(LightAngle, fScaleDepth) - scale(CameraAngle, fScaleDepth)));
		Attenuate.x = exp(-Scatter * (fInvWavelength.x * fKr4PI + fKm4PI));
		Attenuate.y = exp(-Scatter * (fInvWavelength.y * fKr4PI + fKm4PI));
		Attenuate.z = exp(-Scatter * (fInvWavelength.z * fKr4PI + fKm4PI));
		SkyColor += Attenuate * (Depth * ScaledLength);
		SamplePoint += SampleRay;
	}
	D3DXVECTOR3 MieColor = SkyColor * fKmESun;
	D3DXVECTOR3 RayleighColor;
	RayleighColor.x = SkyColor.x * (fInvWavelength.x * fKrESun);
	RayleighColor.y = SkyColor.y * (fInvWavelength.y * fKrESun);
	RayleighColor.z = SkyColor.z * (fInvWavelength.z * fKrESun);
	
	float fcos = -D3DXVec3Dot(&VecToLight, &EyeVec) / D3DXVec3Length(&EyeVec);
	float fMiePhase = 1.5f * ((1.0f - G2) / (2.0f + G2)) * (1.0f + fcos*fcos) / pow(1.0f + G2 - 2.0f*G*fcos, 1.5f);
	output.RayleighColor = RayleighColor;
	output.MieColor = fMiePhase* MieColor;
	output.Attenuation = Attenuate;
	return output;   
}