mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-09-03 14:10:33 +03:00
0032606: Visualization - add a shader for sky V3d_View::BackgroundSkydome()
Introduced V3d_View::SkydomeAspect() property for generating skydome cubemap environment. Skydome features: day/night cycle, 2 types of clouds, atmosphere, water surface, stars, fog.
This commit is contained in:
@@ -24,6 +24,7 @@ srcinc:::PathtraceBase.fs
|
||||
srcinc:::RaytraceBase.vs
|
||||
srcinc:::RaytraceSmooth.fs
|
||||
srcinc:::TangentSpaceNormal.glsl
|
||||
srcinc:::SkydomBackground.fs
|
||||
Shaders_Declarations_glsl.pxx
|
||||
Shaders_DeclarationsImpl_glsl.pxx
|
||||
Shaders_DirectionalLightShadow_glsl.pxx
|
||||
@@ -48,3 +49,4 @@ Shaders_PathtraceBase_fs.pxx
|
||||
Shaders_RaytraceBase_vs.pxx
|
||||
Shaders_RaytraceSmooth_fs.pxx
|
||||
Shaders_TangentSpaceNormal_glsl.pxx
|
||||
Shaders_SkydomBackground_fs.pxx
|
||||
|
303
src/Shaders/Shaders_SkydomBackground_fs.pxx
Normal file
303
src/Shaders/Shaders_SkydomBackground_fs.pxx
Normal file
@@ -0,0 +1,303 @@
|
||||
// This file has been automatically generated from resource file src/Shaders/SkydomBackground.fs
|
||||
|
||||
static const char Shaders_SkydomBackground_fs[] =
|
||||
"// Constants\n"
|
||||
"const float M_PI = 3.1415926535;\n"
|
||||
"const float THE_EARTH_RADIUS = 6360e3;\n"
|
||||
"const vec3 THE_EARTH_CENTER = vec3 (0.0, -THE_EARTH_RADIUS, 0.0);\n"
|
||||
"const float THE_ATMO_RADIUS = 6380e3; // atmosphere radius (6420e3?)\n"
|
||||
"const float THE_G = 0.76; // anisotropy of the medium (papers use 0.76)\n"
|
||||
"const float THE_G2 = THE_G * THE_G;\n"
|
||||
"const float THE_HR = 8000.0; // Thickness of the atmosphere\n"
|
||||
"const float THE_HM = 1000.0; // Same as above but for Mie\n"
|
||||
"const vec3 THE_BETA_R = vec3 (5.8e-6, 13.5e-6, 33.1e-6); // Reyleigh scattering normal earth\n"
|
||||
"const vec3 THE_BETA_M = vec3 (21e-6); // Normal Mie scattering\n"
|
||||
"\n"
|
||||
"// Parameters\n"
|
||||
"const float THE_SunAttenuation = 1.0; // sun intensity\n"
|
||||
"const float THE_EyeHeight = 100.0; // viewer height\n"
|
||||
"const float THE_HorizonWidth = 0.002;\n"
|
||||
"const int THE_NbSamples = 8;\n"
|
||||
"const int THE_NbSamplesLight = 8; // integral sampling rate (might highly hit performance)\n"
|
||||
"const float THE_SunPower = 5.0;\n"
|
||||
"const float THE_StarTreshold = 0.98;\n"
|
||||
"\n"
|
||||
"// Uniforms\n"
|
||||
"uniform vec3 uSunDir;\n"
|
||||
"uniform float uTime;\n"
|
||||
"uniform float uCloudy;\n"
|
||||
"uniform float uFog;\n"
|
||||
"\n"
|
||||
"float hash13 (in vec3 p3)\n"
|
||||
"{\n"
|
||||
" p3 = fract (p3 * 0.1031);\n"
|
||||
" p3 += dot (p3, p3.zyx + 31.32);\n"
|
||||
" return fract ((p3.x + p3.y) * p3.z);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float hash12 (in vec2 p)\n"
|
||||
"{\n"
|
||||
" vec3 p3 = fract (vec3(p.xyx) * .1031);\n"
|
||||
" p3 += dot (p3, p3.yzx + 33.33);\n"
|
||||
" return fract ((p3.x + p3.y) * p3.z);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float smoothStarField (in vec2 theSamplePos)\n"
|
||||
"{\n"
|
||||
" vec2 aFract = fract (theSamplePos);\n"
|
||||
" vec2 aFloorSample = floor (theSamplePos);\n"
|
||||
" float v1 = hash12 (aFloorSample);\n"
|
||||
" float v2 = hash12 (aFloorSample + vec2( 0.0, 1.0 ));\n"
|
||||
" float v3 = hash12 (aFloorSample + vec2( 1.0, 0.0 ));\n"
|
||||
" float v4 = hash12 (aFloorSample + vec2( 1.0, 1.0 ));\n"
|
||||
"\n"
|
||||
" vec2 u = aFract * aFract * (3.0 - 2.0 * aFract);\n"
|
||||
"\n"
|
||||
" return mix(v1, v2, u.x) +\n"
|
||||
" (v3 - v1) * u.y * (1.0 - u.x) +\n"
|
||||
" (v4 - v2) * u.x * u.y;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float noisyStarField (in vec2 theSamplePos)\n"
|
||||
"{\n"
|
||||
" float aStarVal = smoothStarField (theSamplePos);\n"
|
||||
" if (aStarVal >= THE_StarTreshold)\n"
|
||||
" {\n"
|
||||
" aStarVal = pow ((aStarVal - THE_StarTreshold) / (1.0 - THE_StarTreshold), 6.0);\n"
|
||||
" }\n"
|
||||
" else\n"
|
||||
" {\n"
|
||||
" aStarVal = 0.0;\n"
|
||||
" }\n"
|
||||
" return aStarVal;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float smoothNoise (in vec3 theCoord)\n"
|
||||
"{\n"
|
||||
" vec3 anInt = floor (theCoord);\n"
|
||||
" vec3 anFract = fract (theCoord);\n"
|
||||
" anFract = anFract * anFract * (3.0 - (2.0 * anFract));\n"
|
||||
" return mix(mix(mix(hash13(anInt ),\n"
|
||||
" hash13(anInt + vec3(1.0, 0.0, 0.0)), anFract.x),\n"
|
||||
" mix(hash13(anInt + vec3(0.0, 1.0, 0.0)),\n"
|
||||
" hash13(anInt + vec3(1.0, 1.0, 0.0)), anFract.x), anFract.y),\n"
|
||||
" mix(mix(hash13(anInt + vec3(0.0, 0.0, 1.0)),\n"
|
||||
" hash13(anInt + vec3(1.0, 0.0, 1.0)), anFract.x),\n"
|
||||
" mix(hash13(anInt + vec3(0.0, 1.0, 1.0)),\n"
|
||||
" hash13(anInt + vec3(1.0, 1.0, 1.0)), anFract.x), anFract.y), anFract.z);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float fnoise (in vec3 theCoord, in float theTime)\n"
|
||||
"{\n"
|
||||
" theCoord *= .25;\n"
|
||||
" float aNoise;\n"
|
||||
"\n"
|
||||
" aNoise = 0.5000 * smoothNoise (theCoord);\n"
|
||||
" theCoord = theCoord * 3.02; theCoord.y -= theTime * 0.2;\n"
|
||||
" aNoise += 0.2500 * smoothNoise (theCoord);\n"
|
||||
" theCoord = theCoord * 3.03; theCoord.y += theTime * 0.06;\n"
|
||||
" aNoise += 0.1250 * smoothNoise (theCoord);\n"
|
||||
" theCoord = theCoord * 3.01;\n"
|
||||
" aNoise += 0.0625 * smoothNoise (theCoord);\n"
|
||||
" theCoord = theCoord * 3.03;\n"
|
||||
" aNoise += 0.03125 * smoothNoise (theCoord);\n"
|
||||
" theCoord = theCoord * 3.02;\n"
|
||||
" aNoise += 0.015625 * smoothNoise (theCoord);\n"
|
||||
" return aNoise;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"float clouds (in vec3 theTs, in float theTime)\n"
|
||||
"{\n"
|
||||
" float aCloud = fnoise (theTs * 2e-4, theTime) + uCloudy * 0.1;\n"
|
||||
" aCloud = smoothstep (0.44, 0.64, aCloud);\n"
|
||||
" aCloud *= 70.0;\n"
|
||||
" return aCloud + uFog;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void densities (in vec3 thePos, out float theRayleigh, out float theMie, in float theTime)\n"
|
||||
"{\n"
|
||||
" float aHeight = length (thePos - THE_EARTH_CENTER) - THE_EARTH_RADIUS;\n"
|
||||
" theRayleigh = exp (-aHeight / THE_HR);\n"
|
||||
"\n"
|
||||
" float aCloud = 0.0;\n"
|
||||
" if (aHeight > 5000.0 && aHeight < 8000.0)\n"
|
||||
" {\n"
|
||||
" aCloud = clouds (thePos + vec3 (0.0, 0.,-theTime*3e3), theTime);\n"
|
||||
" aCloud *= sin (M_PI*(aHeight - 5e3) / 5e3) * uCloudy;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" float aCloud2 = 0.0;\n"
|
||||
" if (aHeight > 12e3 && aHeight < 15.5e3)\n"
|
||||
" {\n"
|
||||
" aCloud2 = fnoise (thePos * 3e-4, theTime) * clouds (thePos * 32.0, theTime);\n"
|
||||
" aCloud2 *= sin (M_PI * (aHeight - 12e3) / 12e3) * 0.05;\n"
|
||||
" aCloud2 = clamp (aCloud2, 0.0, 1.0);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" theMie = exp (-aHeight / THE_HM) + aCloud + uFog;\n"
|
||||
" theMie += aCloud2;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"// ray with sphere intersection problem is reduced to solving the equation\n"
|
||||
"// (P - C)^2 = r^2 <--- sphere equation\n"
|
||||
"// where P is P(t) = A + t*B <--- point on ray\n"
|
||||
"// t^2*dot(B, B) + t*2*dot(B, A-C) + dot(A-C, A-C) - r^2 = 0\n"
|
||||
"// [ A ] [ B ] [ C ]\n"
|
||||
"// We just need to solve the above quadratic equation\n"
|
||||
"float raySphereIntersect (in vec3 theOrig, in vec3 theDir, in float theRadius)\n"
|
||||
"{\n"
|
||||
" theOrig = theOrig - THE_EARTH_CENTER;\n"
|
||||
" // A coefficient will be always 1 (theDir is normalized)\n"
|
||||
" float B = dot (theOrig, theDir);\n"
|
||||
" float C = dot (theOrig, theOrig) - theRadius * theRadius;\n"
|
||||
" // optimized version of classic (-b +- sqrt(b^2 - 4ac)) / 2a\n"
|
||||
" float aDet2 = B * B - C;\n"
|
||||
" if (aDet2 < 0.0) { return -1.0; }\n"
|
||||
" float aDet = sqrt (aDet2);\n"
|
||||
" float aT1 = -B - aDet;\n"
|
||||
" float aT2 = -B + aDet;\n"
|
||||
" return aT1 >= 0.0 ? aT1 : aT2;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void scatter (in vec3 theEye, in vec3 theRay, in vec3 theSun,\n"
|
||||
" out vec3 theCol, out float theScat, in float theTime)\n"
|
||||
"{\n"
|
||||
" float aRayLen = raySphereIntersect (theEye, theRay, THE_ATMO_RADIUS);\n"
|
||||
" float aMu = dot (theRay, theSun);\n"
|
||||
" float aMu2 = 1.0 + aMu*aMu;\n"
|
||||
" // The Raleigh phase function looks like this:\n"
|
||||
" float aPhaseR = 3.0/(16.0 * M_PI) * aMu2;\n"
|
||||
" // And the Mie phase function equation is:\n"
|
||||
" float aPhaseM = (3.0 / (8.0 * M_PI) * (1.0 - THE_G2) * aMu2)\n"
|
||||
" / ((2.0 + THE_G2) * pow (1.0 + THE_G2 - 2.0 * THE_G * aMu, 1.5));\n"
|
||||
"\n"
|
||||
" float anOpticalDepthR = 0.0;\n"
|
||||
" float anOpticalDepthM = 0.0;\n"
|
||||
" vec3 aSumR = vec3 (0.0);\n"
|
||||
" vec3 aSumM = vec3 (0.0); // Mie and Rayleigh contribution\n"
|
||||
"\n"
|
||||
" float dl = aRayLen / float (THE_NbSamples);\n"
|
||||
" for (int i = 0; i < THE_NbSamples; ++i)\n"
|
||||
" {\n"
|
||||
" float l = float(i) * dl;\n"
|
||||
" vec3 aSamplePos = theEye + theRay * l;\n"
|
||||
"\n"
|
||||
" float dR, dM;\n"
|
||||
" densities (aSamplePos, dR, dM, theTime);\n"
|
||||
" dR *= dl;\n"
|
||||
" dM *= dl;\n"
|
||||
" anOpticalDepthR += dR;\n"
|
||||
" anOpticalDepthM += dM;\n"
|
||||
"\n"
|
||||
" float aSegmentLengthLight = raySphereIntersect (aSamplePos, theSun, THE_ATMO_RADIUS);\n"
|
||||
" if (aSegmentLengthLight > 0.0)\n"
|
||||
" {\n"
|
||||
" float dls = aSegmentLengthLight / float (THE_NbSamplesLight);\n"
|
||||
" float anOpticalDepthRs = 0.0;\n"
|
||||
" float anOpticalDepthMs = 0.0;\n"
|
||||
" for (int j = 0; j < THE_NbSamplesLight; ++j)\n"
|
||||
" {\n"
|
||||
" float ls = float (j) * dls;\n"
|
||||
" vec3 aSamplePosS = aSamplePos + theSun * ls;\n"
|
||||
" float dRs, dMs;\n"
|
||||
" densities (aSamplePosS, dRs, dMs, theTime);\n"
|
||||
" anOpticalDepthRs += dRs * dls;\n"
|
||||
" anOpticalDepthMs += dMs * dls;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" vec3 anAttenuation = exp (-(THE_BETA_R * (anOpticalDepthR + anOpticalDepthRs)\n"
|
||||
" + THE_BETA_M * (anOpticalDepthM + anOpticalDepthMs)));\n"
|
||||
" aSumR += anAttenuation * dR;\n"
|
||||
" aSumM += anAttenuation * dM;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" theCol = THE_SunPower * (aSumR * THE_BETA_R * aPhaseR + aSumM * THE_BETA_M * aPhaseM);\n"
|
||||
" theScat = 1.0 - clamp (anOpticalDepthM*1e-5, 0.0, 1.0);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"// This is where all the magic happens. We first raymarch along the primary ray\n"
|
||||
"// (from the camera origin to the point where the ray exits the atmosphere).\n"
|
||||
"// For each sample along the primary ray,\n"
|
||||
"// we then \"cast\" a light ray and raymarch along that ray as well.\n"
|
||||
"// We basically shoot a ray in the direction of the sun.\n"
|
||||
"vec4 computeIncidentLight (in vec3 theRayDirection, in vec2 theUv, in float theTime)\n"
|
||||
"{\n"
|
||||
" float aSunAttenuation = THE_SunAttenuation;\n"
|
||||
" vec3 aSunDir = uSunDir;\n"
|
||||
" // conversion to moon\n"
|
||||
" float aStarAttenuation = 0.0;\n"
|
||||
" if (aSunDir.y < 0.0)\n"
|
||||
" {\n"
|
||||
" aSunDir *= -1.0;\n"
|
||||
" aSunAttenuation = aSunAttenuation * 0.1;\n"
|
||||
" aStarAttenuation = sqrt (aSunDir.y);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" vec3 anEyePosition = vec3(0.0, THE_EyeHeight, 0.0);\n"
|
||||
"\n"
|
||||
" // draw a water surface horizontally symmetrically to the sky\n"
|
||||
" if (theRayDirection.y <= -THE_HorizonWidth / 2.0)\n"
|
||||
" {\n"
|
||||
" theRayDirection.y = -THE_HorizonWidth - theRayDirection.y;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" float aScattering = 0.0;\n"
|
||||
" vec3 aColor = vec3 (0.0);\n"
|
||||
"\n"
|
||||
" scatter (anEyePosition, theRayDirection, aSunDir, aColor, aScattering, theTime);\n"
|
||||
" aColor *= aSunAttenuation;\n"
|
||||
" float aStarIntensity = noisyStarField (theUv * 2048.0);\n"
|
||||
" vec3 aStarColor = vec3 (aScattering * aStarIntensity * aStarAttenuation);\n"
|
||||
" aColor += aStarColor;\n"
|
||||
"\n"
|
||||
" return vec4 (1.18 * pow (aColor, vec3(0.7)), 1.0);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"uniform int uSide;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec2 anUv = vec2 (2.0 * TexCoord.x - 1.0,\n"
|
||||
" 2.0 * TexCoord.y - 1.0);\n"
|
||||
" vec3 aPlanes[6];\n"
|
||||
" aPlanes[0] = vec3 (+1.0, 0.0, 0.0);\n"
|
||||
" aPlanes[1] = vec3 (-1.0, 0.0, 0.0);\n"
|
||||
" aPlanes[2] = vec3 ( 0.0,+1.0, 0.0);\n"
|
||||
" aPlanes[3] = vec3 ( 0.0,-1.0, 0.0);\n"
|
||||
" aPlanes[4] = vec3 ( 0.0, 0.0,+1.0);\n"
|
||||
" aPlanes[5] = vec3 ( 0.0, 0.0,-1.0);\n"
|
||||
" vec3 aRayDirection;\n"
|
||||
" if (uSide == 0)\n"
|
||||
" {\n"
|
||||
" // Positive X side\n"
|
||||
" aRayDirection = aPlanes[0] + vec3 (0.0, +anUv.y, -anUv.x);\n"
|
||||
" }\n"
|
||||
" else if (uSide == 1)\n"
|
||||
" {\n"
|
||||
" // Negative X side\n"
|
||||
" aRayDirection = aPlanes[1] + vec3 (0.0, +anUv.y, +anUv.x);\n"
|
||||
" }\n"
|
||||
" else if (uSide == 2)\n"
|
||||
" {\n"
|
||||
" // Positive Y side\n"
|
||||
" aRayDirection = aPlanes[2] + vec3 (+anUv.x, 0.0, +anUv.y);\n"
|
||||
" }\n"
|
||||
" else if (uSide == 3)\n"
|
||||
" {\n"
|
||||
" // Negative Y side\n"
|
||||
" aRayDirection = aPlanes[3] + vec3 (+anUv.x, 0.0, -anUv.y);\n"
|
||||
" }\n"
|
||||
" else if (uSide == 4)\n"
|
||||
" {\n"
|
||||
" // Positive Z side\n"
|
||||
" aRayDirection = aPlanes[4] + vec3 (+anUv.x, +anUv.y, 0.0);\n"
|
||||
" }\n"
|
||||
" else if (uSide == 5)\n"
|
||||
" {\n"
|
||||
" // Negative Z side\n"
|
||||
" aRayDirection = aPlanes[5] + vec3 (-anUv.x, +anUv.y, 0.0);\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" occFragColor = computeIncidentLight (normalize (aRayDirection), anUv, uTime);\n"
|
||||
"}\n";
|
300
src/Shaders/SkydomBackground.fs
Normal file
300
src/Shaders/SkydomBackground.fs
Normal file
@@ -0,0 +1,300 @@
|
||||
// Constants
|
||||
const float M_PI = 3.1415926535;
|
||||
const float THE_EARTH_RADIUS = 6360e3;
|
||||
const vec3 THE_EARTH_CENTER = vec3 (0.0, -THE_EARTH_RADIUS, 0.0);
|
||||
const float THE_ATMO_RADIUS = 6380e3; // atmosphere radius (6420e3?)
|
||||
const float THE_G = 0.76; // anisotropy of the medium (papers use 0.76)
|
||||
const float THE_G2 = THE_G * THE_G;
|
||||
const float THE_HR = 8000.0; // Thickness of the atmosphere
|
||||
const float THE_HM = 1000.0; // Same as above but for Mie
|
||||
const vec3 THE_BETA_R = vec3 (5.8e-6, 13.5e-6, 33.1e-6); // Reyleigh scattering normal earth
|
||||
const vec3 THE_BETA_M = vec3 (21e-6); // Normal Mie scattering
|
||||
|
||||
// Parameters
|
||||
const float THE_SunAttenuation = 1.0; // sun intensity
|
||||
const float THE_EyeHeight = 100.0; // viewer height
|
||||
const float THE_HorizonWidth = 0.002;
|
||||
const int THE_NbSamples = 8;
|
||||
const int THE_NbSamplesLight = 8; // integral sampling rate (might highly hit performance)
|
||||
const float THE_SunPower = 5.0;
|
||||
const float THE_StarTreshold = 0.98;
|
||||
|
||||
// Uniforms
|
||||
uniform vec3 uSunDir;
|
||||
uniform float uTime;
|
||||
uniform float uCloudy;
|
||||
uniform float uFog;
|
||||
|
||||
float hash13 (in vec3 p3)
|
||||
{
|
||||
p3 = fract (p3 * 0.1031);
|
||||
p3 += dot (p3, p3.zyx + 31.32);
|
||||
return fract ((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
float hash12 (in vec2 p)
|
||||
{
|
||||
vec3 p3 = fract (vec3(p.xyx) * .1031);
|
||||
p3 += dot (p3, p3.yzx + 33.33);
|
||||
return fract ((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
|
||||
float smoothStarField (in vec2 theSamplePos)
|
||||
{
|
||||
vec2 aFract = fract (theSamplePos);
|
||||
vec2 aFloorSample = floor (theSamplePos);
|
||||
float v1 = hash12 (aFloorSample);
|
||||
float v2 = hash12 (aFloorSample + vec2( 0.0, 1.0 ));
|
||||
float v3 = hash12 (aFloorSample + vec2( 1.0, 0.0 ));
|
||||
float v4 = hash12 (aFloorSample + vec2( 1.0, 1.0 ));
|
||||
|
||||
vec2 u = aFract * aFract * (3.0 - 2.0 * aFract);
|
||||
|
||||
return mix(v1, v2, u.x) +
|
||||
(v3 - v1) * u.y * (1.0 - u.x) +
|
||||
(v4 - v2) * u.x * u.y;
|
||||
}
|
||||
|
||||
float noisyStarField (in vec2 theSamplePos)
|
||||
{
|
||||
float aStarVal = smoothStarField (theSamplePos);
|
||||
if (aStarVal >= THE_StarTreshold)
|
||||
{
|
||||
aStarVal = pow ((aStarVal - THE_StarTreshold) / (1.0 - THE_StarTreshold), 6.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
aStarVal = 0.0;
|
||||
}
|
||||
return aStarVal;
|
||||
}
|
||||
|
||||
float smoothNoise (in vec3 theCoord)
|
||||
{
|
||||
vec3 anInt = floor (theCoord);
|
||||
vec3 anFract = fract (theCoord);
|
||||
anFract = anFract * anFract * (3.0 - (2.0 * anFract));
|
||||
return mix(mix(mix(hash13(anInt ),
|
||||
hash13(anInt + vec3(1.0, 0.0, 0.0)), anFract.x),
|
||||
mix(hash13(anInt + vec3(0.0, 1.0, 0.0)),
|
||||
hash13(anInt + vec3(1.0, 1.0, 0.0)), anFract.x), anFract.y),
|
||||
mix(mix(hash13(anInt + vec3(0.0, 0.0, 1.0)),
|
||||
hash13(anInt + vec3(1.0, 0.0, 1.0)), anFract.x),
|
||||
mix(hash13(anInt + vec3(0.0, 1.0, 1.0)),
|
||||
hash13(anInt + vec3(1.0, 1.0, 1.0)), anFract.x), anFract.y), anFract.z);
|
||||
}
|
||||
|
||||
float fnoise (in vec3 theCoord, in float theTime)
|
||||
{
|
||||
theCoord *= .25;
|
||||
float aNoise;
|
||||
|
||||
aNoise = 0.5000 * smoothNoise (theCoord);
|
||||
theCoord = theCoord * 3.02; theCoord.y -= theTime * 0.2;
|
||||
aNoise += 0.2500 * smoothNoise (theCoord);
|
||||
theCoord = theCoord * 3.03; theCoord.y += theTime * 0.06;
|
||||
aNoise += 0.1250 * smoothNoise (theCoord);
|
||||
theCoord = theCoord * 3.01;
|
||||
aNoise += 0.0625 * smoothNoise (theCoord);
|
||||
theCoord = theCoord * 3.03;
|
||||
aNoise += 0.03125 * smoothNoise (theCoord);
|
||||
theCoord = theCoord * 3.02;
|
||||
aNoise += 0.015625 * smoothNoise (theCoord);
|
||||
return aNoise;
|
||||
}
|
||||
|
||||
float clouds (in vec3 theTs, in float theTime)
|
||||
{
|
||||
float aCloud = fnoise (theTs * 2e-4, theTime) + uCloudy * 0.1;
|
||||
aCloud = smoothstep (0.44, 0.64, aCloud);
|
||||
aCloud *= 70.0;
|
||||
return aCloud + uFog;
|
||||
}
|
||||
|
||||
void densities (in vec3 thePos, out float theRayleigh, out float theMie, in float theTime)
|
||||
{
|
||||
float aHeight = length (thePos - THE_EARTH_CENTER) - THE_EARTH_RADIUS;
|
||||
theRayleigh = exp (-aHeight / THE_HR);
|
||||
|
||||
float aCloud = 0.0;
|
||||
if (aHeight > 5000.0 && aHeight < 8000.0)
|
||||
{
|
||||
aCloud = clouds (thePos + vec3 (0.0, 0.,-theTime*3e3), theTime);
|
||||
aCloud *= sin (M_PI*(aHeight - 5e3) / 5e3) * uCloudy;
|
||||
}
|
||||
|
||||
float aCloud2 = 0.0;
|
||||
if (aHeight > 12e3 && aHeight < 15.5e3)
|
||||
{
|
||||
aCloud2 = fnoise (thePos * 3e-4, theTime) * clouds (thePos * 32.0, theTime);
|
||||
aCloud2 *= sin (M_PI * (aHeight - 12e3) / 12e3) * 0.05;
|
||||
aCloud2 = clamp (aCloud2, 0.0, 1.0);
|
||||
}
|
||||
|
||||
theMie = exp (-aHeight / THE_HM) + aCloud + uFog;
|
||||
theMie += aCloud2;
|
||||
}
|
||||
|
||||
// ray with sphere intersection problem is reduced to solving the equation
|
||||
// (P - C)^2 = r^2 <--- sphere equation
|
||||
// where P is P(t) = A + t*B <--- point on ray
|
||||
// t^2*dot(B, B) + t*2*dot(B, A-C) + dot(A-C, A-C) - r^2 = 0
|
||||
// [ A ] [ B ] [ C ]
|
||||
// We just need to solve the above quadratic equation
|
||||
float raySphereIntersect (in vec3 theOrig, in vec3 theDir, in float theRadius)
|
||||
{
|
||||
theOrig = theOrig - THE_EARTH_CENTER;
|
||||
// A coefficient will be always 1 (theDir is normalized)
|
||||
float B = dot (theOrig, theDir);
|
||||
float C = dot (theOrig, theOrig) - theRadius * theRadius;
|
||||
// optimized version of classic (-b +- sqrt(b^2 - 4ac)) / 2a
|
||||
float aDet2 = B * B - C;
|
||||
if (aDet2 < 0.0) { return -1.0; }
|
||||
float aDet = sqrt (aDet2);
|
||||
float aT1 = -B - aDet;
|
||||
float aT2 = -B + aDet;
|
||||
return aT1 >= 0.0 ? aT1 : aT2;
|
||||
}
|
||||
|
||||
void scatter (in vec3 theEye, in vec3 theRay, in vec3 theSun,
|
||||
out vec3 theCol, out float theScat, in float theTime)
|
||||
{
|
||||
float aRayLen = raySphereIntersect (theEye, theRay, THE_ATMO_RADIUS);
|
||||
float aMu = dot (theRay, theSun);
|
||||
float aMu2 = 1.0 + aMu*aMu;
|
||||
// The Raleigh phase function looks like this:
|
||||
float aPhaseR = 3.0/(16.0 * M_PI) * aMu2;
|
||||
// And the Mie phase function equation is:
|
||||
float aPhaseM = (3.0 / (8.0 * M_PI) * (1.0 - THE_G2) * aMu2)
|
||||
/ ((2.0 + THE_G2) * pow (1.0 + THE_G2 - 2.0 * THE_G * aMu, 1.5));
|
||||
|
||||
float anOpticalDepthR = 0.0;
|
||||
float anOpticalDepthM = 0.0;
|
||||
vec3 aSumR = vec3 (0.0);
|
||||
vec3 aSumM = vec3 (0.0); // Mie and Rayleigh contribution
|
||||
|
||||
float dl = aRayLen / float (THE_NbSamples);
|
||||
for (int i = 0; i < THE_NbSamples; ++i)
|
||||
{
|
||||
float l = float(i) * dl;
|
||||
vec3 aSamplePos = theEye + theRay * l;
|
||||
|
||||
float dR, dM;
|
||||
densities (aSamplePos, dR, dM, theTime);
|
||||
dR *= dl;
|
||||
dM *= dl;
|
||||
anOpticalDepthR += dR;
|
||||
anOpticalDepthM += dM;
|
||||
|
||||
float aSegmentLengthLight = raySphereIntersect (aSamplePos, theSun, THE_ATMO_RADIUS);
|
||||
if (aSegmentLengthLight > 0.0)
|
||||
{
|
||||
float dls = aSegmentLengthLight / float (THE_NbSamplesLight);
|
||||
float anOpticalDepthRs = 0.0;
|
||||
float anOpticalDepthMs = 0.0;
|
||||
for (int j = 0; j < THE_NbSamplesLight; ++j)
|
||||
{
|
||||
float ls = float (j) * dls;
|
||||
vec3 aSamplePosS = aSamplePos + theSun * ls;
|
||||
float dRs, dMs;
|
||||
densities (aSamplePosS, dRs, dMs, theTime);
|
||||
anOpticalDepthRs += dRs * dls;
|
||||
anOpticalDepthMs += dMs * dls;
|
||||
}
|
||||
|
||||
vec3 anAttenuation = exp (-(THE_BETA_R * (anOpticalDepthR + anOpticalDepthRs)
|
||||
+ THE_BETA_M * (anOpticalDepthM + anOpticalDepthMs)));
|
||||
aSumR += anAttenuation * dR;
|
||||
aSumM += anAttenuation * dM;
|
||||
}
|
||||
}
|
||||
|
||||
theCol = THE_SunPower * (aSumR * THE_BETA_R * aPhaseR + aSumM * THE_BETA_M * aPhaseM);
|
||||
theScat = 1.0 - clamp (anOpticalDepthM*1e-5, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// This is where all the magic happens. We first raymarch along the primary ray
|
||||
// (from the camera origin to the point where the ray exits the atmosphere).
|
||||
// For each sample along the primary ray,
|
||||
// we then "cast" a light ray and raymarch along that ray as well.
|
||||
// We basically shoot a ray in the direction of the sun.
|
||||
vec4 computeIncidentLight (in vec3 theRayDirection, in vec2 theUv, in float theTime)
|
||||
{
|
||||
float aSunAttenuation = THE_SunAttenuation;
|
||||
vec3 aSunDir = uSunDir;
|
||||
// conversion to moon
|
||||
float aStarAttenuation = 0.0;
|
||||
if (aSunDir.y < 0.0)
|
||||
{
|
||||
aSunDir *= -1.0;
|
||||
aSunAttenuation = aSunAttenuation * 0.1;
|
||||
aStarAttenuation = sqrt (aSunDir.y);
|
||||
}
|
||||
|
||||
vec3 anEyePosition = vec3(0.0, THE_EyeHeight, 0.0);
|
||||
|
||||
// draw a water surface horizontally symmetrically to the sky
|
||||
if (theRayDirection.y <= -THE_HorizonWidth / 2.0)
|
||||
{
|
||||
theRayDirection.y = -THE_HorizonWidth - theRayDirection.y;
|
||||
}
|
||||
|
||||
float aScattering = 0.0;
|
||||
vec3 aColor = vec3 (0.0);
|
||||
|
||||
scatter (anEyePosition, theRayDirection, aSunDir, aColor, aScattering, theTime);
|
||||
aColor *= aSunAttenuation;
|
||||
float aStarIntensity = noisyStarField (theUv * 2048.0);
|
||||
vec3 aStarColor = vec3 (aScattering * aStarIntensity * aStarAttenuation);
|
||||
aColor += aStarColor;
|
||||
|
||||
return vec4 (1.18 * pow (aColor, vec3(0.7)), 1.0);
|
||||
}
|
||||
|
||||
uniform int uSide;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 anUv = vec2 (2.0 * TexCoord.x - 1.0,
|
||||
2.0 * TexCoord.y - 1.0);
|
||||
vec3 aPlanes[6];
|
||||
aPlanes[0] = vec3 (+1.0, 0.0, 0.0);
|
||||
aPlanes[1] = vec3 (-1.0, 0.0, 0.0);
|
||||
aPlanes[2] = vec3 ( 0.0,+1.0, 0.0);
|
||||
aPlanes[3] = vec3 ( 0.0,-1.0, 0.0);
|
||||
aPlanes[4] = vec3 ( 0.0, 0.0,+1.0);
|
||||
aPlanes[5] = vec3 ( 0.0, 0.0,-1.0);
|
||||
vec3 aRayDirection;
|
||||
if (uSide == 0)
|
||||
{
|
||||
// Positive X side
|
||||
aRayDirection = aPlanes[0] + vec3 (0.0, +anUv.y, -anUv.x);
|
||||
}
|
||||
else if (uSide == 1)
|
||||
{
|
||||
// Negative X side
|
||||
aRayDirection = aPlanes[1] + vec3 (0.0, +anUv.y, +anUv.x);
|
||||
}
|
||||
else if (uSide == 2)
|
||||
{
|
||||
// Positive Y side
|
||||
aRayDirection = aPlanes[2] + vec3 (+anUv.x, 0.0, +anUv.y);
|
||||
}
|
||||
else if (uSide == 3)
|
||||
{
|
||||
// Negative Y side
|
||||
aRayDirection = aPlanes[3] + vec3 (+anUv.x, 0.0, -anUv.y);
|
||||
}
|
||||
else if (uSide == 4)
|
||||
{
|
||||
// Positive Z side
|
||||
aRayDirection = aPlanes[4] + vec3 (+anUv.x, +anUv.y, 0.0);
|
||||
}
|
||||
else if (uSide == 5)
|
||||
{
|
||||
// Negative Z side
|
||||
aRayDirection = aPlanes[5] + vec3 (-anUv.x, +anUv.y, 0.0);
|
||||
}
|
||||
|
||||
occFragColor = computeIncidentLight (normalize (aRayDirection), anUv, uTime);
|
||||
}
|
Reference in New Issue
Block a user