BVB Source Codes

CRYENGINE Show SkyLightNishita.cpp Source code

Return Download CRYENGINE: download SkyLightNishita.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /*************************************************************************
  4.    -------------------------------------------------------------------------
  5.    $Id$
  6.    $DateTime$
  7.  
  8.    -------------------------------------------------------------------------
  9.    History:
  10.    - 09:05:2005   11:08 : Created by Carsten Wenzel
  11.  
  12. *************************************************************************/
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #define IGNORE_ASSERTS
  17. #if defined(_DEBUG) && defined(IGNORE_ASSERTS)
  18.         #undef assert
  19.         #define assert(cond) ((void)0)
  20. #endif
  21.  
  22. #include "SkyLightNishita.h"
  23.  
  24. #include <math.h>
  25.  
  26. // constant definitions (all heights & radii given in km or km^-1 )
  27. const f64 c_maxAtmosphereHeight(100.0);
  28. const f64 c_earthRadius(6368.0);
  29. const f32 c_earthRadiusf(6368.0f);
  30. const f64 c_avgDensityHeightMieInv(1.0 / 1.2);
  31. const f64 c_avgDensityHeightRayleighInv(1.0 / 7.994);
  32.  
  33. const f64 c_opticalDepthWhenHittingEarth(1e10);
  34.  
  35. const f64 c_pi(3.1415926535897932384626433832795);
  36. const f32 c_pif(3.1415926535897932384626433832795f);
  37.  
  38. // constants for optical LUT serialization
  39. const uint32 c_lutFileTag(0x4C594B53);          // "SKYL"
  40. const uint32 c_lutFileVersion(0x00010002);
  41. const char c_lutFileName[] = "engineassets/sky/optical.lut";
  42.  
  43. static inline f64 MapSaveExpArg(f64 arg)
  44. {
  45.         const f64 c_saveExpArgRange((f64)650.0);   // -650.0 to 650 range is safe not to introduce fp over-/underflows
  46.         return((arg < -c_saveExpArgRange) ? -c_saveExpArgRange : (arg > c_saveExpArgRange) ? c_saveExpArgRange : arg);
  47. }
  48.  
  49. static inline f64 exp_precise(f64 arg)
  50. {
  51.         return(exp(MapSaveExpArg((f64) arg)));
  52. }
  53.  
  54. namespace
  55. {
  56. union eco
  57. {
  58.         f64 d;
  59.         struct
  60.         {
  61.                 int32 i, j;
  62.         } n;
  63. };
  64. }
  65.  
  66. static inline f64 exp_fast(f64 arg)
  67. {
  68.         const f64 eco_m(1048576L / 0.693147180559945309417232121458177);
  69.         const f64 eco_a(1072693248L - 60801L);
  70.  
  71. #if CRY_PLATFORM_X86 || CRY_PLATFORM_X64 || CRY_PLATFORM_ARM // for little endian (tested on Win32 / Win64)
  72.         eco e;
  73.         #ifdef _DEBUG
  74.         e.d = 1.0;
  75.         assert(e.n.j - 1072693248L || e.n.i == 0);     // check IEEE-754 conformance
  76.         #endif
  77.         e.n.j = (int32) (eco_m * MapSaveExpArg(arg) + eco_a);
  78.         return((f64)e.d);
  79. #else // fall back to default exp_sky() implementation for untested/unsupported target platforms
  80.         #pragma message( "Optimized exp_fast() not available for this platform!" )
  81.         #pragma message(        "If your target CPU is IEEE-754 conformant then please specify it in either the little or big endian branch (see SkyLightNishita.cpp::exp_fast())." )
  82.         return(exp(arg));
  83. #endif
  84. }
  85.  
  86. static inline f64 OpticalScaleFunction(const f64& height, const f64& avgDensityHeightInv)
  87. {
  88.         assert(height >= 0.0);
  89.         assert(avgDensityHeightInv > 0.0 && avgDensityHeightInv <= 1.0);
  90.         return(exp_precise(-height * avgDensityHeightInv));
  91. }
  92.  
  93. static inline f64 IntegrateOpticalDepthInternal(const Vec3d& start, const f64& startScale,
  94.                                                 const Vec3d& end, const f64& endScale, const f64& avgDensityHeightInv, const f64& error)
  95. {
  96.         assert(_finite(startScale) && _finite(endScale));
  97.  
  98.         Vec3d mid(0.5 * (start + end));
  99.         f64 midScale(OpticalScaleFunction(mid.GetLength() - c_earthRadius, avgDensityHeightInv));
  100.  
  101.         if (fabs(startScale - midScale) <= error && fabs(midScale - endScale) <= error)
  102.         {
  103.                 // integrate section this via simpson rule and stop recursing
  104.                 const f64 c_oneSixth(1.0 / 6.0);
  105.                 return((startScale + 4.0 * midScale + endScale) * c_oneSixth * (end - start).GetLength());
  106.         }
  107.         else
  108.         {
  109.                 // refine section via recursing down left and right branch
  110.                 return(IntegrateOpticalDepthInternal(start, startScale, mid, midScale, avgDensityHeightInv, error) +
  111.                        IntegrateOpticalDepthInternal(mid, midScale, end, endScale, avgDensityHeightInv, error));
  112.         }
  113. }
  114.  
  115. CSkyLightNishita::CSkyLightNishita()
  116.         : m_opticalDepthLUT()
  117.         , m_opticalScaleLUT()
  118.         , m_phaseLUT()
  119.         , m_Km(0.0f)
  120.         , m_Kr(0.0f)
  121.         , m_sunIntensity(20.0f, 20.0f, 20.0f)
  122.         , m_g(0.0f)
  123.         , m_invRGBWaveLength4(1.0f, 1.0f, 1.0f)
  124.         , m_sunDir(0.0f, 0.707106f, 0.707106f)
  125.         , m_inScatteringStepSize(1)
  126. {
  127.         SetRGBWaveLengths(Vec3(650.0f, 570.0f, 475.0f));
  128.         SetSunDirection(Vec3(0.0f, 0.707106f, 0.707106f));
  129.         SetAtmosphericConditions(Vec3(20.0f, 20.0f, 20.0f), 0.001f, 0.00025f, -0.99f);
  130.         ILog* pLog(C3DEngine::GetLog());
  131.         if (false == LoadOpticalLUTs())
  132.         {
  133.                 if (0 != pLog)
  134.                 {
  135.                         PrintMessage("Sky light: Optical lookup tables couldn't be loaded off disc. Recomputation needed!");
  136.                 }
  137.                 ComputeOpticalLUTs();
  138.         }
  139.         else
  140.         {
  141.                 if (0 != pLog)
  142.                 {
  143.                         PrintMessage("Sky light: Optical lookup tables loaded off disc.");
  144.                 }
  145.         }
  146. }
  147.  
  148. CSkyLightNishita::~CSkyLightNishita()
  149. {
  150. }
  151.  
  152. CSkyLightNishita::SOpticalDepthLUTEntry CSkyLightNishita::LookupBilerpedOpticalDepthLUTEntry(
  153.   const SOpticalDepthLUTEntry* const __restrict cpOptDepthLUT,
  154.   uint32 heightIndex, const f32 cosVertAngle) const
  155. {
  156.         uint32 vertAngleIndex;
  157.         f32 vertAngleIndexFrc;
  158.         f32 saveCosVertAngle(clamp_tpl(cosVertAngle, -1.0f, 1.0f));
  159.         f32 _index((f32) (cOLUT_AngularSteps - 1) * (-saveCosVertAngle * 0.5f + 0.5f));
  160.         vertAngleIndex = (uint32) _index;
  161.         vertAngleIndexFrc = _index - floorf(_index);
  162.  
  163.         if (vertAngleIndex >= cOLUT_AngularSteps - 1)
  164.         {
  165.                 return(cpOptDepthLUT[OpticalLUTIndex(heightIndex, vertAngleIndex)]);
  166.         }
  167.         else
  168.         {
  169.                 uint32 index(OpticalLUTIndex(heightIndex, vertAngleIndex));
  170.                 const SOpticalDepthLUTEntry& a(cpOptDepthLUT[index]);
  171.                 const SOpticalDepthLUTEntry& b(cpOptDepthLUT[index + 1]);
  172.  
  173.                 SOpticalDepthLUTEntry res;
  174.                 res.mie = a.mie + vertAngleIndexFrc * (b.mie - a.mie);
  175.                 res.rayleigh = a.rayleigh + vertAngleIndexFrc * (b.rayleigh - a.rayleigh);
  176.                 return(res);
  177.         }
  178. }
  179.  
  180. CSkyLightNishita::SPhaseLUTEntry CSkyLightNishita::LookupBilerpedPhaseLUTEntry(const f32 cosPhaseAngle) const
  181. {
  182.         uint32 index;
  183.         f32 indexFrc;
  184.         MapCosPhaseAngleToIndex(cosPhaseAngle, index, indexFrc);
  185.  
  186.         if (index >= cPLUT_AngularSteps - 1)
  187.         {
  188.                 return(m_phaseLUT[cPLUT_AngularSteps - 1]);
  189.         }
  190.         else
  191.         {
  192.                 const SPhaseLUTEntry& a(m_phaseLUT[index + 0]);
  193.                 const SPhaseLUTEntry& b(m_phaseLUT[index + 1]);
  194.  
  195.                 SPhaseLUTEntry res;
  196.                 res.mie = a.mie + indexFrc * (b.mie - a.mie);
  197.                 res.rayleigh = a.rayleigh + indexFrc * (b.rayleigh - a.rayleigh);
  198.                 return(res);
  199.         }
  200. }
  201.  
  202. void CSkyLightNishita::SamplePartialInScatteringAtHeight(const SOpticalScaleLUTEntry& osAtHeight,
  203.                                                          const f32 outScatteringConstMie, const Vec3& outScatteringConstRayleigh, const SOpticalDepthLUTEntry& odAtHeightSky,
  204.                                                          const SOpticalDepthLUTEntry& odAtViewerSky, const SOpticalDepthLUTEntry& odAtHeightSun,
  205.                                                          Vec3& partialInScatteringMie, Vec3& partialInScatteringRayleigh) const
  206. {
  207.         assert(odAtHeightSky.mie >= 0.0 && odAtHeightSky.mie <= odAtViewerSky.mie);
  208.         assert(odAtHeightSun.mie >= 0.0);
  209.         assert(odAtHeightSky.rayleigh >= 0.0 && odAtHeightSky.rayleigh <= odAtViewerSky.rayleigh);
  210.         assert(odAtHeightSun.rayleigh >= 0.0);
  211.  
  212.         // mie out-scattering
  213.         f32 sampleExpArgMie(outScatteringConstMie * (-odAtHeightSun.mie - (odAtViewerSky.mie - odAtHeightSky.mie)));
  214.  
  215.         // rayleigh out-scattering
  216.         Vec3 sampleExpArgRayleigh(outScatteringConstRayleigh * (-odAtHeightSun.rayleigh - (odAtViewerSky.rayleigh - odAtHeightSky.rayleigh)));
  217.  
  218.         // partial in-scattering sampling result
  219.         Vec3 sampleExpArg(Vec3(sampleExpArgMie, sampleExpArgMie, sampleExpArgMie) + sampleExpArgRayleigh);
  220.         Vec3 sampleRes((float)exp_fast(sampleExpArg.x), (float)exp_fast(sampleExpArg.y), (float)exp_fast(sampleExpArg.z));
  221.  
  222.         partialInScatteringMie = osAtHeight.mie * sampleRes;
  223.         partialInScatteringRayleigh = osAtHeight.rayleigh * sampleRes;
  224. }
  225.  
  226. void CSkyLightNishita::ComputeInScatteringNoPremul(const f32 outScatteringConstMie, const Vec3& outScatteringConstRayleigh, const Vec3& skyDir,
  227.                                                    Vec3& inScatteringMieNoPremul, Vec3& inScatteringRayleighNoPremul) const
  228. {
  229.         // start integration along the "skyDir" from the viewer's point of view
  230.         const Vec3 c_up(0.0f, 0.0f, 1.0f);
  231.         const Vec3 viewer(c_up * c_earthRadiusf);
  232.         Vec3 curRayPos(viewer);
  233.  
  234.         // to be reused by ray-sphere intersection code in loop below
  235.         f32 B(2.0f * viewer.Dot(skyDir));
  236.         f32 Bsq(B * B);
  237.         f32 Cpart(viewer.Dot(viewer));
  238.  
  239.         // calculate optical depth at viewer
  240.         const SOpticalDepthLUTEntry* const __restrict cpOptDepthLUT = &m_opticalDepthLUT[0];
  241.  
  242.         const Vec3& cSunDir(m_sunDir);
  243.  
  244.         SOpticalDepthLUTEntry odAtViewerSky(LookupBilerpedOpticalDepthLUTEntry(cpOptDepthLUT, 0, skyDir.Dot(c_up)));
  245.         SOpticalDepthLUTEntry odAtViewerSun(LookupBilerpedOpticalDepthLUTEntry(cpOptDepthLUT, 0, cSunDir.Dot(c_up)));
  246.  
  247.         // sample partial in-scattering term at viewer
  248.         Vec3 curSampleMie, curSampleRayleigh;
  249.  
  250.         const SOpticalScaleLUTEntry* const __restrict cpOptScaleLUT = &m_opticalScaleLUT[0];
  251.  
  252.         SamplePartialInScatteringAtHeight(cpOptScaleLUT[0], outScatteringConstMie, outScatteringConstRayleigh,
  253.                                           odAtViewerSky, odAtViewerSky, odAtViewerSun, curSampleMie, curSampleRayleigh);
  254.  
  255.         // integrate along "skyDir" over all height segments we've precalculated in the optical lookup table
  256.         inScatteringMieNoPremul = Vec3(0.0f, 0.0f, 0.0f);
  257.         inScatteringRayleighNoPremul = Vec3(0.0f, 0.0f, 0.0f);
  258.         const int32 cInScatteringStepSize(m_inScatteringStepSize);
  259.         for (int a(1); a < cOLUT_HeightSteps; a += cInScatteringStepSize)
  260.         {
  261.                 // calculate intersection with current "atmosphere shell"
  262.                 const SOpticalScaleLUTEntry& crOpticalScaleLUTEntry = cpOptScaleLUT[a];
  263.                 SOpticalScaleLUTEntry osAtHeight(crOpticalScaleLUTEntry);
  264.  
  265.                 f32 C(Cpart - (c_earthRadiusf + osAtHeight.atmosphereLayerHeight) * (c_earthRadiusf + osAtHeight.atmosphereLayerHeight));
  266.                 f32 det(Bsq - 4.0f * C);
  267.                 assert(det >= 0.0f && (0.5f * (-B - sqrtf(det)) <= 0.0f) && (0.5f * (-B + sqrtf(det)) >= 0.0f));
  268.  
  269.                 f32 t(0.5f * (-B + sqrtf(det)));
  270.  
  271.                 Vec3 newRayPos(viewer + t * skyDir);
  272.  
  273.                 // calculate optical depth at new position
  274.                 // since atmosphere bends we need to determine a new up vector to properly index the optical LUT
  275.                 Vec3 newUp(newRayPos.GetNormalized());
  276.                 SOpticalDepthLUTEntry odAtHeightSky(LookupBilerpedOpticalDepthLUTEntry(cpOptDepthLUT, a, skyDir.Dot(newUp)));
  277.                 SOpticalDepthLUTEntry odAtHeightSun(LookupBilerpedOpticalDepthLUTEntry(cpOptDepthLUT, a, cSunDir.Dot(newUp)));
  278.  
  279.                 // sample partial in-scattering term at new position
  280.                 Vec3 newSampleMie, newSampleRayleigh;
  281.                 SamplePartialInScatteringAtHeight(osAtHeight, outScatteringConstMie, outScatteringConstRayleigh,
  282.                                                   odAtHeightSky, odAtViewerSky, odAtHeightSun, newSampleMie, newSampleRayleigh);
  283.  
  284.                 // integrate via trapezoid rule
  285.                 f32 weight((newRayPos - curRayPos).GetLength() * 0.5f);
  286.                 inScatteringMieNoPremul += (curSampleMie + newSampleMie) * weight;
  287.                 inScatteringRayleighNoPremul += (curSampleRayleigh + newSampleRayleigh) * weight;
  288.  
  289.                 // update sampling data
  290.                 curRayPos = newRayPos;
  291.                 curSampleMie = newSampleMie;
  292.                 curSampleRayleigh = newSampleRayleigh;
  293.         }
  294. }
  295.  
  296. void CSkyLightNishita::ComputeSkyColor(const Vec3& skyDir, Vec3* pInScattering, Vec3* pInScatteringMieNoPremul,
  297.                                        Vec3* pInScatteringRayleighNoPremul, Vec3* pInScatteringRayleigh) const
  298. {
  299.         //// get high precision normalized sky direction
  300.         //Vec3 _skyDir( skyDir );
  301.         //assert( _skyDir.GetLengthSquared() > 0.0 );
  302.         //_skyDir.Normalize();
  303.  
  304.         assert(fabsf(skyDir.GetLengthSquared() - 1.0f) < 1e-4f);
  305.  
  306.         SPhaseLUTEntry phaseLUTEntry(LookupBilerpedPhaseLUTEntry(-skyDir.Dot(m_sunDir)));
  307.  
  308.         // initialize constants for mie scattering
  309.         f32 phaseForPhiGMie(phaseLUTEntry.mie);
  310.         f32 outScatteringConstMie(4.0f * c_pif * m_Km);
  311.         Vec3 inScatteringConstMie(m_sunIntensity * m_Km * phaseForPhiGMie);
  312.  
  313.         // initialize constants for rayleigh scattering
  314.         f32 phaseForPhiGRayleigh(phaseLUTEntry.rayleigh);
  315.         Vec3 outScatteringConstRayleigh(4.0f * (float)c_pi * m_Kr * m_invRGBWaveLength4);
  316.         Vec3 inScatteringConstRayleigh((m_sunIntensity * m_Kr * phaseForPhiGRayleigh).CompMul(m_invRGBWaveLength4));
  317.  
  318.         // compute in-scattering
  319.         Vec3 inScatteringMieNoPremul, inScatteringRayleighNoPremul;
  320.  
  321.         ComputeInScatteringNoPremul(outScatteringConstMie, outScatteringConstRayleigh, skyDir, inScatteringMieNoPremul, inScatteringRayleighNoPremul);
  322.  
  323.         assert(inScatteringMieNoPremul.x >= 0.0f && inScatteringMieNoPremul.y >= 0.0f && inScatteringMieNoPremul.z >= 0.0f);
  324.         assert(inScatteringRayleighNoPremul.x >= 0.0f && inScatteringRayleighNoPremul.y >= 0.0f && inScatteringRayleighNoPremul.z >= 0.0f);
  325.  
  326.         // return color
  327.         if (pInScattering)
  328.                 *pInScattering = Vec3(inScatteringMieNoPremul.CompMul(inScatteringConstMie) + inScatteringRayleighNoPremul.CompMul(inScatteringConstRayleigh));
  329.  
  330.         if (pInScatteringMieNoPremul)
  331.                 *pInScatteringMieNoPremul = Vec3(inScatteringMieNoPremul);
  332.  
  333.         if (pInScatteringRayleighNoPremul)
  334.                 *pInScatteringRayleighNoPremul = Vec3(inScatteringRayleighNoPremul);
  335.  
  336.         if (pInScatteringRayleigh)
  337.                 *pInScatteringRayleigh = Vec3(inScatteringRayleighNoPremul.CompMul(inScatteringConstRayleigh));
  338. }
  339.  
  340. void CSkyLightNishita::SetInScatteringIntegralStepSize(int32 stepSize)
  341. {
  342.         stepSize = stepSize < 1 ? 1 : stepSize > 2 ? 2 : stepSize;
  343.         m_inScatteringStepSize = stepSize;
  344. }
  345.  
  346. int32 CSkyLightNishita::GetInScatteringIntegralStepSize() const
  347. {
  348.         return(m_inScatteringStepSize);
  349. }
  350.  
  351. Vec4 CSkyLightNishita::GetPartialMieInScatteringConst() const
  352. {
  353.         Vec3 res(m_sunIntensity * m_Km);
  354.         return(Vec4(res.x, res.y, res.z, 0.0f));
  355. }
  356.  
  357. Vec4 CSkyLightNishita::GetPartialRayleighInScatteringConst() const
  358. {
  359.         Vec3 res((m_sunIntensity * m_Kr).CompMul(m_invRGBWaveLength4));
  360.         return(Vec4(res.x, res.y, res.z, 0.0f));
  361. }
  362.  
  363. Vec3 CSkyLightNishita::GetSunDirection() const
  364. {
  365.         return(Vec3(m_sunDir.x, m_sunDir.y, m_sunDir.z));
  366. }
  367.  
  368. Vec4 CSkyLightNishita::GetPhaseFunctionConsts() const
  369. {
  370.         //f32 g2( m_g * m_g );
  371.         //f32 miePart( 1.5f * ( 1.0f - g2 ) / ( 2.0f + g2 ) );
  372.         //return( Vec4( m_g, m_g * m_g, miePart, 0.0f ) );
  373.  
  374.         f32 g2(m_g * m_g);
  375.         f32 miePart(1.5f * (1.0f - g2) / (2.0f + g2));
  376.         f32 miePartPow(powf(miePart, -2.0f / 3.0f));
  377.         return(Vec4(miePartPow * -2.0f * m_g, miePartPow * (1.0f + g2), 0.0f, 0.0f));
  378. }
  379.  
  380. f64 CSkyLightNishita::IntegrateOpticalDepth(const Vec3d& start, const Vec3d& end, const f64& avgDensityHeightInv, const f64& error) const
  381. {
  382.         f64 startScale(OpticalScaleFunction(start.GetLength() - c_earthRadius, avgDensityHeightInv));
  383.         f64 endScale(OpticalScaleFunction(end.GetLength() - c_earthRadius, avgDensityHeightInv));
  384.         return(IntegrateOpticalDepthInternal(start, startScale, end, endScale, avgDensityHeightInv, error));
  385. }
  386.  
  387. bool CSkyLightNishita::ComputeOpticalDepth(const Vec3d& cameraLookDir, const f64& cameraHeight, const f64& avgDensityHeightInv, float& depth) const
  388. {
  389.         // init camera position
  390.         Vec3d cameraPos(0.0, cameraHeight + c_earthRadius, 0.0);
  391.  
  392.         // check if ray hits earth
  393.         // compute B, and C of quadratic function (A=1, as looking direction is normalized)
  394.         f64 B(2.0 * cameraPos.Dot(cameraLookDir));
  395.         f64 Bsq(B * B);
  396.         f64 Cpart(cameraPos.Dot(cameraPos));
  397.         f64 C(Cpart - c_earthRadius * c_earthRadius);
  398.         f64 det(Bsq - 4.0 * C);
  399.  
  400.         bool hitsEarth(det >= 0.0 && ((0.5 * (-B - sqrt(det)) > 1e-4) || (0.5 * (-B + sqrt(det)) > 1e-4)));
  401.         if (false != hitsEarth)
  402.         {
  403.                 depth = (float)c_opticalDepthWhenHittingEarth;
  404.                 return(false);
  405.         }
  406.  
  407.         // find intersection with atmosphere top
  408.         C = Cpart - (c_maxAtmosphereHeight + c_earthRadius) * (c_maxAtmosphereHeight + c_earthRadius);
  409.         det = Bsq - 4.0 * C;
  410.         assert(det >= 0.0);   // ray defined outside the atmosphere
  411.         f64 t(0.5 * (-B + sqrt(det)));
  412.         assert(t >= -1e-4);
  413.         if (t < 0.0) t = 0.0;
  414.  
  415.         // integrate depth along ray from camera to atmosphere top
  416.         f64 _depth(0.0);
  417.  
  418.         int numInitialSamples((int) t);
  419.         numInitialSamples = (numInitialSamples < 2) ? 2 : numInitialSamples;
  420.  
  421.         Vec3d lastCameraPos(cameraPos);
  422.         for (int i(1); i < numInitialSamples; ++i)
  423.         {
  424.                 Vec3d curCameraPos(cameraPos + cameraLookDir * (t * ((float) i / (float) numInitialSamples)));
  425.                 _depth += IntegrateOpticalDepth(lastCameraPos, curCameraPos, avgDensityHeightInv, 1e-1);
  426.                 lastCameraPos = curCameraPos;
  427.         }
  428.  
  429.         assert(_depth >= 0.0 && _depth < 1e25);
  430.         assert(0 != _finite(_depth));
  431.  
  432.         depth = (float) _depth;
  433.         return(true);
  434. }
  435.  
  436. void CSkyLightNishita::ComputeOpticalLUTs()
  437. {
  438.         LOADING_TIME_PROFILE_SECTION(GetISystem());
  439.  
  440.         ILog* pLog(C3DEngine::GetLog());
  441.         if (0 != pLog)
  442.         {
  443.                 PrintMessage("Sky light: Computing optical lookup tables (this might take a while)... ");
  444.         }
  445.  
  446.         // reset tables
  447.         m_opticalDepthLUT.resize(0);
  448.         m_opticalDepthLUT.reserve(cOLUT_HeightSteps * cOLUT_AngularSteps);
  449.  
  450.         m_opticalScaleLUT.resize(0);
  451.         m_opticalScaleLUT.reserve(cOLUT_HeightSteps);
  452.  
  453.         // compute LUTs
  454.         for (int a(0); a < cOLUT_HeightSteps; ++a)
  455.         {
  456.                 f64 height(MapIndexToHeight(a));
  457.  
  458.                 // compute optical depth
  459.                 for (int i(0); i < cOLUT_AngularSteps; ++i)
  460.                 {
  461.                         // init looking direction of camera
  462.                         f64 cosVertAngle(MapIndexToCosVertAngle(i));
  463.                         Vec3d cameraLookDir(sqrt(1.0 - cosVertAngle * cosVertAngle), cosVertAngle, 0.0);
  464.  
  465.                         // compute optical depth
  466.                         SOpticalDepthLUTEntry e;
  467.                         bool b0(ComputeOpticalDepth(cameraLookDir, height, c_avgDensityHeightMieInv, e.mie));
  468.                         bool b1(ComputeOpticalDepth(cameraLookDir, height, c_avgDensityHeightRayleighInv, e.rayleigh));
  469.                         assert(b0 == b1);
  470.  
  471.                         // blend out previous values once camera ray hits earth
  472.                         if (false == b0 && false == b1 && i > 0)
  473.                         {
  474.                                 e = m_opticalDepthLUT.back();
  475.                                 e.mie = (f32) ((f32)0.5 * (e.mie + c_opticalDepthWhenHittingEarth));
  476.                                 e.rayleigh = (f32) ((f32)0.5 * (e.rayleigh + c_opticalDepthWhenHittingEarth));
  477.                         }
  478.  
  479.                         // store result
  480.                         m_opticalDepthLUT.push_back(e);
  481.                 }
  482.  
  483.                 {
  484.                         // compute optical scale
  485.                         SOpticalScaleLUTEntry e;
  486.                         e.atmosphereLayerHeight = (f32) height;
  487.                         e.mie = (f32) OpticalScaleFunction(height, c_avgDensityHeightMieInv);
  488.                         e.rayleigh = (f32) OpticalScaleFunction(height, c_avgDensityHeightRayleighInv);
  489.                         m_opticalScaleLUT.push_back(e);
  490.                 }
  491.         }
  492.  
  493.         // save LUTs for next time
  494.         SaveOpticalLUTs();
  495.         if (0 != pLog)
  496.         {
  497.                 PrintMessage(" ... done.\n");
  498.         }
  499. }
  500.  
  501. void CSkyLightNishita::ComputePhaseLUT()
  502. {
  503.         //ILog* pLog( C3DEngine::GetLog() );
  504.         //if( 0 != pLog )
  505.         //      PrintMessage( "Sky light: Computing phase lookup table... " );
  506.  
  507.         // reset tables
  508.         m_phaseLUT.resize(0);
  509.         m_phaseLUT.reserve(cPLUT_AngularSteps);
  510.  
  511.         // compute coefficients
  512.         f32 g(m_g);
  513.         f32 g2(g * g);
  514.         f32 miePart(1.5f * (1.0f - g2) / (2.0f + g2));
  515.  
  516.         // calculate entries
  517.         for (int i(0); i < cPLUT_AngularSteps; ++i)
  518.         {
  519.                 f32 cosine(MapIndexToCosPhaseAngle(i));
  520.                 f32 cosine2(cosine * cosine);
  521.  
  522.                 //f32 t = 1.0f + g2 - 2.0f * g * cosine;
  523.                 //if (fabsf(t) < 1e-5f)
  524.                 //{
  525.                 //      PrintMessage( "Sky light: g = %.10f", g );
  526.                 //      PrintMessage( "Sky light: g2 = %.10f", g2 );
  527.                 //      PrintMessage( "Sky light: cosine = %.10f", cosine );
  528.                 //      PrintMessage( "Sky light: cosine2 = %.10f", cosine2 );
  529.                 //      PrintMessage( "Sky light: t = %.10f", t );
  530.                 //}
  531.  
  532.                 f32 miePhase(miePart * (1.0f + cosine2) / powf(1.0f + g2 - 2.0f * g * cosine, 1.5f));
  533.                 f32 rayleighPhase(0.75f * (1.0f + cosine2));
  534.  
  535.                 SPhaseLUTEntry e;
  536.                 e.mie = (float) miePhase;
  537.                 e.rayleigh = (float) rayleighPhase;
  538.                 m_phaseLUT.push_back(e);
  539.         }
  540.         //if( 0 != pLog )
  541.         //      PrintMessage( " ... done.\n" );
  542. }
  543.  
  544. f64 CSkyLightNishita::MapIndexToHeight(uint32 index) const
  545. {
  546.         // a function that maps well to mie and rayleigh at the same time
  547.         // that is, a lot of indices will map below the average density height for mie & rayleigh scattering
  548.         assert(index < cOLUT_HeightSteps);
  549.         f64 x((f64)index / (cOLUT_HeightSteps - 1));
  550.         return(c_maxAtmosphereHeight * exp_precise(10.0 * (x - 1.0)) * x);
  551. }
  552.  
  553. f64 CSkyLightNishita::MapIndexToCosVertAngle(uint32 index) const
  554. {
  555.         assert(index < cOLUT_AngularSteps);
  556.         return(1.0 - 2.0 * ((f64)index / (cOLUT_AngularSteps - 1)));
  557. }
  558.  
  559. f32 CSkyLightNishita::MapIndexToCosPhaseAngle(uint32 index) const
  560. {
  561.         assert(index < cPLUT_AngularSteps);
  562.         return(1.0f - 2.0f * ((f32)index / ((f32)cPLUT_AngularSteps - 1)));
  563. }
  564.  
  565. void CSkyLightNishita::MapCosPhaseAngleToIndex(const f32 cosPhaseAngle, uint32& index, f32& indexFrc) const
  566. {
  567.         //assert( -1 <= cosPhaseAngle && 1 >= cosPhaseAngle );
  568.         f32 saveCosPhaseAngle(clamp_tpl(cosPhaseAngle, -1.0f, 1.0f));
  569.         f32 _index((f32) (cPLUT_AngularSteps - 1) * (-saveCosPhaseAngle * 0.5f + 0.5f));
  570.         index = (uint32) _index;
  571.         indexFrc = _index - floorf(_index);
  572. }
  573.  
  574. uint32 CSkyLightNishita::OpticalLUTIndex(uint32 heightIndex, uint32 cosVertAngleIndex) const
  575. {
  576.         assert(heightIndex < cOLUT_HeightSteps && cosVertAngleIndex < cOLUT_AngularSteps);
  577.         return(heightIndex * cOLUT_AngularSteps + cosVertAngleIndex);
  578. }
  579.  
  580. bool CSkyLightNishita::LoadOpticalLUTs()
  581. {
  582.         ICryPak* pPak(C3DEngine::GetPak());
  583.         if (0 != pPak)
  584.         {
  585.                 FILE* f(pPak->FOpen(c_lutFileName, "rb"));
  586.                 if (0 != f)
  587.                 {
  588.                         size_t itemsRead(0);
  589.  
  590.                         // read in file tag
  591.                         uint32 fileTag(0);
  592.                         itemsRead = pPak->FRead(&fileTag, 1, f);
  593.                         if (itemsRead != 1 || fileTag != c_lutFileTag)
  594.                         {
  595.                                 // file tag mismatch
  596.                                 pPak->FClose(f);
  597.                                 return(false);
  598.                         }
  599.  
  600.                         // read in file format version
  601.                         uint32 fileVersion(0);
  602.                         itemsRead = pPak->FRead(&fileVersion, 1, f);
  603.                         if (itemsRead != 1 || fileVersion != c_lutFileVersion)
  604.                         {
  605.                                 // file version mismatch
  606.                                 pPak->FClose(f);
  607.                                 return(false);
  608.                         }
  609.  
  610.                         // read in optical depth LUT
  611.                         m_opticalDepthLUT.resize(cOLUT_HeightSteps * cOLUT_AngularSteps);
  612.                         itemsRead = pPak->FRead(&m_opticalDepthLUT[0], m_opticalDepthLUT.size(), f);
  613.                         if (itemsRead != m_opticalDepthLUT.size())
  614.                         {
  615.                                 pPak->FClose(f);
  616.                                 return(false);
  617.                         }
  618.  
  619.                         // read in optical scale LUT
  620.                         m_opticalScaleLUT.resize(cOLUT_HeightSteps);
  621.                         itemsRead = pPak->FRead(&m_opticalScaleLUT[0], m_opticalScaleLUT.size(), f);
  622.                         if (itemsRead != m_opticalScaleLUT.size())
  623.                         {
  624.                                 pPak->FClose(f);
  625.                                 return(false);
  626.                         }
  627.  
  628.                         // check if we read entire file
  629.                         long curPos(pPak->FTell(f));
  630.                         pPak->FSeek(f, 0, SEEK_END);
  631.                         long endPos(pPak->FTell(f));
  632.                         if (curPos != endPos)
  633.                         {
  634.                                 pPak->FClose(f);
  635.                                 return(false);
  636.                         }
  637.  
  638.                         // LUT successfully read
  639.                         pPak->FClose(f);
  640.                         return(true);
  641.                 }
  642.         }
  643.  
  644.         return(false);
  645. }
  646.  
  647. void CSkyLightNishita::SaveOpticalLUTs() const
  648. {
  649.         // only save on little endian PCs so the load function can do proper endian swapping
  650. #if CRY_PLATFORM_WINDOWS
  651.         ICryPak* pPak(C3DEngine::GetPak());
  652.         if (0 != pPak)
  653.         {
  654.                 FILE* f(pPak->FOpen(c_lutFileName, "wb"));
  655.                 if (0 != f)
  656.                 {
  657.                         // write out file tag
  658.                         pPak->FWrite(&c_lutFileTag, 1, sizeof(c_lutFileTag), f);
  659.  
  660.                         // write out file format version
  661.                         pPak->FWrite(&c_lutFileVersion, 1, sizeof(c_lutFileVersion), f);
  662.  
  663.                         // write out optical depth LUT
  664.                         assert(m_opticalDepthLUT.size() == cOLUT_HeightSteps * cOLUT_AngularSteps);
  665.                         pPak->FWrite(&m_opticalDepthLUT[0], 1, sizeof(SOpticalDepthLUTEntry) * m_opticalDepthLUT.size(), f);
  666.  
  667.                         // write out optical scale LUT
  668.                         assert(m_opticalScaleLUT.size() == cOLUT_HeightSteps);
  669.                         pPak->FWrite(&m_opticalScaleLUT[0], 1, sizeof(SOpticalScaleLUTEntry) * m_opticalScaleLUT.size(), f);
  670.  
  671.                         // close file
  672.                         pPak->FClose(f);
  673.                 }
  674.         }
  675. #endif
  676. }
  677.  
downloadSkyLightNishita.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top