23# pragma warning (push)
24# pragma warning (disable: 4505)
27#include <TileableVolumeNoise.h>
28#include <CurlNoise/Curl.h>
30#ifndef STBI_INCLUDE_STB_IMAGE_WRITE_H
31#define STB_IMAGE_WRITE_IMPLEMENTATION
32#define STB_IMAGE_WRITE_STATIC
33#include <stb_image_write.h>
59 Byte* data =
new Byte[width * height * 4];
60 memset( data, 255, width * height * 4u );
62 constexpr F32 frequency[] = { 8.0f, 6.0f, 4.0f };
64 for (
I32 i = 0; i < width * height * 4; i += 4 )
66 const Vectormath::Aos::Vector3 pos
68 to_F32( (i / 4) % width ) / width,
69 to_F32( ((i / 4) / height) ) / height,
72 for (
U8 pass = 0u; pass < 3; ++pass )
74 CurlNoise::SetCurlSettings(
false, frequency[pass], 3, 2.f, 0.5f );
75 const auto res = CurlNoise::ComputeCurlNoBoundaries( pos );
77 const F32 cellFBM0 = curl.
r * 0.5f + curl.
g * 0.35f + curl.
b * 0.15f;
79 data[i + pass] =
to_byte( cellFBM0 * 128.f + 127.f );
83 stbi_write_bmp( fileName, width, height, 4, data );
89 const auto smoothstep = [](
const F32 edge0,
const F32 edge1,
const F32 x )
91 const F32 t = std::min( std::max( (x - edge0) / (edge1 - edge0), 0.0f ), 1.0f );
92 return t * t * (3.f - 2.f * t);
96 Byte* data =
new Byte[width * height * 4];
97 memset( data, 255, width * height * 4u );
99 for (
I32 i = 0; i < width * height * 4; i += 4 )
101 const glm::vec3 pos = glm::vec3(
to_F32( (i / 4) % width ) /
to_F32( width ),
104 const glm::vec3 offset1 = glm::vec3( 0.f, 0.f, 581.163f );
105 const glm::vec3 offset2 = glm::vec3( 0.f, 0.f, 1245.463f );
108 const F32 perlinNoise = Tileable3dNoise::PerlinNoise( pos, 8, 3 );
109 const F32 perlinNoise2 = Tileable3dNoise::PerlinNoise( pos + offset1, 8, 3 );
110 F32 perlinNoise3 = Tileable3dNoise::PerlinNoise( pos + offset2, 2, 3 );
112 perlinNoise3 = std::min( 1.f, (smoothstep( 0.45f, 0.8f, perlinNoise3 ) + smoothstep( 0.25f, 0.45f, perlinNoise3 ) * 0.5f) );
113 data[i + 0] =
to_byte( perlinNoise * 128.f + 127.f );
114 data[i + 1] =
to_byte( smoothstep( 0.5f, 0.7f, perlinNoise2 ) * 255.f );
115 data[i + 2] =
to_byte( perlinNoise3 * 255.f );
117 stbi_write_bmp( fileName, width, height, 4, data );
123 Byte* worlNoiseArray =
new Byte[slices * width * height * 4];
124 memset( worlNoiseArray, 255, slices * width * height * 4u );
126 for (
I32 i = 0; i < slices * width * height * 4; i += 4 )
128 const glm::vec3 pos = glm::vec3(
to_F32( (i / 4) % width ) /
to_F32( width ),
129 to_F32( ((i / 4) / height) % height ) /
to_F32( height ),
130 to_F32( (i / 4) / (slices * slices) ) /
to_F32( slices ) );
131 const F32 cell0 = 1.f - Tileable3dNoise::WorleyNoise( pos, 2.f );
132 const F32 cell1 = 1.f - Tileable3dNoise::WorleyNoise( pos, 4.f );
133 const F32 cell2 = 1.f - Tileable3dNoise::WorleyNoise( pos, 8.f );
134 const F32 cell3 = 1.f - Tileable3dNoise::WorleyNoise( pos, 16.f );
136 const F32 cellFBM0 = cell0 * 0.5f + cell1 * 0.35f + cell2 * 0.15f;
137 const F32 cellFBM1 = cell1 * 0.5f + cell2 * 0.35f + cell3 * 0.15f;
138 const F32 cellFBM2 = cell2 * 0.75f + cell3 * 0.25f;
139 worlNoiseArray[i + 0] =
to_byte( cellFBM0 * 255 );
140 worlNoiseArray[i + 1] =
to_byte( cellFBM1 * 255 );
141 worlNoiseArray[i + 2] =
to_byte( cellFBM2 * 255 );
143 stbi_write_bmp( fileName, width * slices, height, 4, worlNoiseArray );
144 delete[] worlNoiseArray;
149 constexpr bool s_parallelBuild =
false;
151 Byte* perlWorlNoiseArray =
new Byte[slices * width * height * 4];
153 const auto cbk = [width, height, slices, perlWorlNoiseArray](
const U32 i)
155 const glm::vec3 pos = glm::vec3(
to_F32( (i / 4) % width ) /
to_F32( width ),
156 to_F32( ((i / 4) / height) % height ) /
to_F32( height ),
157 to_F32( (i / 4) / (slices * slices) ) /
to_F32( slices ) );
159 const F32 perlinNoise = Tileable3dNoise::PerlinNoise( pos, 8, 3 );
161 const F32 worleyNoise00 = (1.f - Tileable3dNoise::WorleyNoise( pos, 8 ));
162 const F32 worleyNoise01 = (1.f - Tileable3dNoise::WorleyNoise( pos, 32 ));
163 const F32 worleyNoise02 = (1.f - Tileable3dNoise::WorleyNoise( pos, 56 ));
168 const F32 worleyFBM = worleyNoise00 * 0.625f + worleyNoise01 * 0.25f + worleyNoise02 * 0.125f;
169 const F32 PerlWorlNoise =
MAP( perlinNoise, 0.f, 1.f, worleyFBM, 1.f );
173 const F32 worleyNoise12 = (1.f - Tileable3dNoise::WorleyNoise( pos, 16 ));
175 const F32 worleyNoise14 = (1.f - Tileable3dNoise::WorleyNoise( pos, 64 ));
177 const F32 worleyFBM0 = worleyNoise00 * 0.625f + worleyNoise12 * 0.25f + worleyNoise01 * 0.125f;
178 const F32 worleyFBM1 = worleyNoise12 * 0.625f + worleyNoise01 * 0.25f + worleyNoise14 * 0.125f;
179 const F32 worleyFBM2 = worleyNoise01 * 0.750f + worleyNoise14 * 0.25f;
180 perlWorlNoiseArray[i + 0] =
to_byte( PerlWorlNoise * 255 );
181 perlWorlNoiseArray[i + 1] =
to_byte( worleyFBM0 * 255 );
182 perlWorlNoiseArray[i + 2] =
to_byte( worleyFBM1 * 255 );
183 perlWorlNoiseArray[i + 3] =
to_byte( worleyFBM2 * 255 );
186 if constexpr ( s_parallelBuild )
189 descriptor.
_iterCount = slices * width * height * 4u;
193 for ( U32 i = start; i < end; i += 4 )
201 for (
U32 i = 0; i <
to_U32( slices * width * height * 4u ); i += 4 )
207 stbi_write_tga( fileName, width * slices, height, 4, perlWorlNoiseArray );
208 delete[] perlWorlNoiseArray;
213void Sky::OnStartup( PlatformContext& context )
215 static bool init =
false;
223 std::array<Task*, 3> tasks{
nullptr };
230 if ( g_alwaysGenerateWeatherTextures || !
fileExists( curlNoise ) )
232 Console::printfn(
"Generating Curl Noise 128x128 RGB" );
233 tasks[0] =
CreateTask( [fileName = curlNoise.string()](
const Task& )
235 GenerateCurlNoise( fileName.c_str(), 128, 128 );
237 Start( *tasks[0], context.taskPool( TaskPoolType::HIGH_PRIORITY ) );
238 Console::printfn(
"Done!" );
241 if ( g_alwaysGenerateWeatherTextures || !
fileExists( weather ) )
243 Console::printfn(
"Generating Perlin Noise for LUT's" );
244 Console::printfn(
"Generating weather Noise 512x512 RGB" );
245 tasks[1] =
CreateTask( [fileName = weather.string()](
const Task& )
247 GeneratePerlinNoise( fileName.c_str(), 512, 512 );
249 Start( *tasks[1], context.taskPool( TaskPoolType::HIGH_PRIORITY ) );
250 Console::printfn(
"Done!" );
253 if ( g_alwaysGenerateWeatherTextures || !
fileExists( worlNoise ) )
257 Console::printfn(
"Generating Worley Noise 32x32x32 RGB" );
258 tasks[2] =
CreateTask( [fileName = worlNoise.string()](
const Task& )
260 GenerateWorleyNoise( fileName.c_str(), 32, 32, 32 );
262 Start( *tasks[2], context.taskPool( TaskPoolType::HIGH_PRIORITY ) );
263 Console::printfn(
"Done!" );
266 if ( g_alwaysGenerateWeatherTextures || !
fileExists( perWordNoise ) )
268 Console::printfn(
"Generating Perlin-Worley Noise 128x128x128 RGBA" );
270 Console::printfn(
"Done!" );
273 bool keepWaiting =
true;
274 while ( keepWaiting )
277 for ( Task* task : tasks )
279 if ( task !=
nullptr && !
Finished( *task ) )
288Sky::Sky(
const ResourceDescriptor<Sky>& descriptor )
289 : SceneNode( descriptor,
292 , _diameter( descriptor.ID() )
294 nightSkyColour( { 0.05f, 0.06f, 0.1f, 1.f } );
295 moonColour( { 1.0f, 1.f, 0.8f } );
297 const time_t t = time(
nullptr );
298 _sun.SetLocation( -2.589910f, 51.45414f );
299 _sun.SetDate( *localtime( &t ) );
304bool Sky::load( PlatformContext& context )
306 if ( _sky != INVALID_HANDLE<Sphere3D> )
311 std::atomic_uint loadTasks = 0u;
314 Byte* perlWorlData = (
Byte*)stbi_load( perlWolFile.c_str(), &x, &y, &n, STBI_rgb_alpha );
315 ImageTools::ImageData imgDataPerl = {};
320 stbi_image_free( perlWorlData );
323 Byte* worlNoise = (
Byte*)stbi_load( worlFile.c_str(), &x, &y, &n, STBI_rgb_alpha );
324 ImageTools::ImageData imgDataWorl = {};
329 stbi_image_free( worlNoise );
337 _skyboxSampler._anisotropyLevel = 0u;
339 SamplerDescriptor noiseSamplerMipMap {};
346 noiseSamplerMipMap._anisotropyLevel = 8u;
348 STUBBED(
"ToDo: Investigate why weather textures don't work well with DDS conversion using NVTT + STB -Ionut");
351 textureDescriptor._textureOptions._alphaChannelTransparency =
false;
352 textureDescriptor._textureOptions._useDDSCache =
false;
355 ResourceDescriptor<Texture> perlWorlDescriptor(
"perlWorl", textureDescriptor );
356 perlWorlDescriptor.waitForReady(
true );
358 Get( _perlWorlNoiseTex )->createWithData( imgDataPerl, {});
360 ResourceDescriptor<Texture> worlDescriptor(
"worlNoise", textureDescriptor );
361 worlDescriptor.waitForReady(
true );
363 Get(_worlNoiseTex)->createWithData( imgDataWorl, {});
367 ResourceDescriptor<Texture> weatherDescriptor(
"Weather", textureDescriptor );
368 weatherDescriptor.assetName( weatherTexName );
370 weatherDescriptor.waitForReady(
false );
373 ResourceDescriptor<Texture> curlDescriptor(
"CurlNoise", textureDescriptor );
374 curlDescriptor.assetName( curlTexName );
376 curlDescriptor.waitForReady(
false );
380 ResourceDescriptor<Texture> skyboxTextures(
"SkyTextures" );
381 skyboxTextures.assetName(
382 "skyboxDay_FRONT.jpg, skyboxDay_BACK.jpg, skyboxDay_UP.jpg, skyboxDay_DOWN.jpg, skyboxDay_LEFT.jpg, skyboxDay_RIGHT.jpg,"
383 "Milkyway_posx.jpg, Milkyway_negx.jpg, Milkyway_posy.jpg, Milkyway_negy.jpg, Milkyway_posz.jpg, Milkyway_negz.jpg"
385 skyboxTextures.assetLocation( Paths::g_imagesLocation /
"SkyBoxes" );
386 skyboxTextures.waitForReady(
false );
391 skyboxTexture._textureOptions._alphaChannelTransparency =
false;
396 const F32 radius = _diameter * 0.5f;
398 ResourceDescriptor<Sphere3D> skybox(
"SkyBox" );
404 ResourcePtr<Sphere3D> skyPtr =
Get(_sky);
405 skyPtr->renderState().drawState(
false );
409 ResourceDescriptor<Material> skyMaterial(
"skyMaterial_" + resourceName() );
411 ResourcePtr<Material> skyMatPtr =
Get(skyMat);
415 skyMatPtr->properties().roughness( 0.01f );
417 skyMatPtr->computeRenderStateCBK( []( [[maybe_unused]] Material* material,
const RenderStagePass stagePass, RenderStateBlock& blockInOut)
424 skyMatPtr->computeShaderCBK( []( [[maybe_unused]] Material* material,
const RenderStagePass stagePass )
426 ShaderModuleDescriptor vertModule = {};
428 vertModule._sourceFile =
"sky.glsl";
430 ShaderModuleDescriptor fragModule = {};
432 fragModule._sourceFile =
"sky.glsl";
438 vertModule._variant =
"NoClouds";
439 vertModule._defines.emplace_back(
"NO_ATMOSPHERE",
true);
441 shaderDescriptor.
_modules.push_back( vertModule );
445 fragModule._defines.emplace_back(
"NO_ATMOSPHERE",
true );
446 fragModule._variant =
"PrePass";
447 shaderDescriptor._modules.push_back( fragModule );
448 shaderDescriptor._name =
"sky_PrePass";
452 shaderDescriptor._name =
"sky_Depth";
457 shaderDescriptor._name =
"sky_Display";
458 vertModule._variant =
"Clouds";
459 fragModule._variant =
"Clouds";
460 shaderDescriptor._modules.push_back( vertModule );
461 shaderDescriptor._modules.push_back( fragModule );
464 shaderDescriptor._globalDefines.emplace_back(
"SUN_ENERGY 1000.f" );
465 shaderDescriptor._globalDefines.emplace_back(
"SUN_SIZE 0.00872663806f" );
466 shaderDescriptor._globalDefines.emplace_back(
"RAYLEIGH_SCALE 7994.f" );
467 shaderDescriptor._globalDefines.emplace_back(
"MIE_SCALE 1200.f" );
468 shaderDescriptor._globalDefines.emplace_back(
"RAYLEIGH_COEFF vec3(5.5f, 13.0f, 22.4f)" );
469 shaderDescriptor._globalDefines.emplace_back(
"MIE_COEFF vec3(21.0f)" );
471 shaderDescriptor._globalDefines.emplace_back(
"SKIP_REFLECT_REFRACT",
true);
472 shaderDescriptor._globalDefines.emplace_back(
"dvd_NightSkyColour PushData0[0].xyz" );
473 shaderDescriptor._globalDefines.emplace_back(
"dvd_RaySteps PushData0[0].w" );
474 shaderDescriptor._globalDefines.emplace_back(
"dvd_MoonColour PushData0[1].xyz" );
475 shaderDescriptor._globalDefines.emplace_back(
"dvd_MoonScale PushData0[1].w" );
476 shaderDescriptor._globalDefines.emplace_back(
"dvd_UseDaySkybox (int(PushData0[2].x) == 1)" );
477 shaderDescriptor._globalDefines.emplace_back(
"dvd_UseNightSkybox (int(PushData0[2].y) == 1)" );
478 shaderDescriptor._globalDefines.emplace_back(
"dvd_CloudLayerMinMaxHeight PushData0[2].zw" );
479 shaderDescriptor._globalDefines.emplace_back(
"dvd_SunDiskSize PushData0[3].x" );
480 shaderDescriptor._globalDefines.emplace_back(
"dvd_PlanetRadius PushData0[3].y" );
481 shaderDescriptor._globalDefines.emplace_back(
"dvd_CloudDensity PushData0[3].z" );
482 shaderDescriptor._globalDefines.emplace_back(
"dvd_CloudCoverage PushData0[3].w" );
483 shaderDescriptor._globalDefines.emplace_back(
"dvd_EnableClouds (int(PushData1[0].x) == 1)" );
484 shaderDescriptor._globalDefines.emplace_back(
"dvd_Exposure PushData1[0].y" );
485 shaderDescriptor._globalDefines.emplace_back(
"dvd_MieEccentricity PushData1[0].z" );
486 shaderDescriptor._globalDefines.emplace_back(
"dvd_Turbidity PushData1[0].w" );
487 shaderDescriptor._globalDefines.emplace_back(
"dvd_RayleighColour PushData1[1].xyz" );
488 shaderDescriptor._globalDefines.emplace_back(
"dvd_Rayleigh PushData1[1].w" );
489 shaderDescriptor._globalDefines.emplace_back(
"dvd_MieColour PushData1[2].xyz" );
490 shaderDescriptor._globalDefines.emplace_back(
"dvd_Mie PushData1[2].w" );
491 shaderDescriptor._globalDefines.emplace_back(
"dvd_GroundColour PushData1[3].xyz" );
493 return shaderDescriptor;
504 setMaterialTpl( skyMat );
506 setBounds( BoundingBox( vec3<F32>( -radius ), vec3<F32>( radius ) ) );
513void Sky::setSkyShaderData(
const RenderStagePass renderStagePass, PushConstantsStruct& constantsInOut )
515 U16 targetRayCount = rayCount();
516 if ( targetRayCount > 16u &&
520 targetRayCount = std::max<U16>(targetRayCount / 4, 4u);
523 constantsInOut.data[0]._vec[0].set( nightSkyColour().rgb,
to_F32( targetRayCount ) );
524 constantsInOut.data[0]._vec[1].set( moonColour().rgb, moonScale() );
525 constantsInOut.data[0]._vec[2].set( useDaySkybox() ? 1.f : 0.f, useNightSkybox() ? 1.f : 0.f, _atmosphere._cloudLayerMinMaxHeight.min, _atmosphere._cloudLayerMinMaxHeight.max );
526 constantsInOut.data[0]._vec[3].set( _atmosphere._sunDiskSize, _atmosphere._planetRadius, _atmosphere._cloudDensity, _atmosphere._cloudCoverage );
527 constantsInOut.data[1]._vec[0].set( enableProceduralClouds() ? 1.f : 0.f, exposure(), _atmosphere._mieEccentricity, _atmosphere._turbidity );
528 constantsInOut.data[1]._vec[1].set( _atmosphere._rayleighColour.r, _atmosphere._rayleighColour.g, _atmosphere._rayleighColour.b, _atmosphere._rayleigh );
529 constantsInOut.data[1]._vec[2].set( _atmosphere._mieColour.r, _atmosphere._mieColour.g, _atmosphere._mieColour.b, _atmosphere._mie );
530 constantsInOut.data[1]._vec[3].set( _groundColour.r, _groundColour.g, _groundColour.b, 0.f );
533void Sky::postLoad( SceneGraphNode* sgn )
537 SceneGraphNodeDescriptor skyNodeDescriptor;
538 skyNodeDescriptor._serialize =
false;
539 skyNodeDescriptor._nodeHandle =
FromHandle(_sky);
540 skyNodeDescriptor._name = sgn->name() +
"_geometry";
546 sgn->addChildNode( skyNodeDescriptor )->get<BoundsComponent>()->collisionsEnabled(
false);
547 sgn->get<BoundsComponent>()->collisionsEnabled(
false );
549 RenderingComponent* renderable = sgn->get<RenderingComponent>();
552 renderable->lockLoD( 0u );
554 renderable->occlusionCull(
false);
557 _defaultAtmosphere = atmosphere();
559 PlatformContext& pContext = sgn->context();
560 registerEditorComponent( pContext );
563 _editorComponent->onChangedCbk( [
this](
const std::string_view field )
565 if ( field ==
"Reset To Scene Default" )
567 _atmosphere = defaultAtmosphere();
569 else if ( field ==
"Reset To Global Default" )
571 _atmosphere = initialAtmosphere();
573 else if ( field ==
"Enable Procedural Clouds" )
575 rebuildDrawCommands(
true );
577 else if ( field ==
"Update Sky Light" )
582 _atmosphereChanged =
true;
586 EditorComponentField separatorField = {};
587 separatorField._name =
"Sun/Sky";
589 _editorComponent->registerField(
MOV( separatorField ) );
591 EditorComponentField rayCountField = {};
592 rayCountField._name =
"Cloud Ray Count";
593 rayCountField._tooltip =
"Base number of rays used for cloud marching";
594 rayCountField._data = &_rayCount;
596 rayCountField._resetValue = 128.f;
597 rayCountField._readOnly =
false;
598 rayCountField._range = { 32.f, 512.f };
601 _editorComponent->registerField(
MOV( rayCountField ) );
603 EditorComponentField sunIntensityField = {};
604 sunIntensityField._name =
"Sun Disk Size";
605 sunIntensityField._tooltip =
"(0.01x - 15.0x) - visual size of the sun disc.";
606 sunIntensityField._data = &_atmosphere._sunDiskSize;
608 sunIntensityField._resetValue = 1.f;
609 sunIntensityField._readOnly =
false;
610 sunIntensityField._range = { 0.01f, 15.0f };
612 _editorComponent->registerField(
MOV( sunIntensityField ) );
614 EditorComponentField skyLuminanceField = {};
615 skyLuminanceField._name =
"Exposure";
616 skyLuminanceField._tooltip =
"(0.01 - 128.f) - Tone mapping luminance value.";
617 skyLuminanceField._data = &_exposure;
619 skyLuminanceField._readOnly =
false;
620 skyLuminanceField._range = { 0.01f, 128.f };
622 _editorComponent->registerField(
MOV( skyLuminanceField ) );
625 EditorComponentField separatorField = {};
626 separatorField._name =
"Atmosphere";
628 _editorComponent->registerField(
MOV( separatorField ) );
630 EditorComponentField planetRadiusField = {};
631 planetRadiusField._name =
"Planet Radius (m)";
632 planetRadiusField._tooltip =
"The radius of the Earth (default: 6371e3m, range: [2000e3m...9000e3m])";
633 planetRadiusField._data = &_atmosphere._planetRadius;
635 planetRadiusField._resetValue = 6'371'000.f;
636 planetRadiusField._readOnly =
false;
637 planetRadiusField._range = { 2'000'000.f, 9'000'000.f };
639 _editorComponent->registerField(
MOV( planetRadiusField ) );
641 EditorComponentField cloudHeightOffsetField = {};
642 cloudHeightOffsetField._name =
"Cloud height range (m)";
643 cloudHeightOffsetField._tooltip =
"Cloud layer will be limited to the range [cloudRadius + x, cloudRadius + y].";
644 cloudHeightOffsetField._data = &_atmosphere._cloudLayerMinMaxHeight;
646 cloudHeightOffsetField._readOnly =
false;
647 cloudHeightOffsetField._range = { 10.f, 50000.f };
649 _editorComponent->registerField(
MOV( cloudHeightOffsetField ) );
651 EditorComponentField rayleighColourField = {};
652 rayleighColourField._name =
"Rayleigh Colour";
653 rayleighColourField._data = &_atmosphere._rayleighColour;
655 rayleighColourField._readOnly =
false;
657 _editorComponent->registerField(
MOV( rayleighColourField ) );
659 EditorComponentField rayleighField = {};
660 rayleighField._name =
"Rayleigh Factor";
661 rayleighField._data = &_atmosphere._rayleigh;
663 rayleighField._resetValue = 2.f;
664 rayleighField._readOnly =
false;
665 rayleighField._range = { 0.f, 64.0f };
667 _editorComponent->registerField(
MOV( rayleighField ) );
669 EditorComponentField mieColourField = {};
670 mieColourField._name =
"Mie Colour";
671 mieColourField._data = &_atmosphere._mieColour;
673 mieColourField._readOnly =
false;
675 _editorComponent->registerField(
MOV( mieColourField ) );
677 EditorComponentField mieField = {};
678 mieField._name =
"Mie Factor";
679 mieField._data = &_atmosphere._mie;
681 mieField._resetValue = 0.005f;
682 mieField._readOnly =
false;
683 mieField._range = { 0.f, 64.0f };
685 _editorComponent->registerField(
MOV( mieField ) );
687 EditorComponentField mieEccentricityField = {};
688 mieEccentricityField._name =
"Mie Eccentricity Factor";
689 mieEccentricityField._data = &_atmosphere._mieEccentricity;
691 mieEccentricityField._resetValue = 0.8f;
692 mieEccentricityField._readOnly =
false;
693 mieEccentricityField._range = { -1.f, 1.f };
695 _editorComponent->registerField(
MOV( mieEccentricityField ) );
697 EditorComponentField turbidityField = {};
698 turbidityField._name =
"Turbidity Factor";
699 turbidityField._data = &_atmosphere._turbidity;
701 turbidityField._resetValue = 10.f;
702 turbidityField._readOnly =
false;
703 turbidityField._range = { 0.f, 1000.f };
705 _editorComponent->registerField(
MOV( turbidityField ) );
708 EditorComponentField separatorField = {};
709 separatorField._name =
"Weather";
711 _editorComponent->registerField(
MOV( separatorField ) );
713 EditorComponentField cloudCoverageField = {};
714 cloudCoverageField._name =
"Cloud Coverage";
715 cloudCoverageField._data = &_atmosphere._cloudCoverage;
717 cloudCoverageField._resetValue = 0.35f;
718 cloudCoverageField._readOnly =
false;
719 cloudCoverageField._range = { 0.001f, 1.f };
721 _editorComponent->registerField(
MOV( cloudCoverageField ) );
723 EditorComponentField cloudDensityField = {};
724 cloudDensityField._name =
"Cloud Density";
725 cloudDensityField._data = &_atmosphere._cloudDensity;
727 cloudDensityField._resetValue = 0.05f;
728 cloudDensityField._readOnly =
false;
729 cloudDensityField._range = { 0.001f, 1.f };
731 _editorComponent->registerField(
MOV( cloudDensityField ) );
734 EditorComponentField separator3Field = {};
735 separator3Field._name =
"Skybox";
737 _editorComponent->registerField(
MOV( separator3Field ) );
739 EditorComponentField useDaySkyboxField = {};
740 useDaySkyboxField._name =
"Use Day Skybox";
741 useDaySkyboxField._data = &_useDaySkybox;
743 useDaySkyboxField._readOnly =
false;
745 _editorComponent->registerField(
MOV( useDaySkyboxField ) );
747 EditorComponentField useNightSkyboxField = {};
748 useNightSkyboxField._name =
"Use Night Skybox";
749 useNightSkyboxField._data = &_useNightSkybox;
751 useNightSkyboxField._readOnly =
false;
753 _editorComponent->registerField(
MOV( useNightSkyboxField ) );
755 EditorComponentField useProceduralCloudsField = {};
756 useProceduralCloudsField._name =
"Enable Procedural Clouds";
757 useProceduralCloudsField._data = &_enableProceduralClouds;
759 useProceduralCloudsField._readOnly =
false;
761 _editorComponent->registerField(
MOV( useProceduralCloudsField ) );
763 EditorComponentField groundColourField = {};
764 groundColourField._name =
"Ground Colour";
765 groundColourField._data = &_groundColour;
767 groundColourField._readOnly =
false;
769 _editorComponent->registerField(
MOV( groundColourField ) );
771 EditorComponentField nightColourField = {};
772 nightColourField._name =
"Night Colour";
773 nightColourField._data = &_nightSkyColour;
775 nightColourField._readOnly =
false;
777 _editorComponent->registerField(
MOV( nightColourField ) );
779 EditorComponentField moonColourField = {};
780 moonColourField._name =
"Moon Colour";
781 moonColourField._data = &_moonColour;
783 moonColourField._readOnly =
false;
785 _editorComponent->registerField(
MOV( moonColourField ) );
787 EditorComponentField moonScaleField = {};
788 moonScaleField._name =
"Moon Scale";
789 moonScaleField._data = &_moonScale;
791 moonScaleField._readOnly =
false;
792 moonScaleField._range = { 0.001f, 0.99f };
794 _editorComponent->registerField(
MOV( moonScaleField ) );
797 EditorComponentField separatorField = {};
798 separatorField._name =
"Reset";
800 _editorComponent->registerField(
MOV( separatorField ) );
802 EditorComponentField resetSceneField = {};
803 resetSceneField._name =
"Reset To Scene Default";
804 resetSceneField._tooltip =
"Default = whatever value was set at load time for this scene.";
806 _editorComponent->registerField(
MOV( resetSceneField ) );
808 EditorComponentField resetGlobalField = {};
809 resetGlobalField._name =
"Reset To Global Default";
810 resetGlobalField._tooltip =
"Default = whatever value was encoded into the engine.";
812 _editorComponent->registerField(
MOV( resetGlobalField ) );
814 EditorComponentField rebuildSkyLightField = {};
815 rebuildSkyLightField._name =
"Update Sky Light";
816 rebuildSkyLightField._tooltip =
"Rebuild the sky light data (refresh sky probe)";
818 _editorComponent->registerField(
MOV( rebuildSkyLightField ) );
835const SunInfo& Sky::setDateTime(
struct tm* dateTime )
noexcept
837 _sun.SetDate( *dateTime );
838 return getCurrentDetails();
841const SunInfo& Sky::setGeographicLocation(
const SimpleLocation location )
noexcept
843 _sun.SetLocation( location._longitude, location._latitude );
844 return getCurrentDetails();
847const SunInfo& Sky::setDateTimeAndLocation(
struct tm* dateTime, SimpleLocation location )
noexcept
849 _sun.SetLocation( location._longitude, location._latitude );
850 _sun.SetDate( *dateTime );
851 return getCurrentDetails();
854const SunInfo& Sky::getCurrentDetails()
const
856 return _sun.GetDetails();
859[[nodiscard]] vec3<F32> Sky::getSunPosition(
const F32 radius )
const
861 return _sun.GetSunPosition( radius );
864[[nodiscard]] vec3<F32> Sky::getSunDirection(
const F32 radius)
const
869bool Sky::isDay()
const
871 return getCurrentDetails().altitude > 0.f;
874SimpleTime Sky::GetTimeOfDay() const noexcept
876 return _sun.GetTimeOfDay();
879SimpleLocation Sky::GetGeographicLocation() const noexcept
881 return _sun.GetGeographicLocation();
884void Sky::setAtmosphere(
const Atmosphere& atmosphere )
886 _atmosphere = atmosphere;
887 _atmosphereChanged =
true;
890Handle<Texture> Sky::activeSkyBox() const noexcept
895void Sky::sceneUpdate(
const U64 deltaTimeUS, SceneGraphNode* sgn, SceneState& sceneState )
897 if ( _atmosphereChanged )
899 if ( _atmosphere._cloudLayerMinMaxHeight < 1.f )
901 _atmosphere._cloudLayerMinMaxHeight = 1.f;
903 if ( _atmosphere._cloudLayerMinMaxHeight.min > _atmosphere._cloudLayerMinMaxHeight.max )
905 std::swap( _atmosphere._cloudLayerMinMaxHeight.min, _atmosphere._cloudLayerMinMaxHeight.max );
907 _atmosphereChanged =
false;
913void Sky::enableProceduralClouds(
const bool val )
915 _enableProceduralClouds = val;
916 _atmosphereChanged =
true;
919void Sky::useDaySkybox(
const bool val )
922 _atmosphereChanged =
true;
925void Sky::useNightSkybox(
const bool val )
927 _useNightSkybox = val;
928 _atmosphereChanged =
true;
931void Sky::moonScale(
const F32 val )
934 _atmosphereChanged =
true;
937void Sky::rayCount(
const U16 val )
939 _rayCount = CLAMPED<U16>(val, 32u, 512u);
940 _atmosphereChanged =
true;
943void Sky::exposure(
const F32 val )
945 _exposure =
CLAMPED(val, 0.01f, 128.0f);
946 _atmosphereChanged =
true;
949void Sky::moonColour(
const FColour4 val )
952 _atmosphereChanged =
true;
955void Sky::nightSkyColour(
const FColour4 val )
957 _nightSkyColour = val;
958 _atmosphereChanged =
true;
962void Sky::prepareRender( SceneGraphNode* sgn,
963 RenderingComponent& rComp,
965 GFX::MemoryBarrierCommand& postDrawMemCmd,
966 const RenderStagePass renderStagePass,
967 const CameraSnapshot& cameraSnapshot,
968 const bool refreshData )
971 setSkyShaderData( renderStagePass, pkg.pushConstantsCmd()._fastData );
977 GenericDrawCommand& cmd = cmdsOut.emplace_back();
980 const VertexBuffer_ptr& skyBuffer =
Get(_sky)->geometryBuffer();
981 cmd._sourceBuffer = skyBuffer->handle();
982 cmd._cmd.indexCount =
to_U32( skyBuffer->getIndexCount() );
985 _atmosphereChanged =
true;
#define WAIT_FOR_CONDITION(...)
TaskPool & taskPool(const TaskPoolType type) noexcept
static bool SkyLightNeedsRefresh() noexcept
virtual void sceneUpdate(U64 deltaTimeUS, SceneGraphNode *sgn, SceneState &sceneState)
Called from SceneGraph "sceneUpdate".
virtual void prepareRender(SceneGraphNode *sgn, RenderingComponent &rComp, RenderPackage &pkg, GFX::MemoryBarrierCommand &postDrawMemCmd, RenderStagePass renderStagePass, const CameraSnapshot &cameraSnapshot, bool refreshData)
bool load(PlatformContext &context) override
Loading and unloading interface.
virtual void buildDrawCommands(SceneGraphNode *sgn, GenericDrawCommandContainer &cmdsOut)
U32 FLOAT_TO_UINT(F32 src)
void GeneratePerlinWorleyNoise(PlatformContext &context, const char *fileName, const I32 width, const I32 height, const I32 slices)
const string perlWorlTexName
void GeneratePerlinNoise(const char *fileName, const I32 width, const I32 height)
void GenerateCurlNoise(const char *fileName, const I32 width, const I32 height)
constexpr bool g_alwaysGenerateWeatherTextures
void GenerateWorleyNoise(const char *fileName, const I32 width, const I32 height, const I32 slices)
const string weatherTexName
constexpr bool g_useGroundTruthTextures
Handle console commands that start with a forward slash.
vec2< T > Normalized(vec2< T > vector) noexcept
constexpr SceneNodeType GetSceneNodeType()
static constexpr bool IsDepthPass(const RenderStagePass stagePass) noexcept
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
constexpr U16 to_U16(const T value)
Task * CreateTask(Predicate &&threadedFunction, bool allowedInIdle=true)
void toggleOption(GenericDrawCommand &cmd, CmdRenderOptions option) noexcept
constexpr F32 to_F32(const T value)
bool Finished(const Task &task) noexcept
@ EQUAL
Passes if the incoming YYY value is equal to the stored YYY value.
void WaitForReady(Resource *res)
constexpr Byte to_byte(const T value)
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
::value constexpr T MAP(T input, T in_min, T in_max, T out_min, T out_max, D64 &slopeOut) noexcept
constexpr U8 to_U8(const T value)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
eastl::fixed_vector< GenericDrawCommand, 1, true > GenericDrawCommandContainer
void Start(Task &task, TaskPool &pool, TaskPriority priority=TaskPriority::DONT_CARE, const DELEGATE< void > &onCompletionFunction={})
SceneNodeHandle FromHandle(const Handle< T > handle)
constexpr size_t to_size(const T value)
PropertyDescriptor< Texture > TextureDescriptor
void Parallel_For(TaskPool &pool, const ParallelForDescriptor &descriptor, const DELEGATE< void, const Task *, U32, U32 > &cbk)
bool fileExists(const ResourcePath &filePathAndName)
PropertyDescriptor< ShaderProgram > ShaderProgramDescriptor
@ BACK
Cull Back facing polygons (aka CW)
@ FRONT
Cull Front facing polygons (aka CCW)
FORCE_INLINE T * Get(const Handle< T > handle)
constexpr auto to_base(const Type value) -> Type
static NO_INLINE void printfn(const char *format, T &&... args)
U32 _partitionSize
How many elements should we process per async task.
U32 _iterCount
For loop iteration count.
vector< ShaderModuleDescriptor > _modules