Starry sky (#418)

This commit is contained in:
Turánszki János
2022-04-27 12:51:53 +02:00
committed by GitHub
parent 79e321e9cc
commit d0b3f63511
12 changed files with 111 additions and 61 deletions
+48 -43
View File
@@ -27,14 +27,14 @@ void TerrainGenerator::init()
if (lod == 0)
{
for (int x = 0; x < width - 1; x++)
for (int x = 0; x < chunk_width - 1; x++)
{
for (int z = 0; z < width - 1; z++)
for (int z = 0; z < chunk_width - 1; z++)
{
int lowerLeft = x + z * width;
int lowerRight = (x + 1) + z * width;
int topLeft = x + (z + 1) * width;
int topRight = (x + 1) + (z + 1) * width;
int lowerLeft = x + z * chunk_width;
int lowerRight = (x + 1) + z * chunk_width;
int topLeft = x + (z + 1) * chunk_width;
int topRight = (x + 1) + (z + 1) * chunk_width;
indices.push_back(topLeft);
indices.push_back(lowerLeft);
@@ -50,14 +50,14 @@ void TerrainGenerator::init()
{
const int step = 1 << lod;
// inner grid:
for (int x = 1; x < width - 2; x += step)
for (int x = 1; x < chunk_width - 2; x += step)
{
for (int z = 1; z < width - 2; z += step)
for (int z = 1; z < chunk_width - 2; z += step)
{
int lowerLeft = x + z * width;
int lowerRight = (x + step) + z * width;
int topLeft = x + (z + step) * width;
int topRight = (x + step) + (z + step) * width;
int lowerLeft = x + z * chunk_width;
int lowerRight = (x + step) + z * chunk_width;
int topLeft = x + (z + step) * chunk_width;
int topRight = (x + step) + (z + step) * chunk_width;
indices.push_back(topLeft);
indices.push_back(lowerLeft);
@@ -69,12 +69,12 @@ void TerrainGenerator::init()
}
}
// bottom border:
for (int x = 0; x < width - 1; ++x)
for (int x = 0; x < chunk_width - 1; ++x)
{
const int z = 0;
int current = x + z * width;
int neighbor = x + 1 + z * width;
int connection = 1 + ((x + (step + 1) / 2 - 1) / step) * step + (z + 1) * width;
int current = x + z * chunk_width;
int neighbor = x + 1 + z * chunk_width;
int connection = 1 + ((x + (step + 1) / 2 - 1) / step) * step + (z + 1) * chunk_width;
indices.push_back(current);
indices.push_back(neighbor);
@@ -82,7 +82,7 @@ void TerrainGenerator::init()
if (((x - 1) % (step)) == step / 2) // halfway fill triangle
{
int connection1 = 1 + (((x - 1) + (step + 1) / 2 - 1) / step) * step + (z + 1) * width;
int connection1 = 1 + (((x - 1) + (step + 1) / 2 - 1) / step) * step + (z + 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection);
@@ -90,12 +90,12 @@ void TerrainGenerator::init()
}
}
// top border:
for (int x = 0; x < width - 1; ++x)
for (int x = 0; x < chunk_width - 1; ++x)
{
const int z = width - 1;
int current = x + z * width;
int neighbor = x + 1 + z * width;
int connection = 1 + ((x + (step + 1) / 2 - 1) / step) * step + (z - 1) * width;
const int z = chunk_width - 1;
int current = x + z * chunk_width;
int neighbor = x + 1 + z * chunk_width;
int connection = 1 + ((x + (step + 1) / 2 - 1) / step) * step + (z - 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection);
@@ -103,7 +103,7 @@ void TerrainGenerator::init()
if (((x - 1) % (step)) == step / 2) // halfway fill triangle
{
int connection1 = 1 + (((x - 1) + (step + 1) / 2 - 1) / step) * step + (z - 1) * width;
int connection1 = 1 + (((x - 1) + (step + 1) / 2 - 1) / step) * step + (z - 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection1);
@@ -111,12 +111,12 @@ void TerrainGenerator::init()
}
}
// left border:
for (int z = 0; z < width - 1; ++z)
for (int z = 0; z < chunk_width - 1; ++z)
{
const int x = 0;
int current = x + z * width;
int neighbor = x + (z + 1) * width;
int connection = x + 1 + (((z + (step + 1) / 2 - 1) / step) * step + 1) * width;
int current = x + z * chunk_width;
int neighbor = x + (z + 1) * chunk_width;
int connection = x + 1 + (((z + (step + 1) / 2 - 1) / step) * step + 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection);
@@ -124,7 +124,7 @@ void TerrainGenerator::init()
if (((z - 1) % (step)) == step / 2) // halfway fill triangle
{
int connection1 = x + 1 + ((((z - 1) + (step + 1) / 2 - 1) / step) * step + 1) * width;
int connection1 = x + 1 + ((((z - 1) + (step + 1) / 2 - 1) / step) * step + 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection1);
@@ -132,12 +132,12 @@ void TerrainGenerator::init()
}
}
// right border:
for (int z = 0; z < width - 1; ++z)
for (int z = 0; z < chunk_width - 1; ++z)
{
const int x = width - 1;
int current = x + z * width;
int neighbor = x + (z + 1) * width;
int connection = x - 1 + (((z + (step + 1) / 2 - 1) / step) * step + 1) * width;
const int x = chunk_width - 1;
int current = x + z * chunk_width;
int neighbor = x + (z + 1) * chunk_width;
int connection = x - 1 + (((z + (step + 1) / 2 - 1) / step) * step + 1) * chunk_width;
indices.push_back(current);
indices.push_back(neighbor);
@@ -145,7 +145,7 @@ void TerrainGenerator::init()
if (((z - 1) % (step)) == step / 2) // halfway fill triangle
{
int connection1 = x - 1 + ((((z - 1) + (step + 1) / 2 - 1) / step) * step + 1) * width;
int connection1 = x - 1 + ((((z - 1) + (step + 1) / 2 - 1) / step) * step + 1) * chunk_width;
indices.push_back(current);
indices.push_back(connection);
@@ -547,6 +547,7 @@ void TerrainGenerator::Generation_Restart()
weather.cloud_shadow_amount = 0.5f;
weather.cloud_shadow_scale = 0.003f;
weather.cloud_shadow_speed = 0.25f;
weather.stars = 0.6f;
}
if (scene->lights.GetCount() == 0)
{
@@ -559,6 +560,7 @@ void TerrainGenerator::Generation_Restart()
//light.SetVolumetricsEnabled(true);
TransformComponent& transform = *scene->transforms.GetComponent(sunEntity);
transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV4, 0, XM_PIDIV4));
transform.Translate(XMFLOAT3(0, 2, 0));
}
}
@@ -579,8 +581,8 @@ void TerrainGenerator::Generation_Update()
if (centerToCamCheckBox.GetCheck())
{
const CameraComponent& camera = GetCamera();
center_chunk.x = (int)std::floor((camera.Eye.x + half_width) * width_rcp);
center_chunk.z = (int)std::floor((camera.Eye.z + half_width) * width_rcp);
center_chunk.x = (int)std::floor((camera.Eye.x + chunk_half_width) * chunk_width_rcp);
center_chunk.z = (int)std::floor((camera.Eye.z + chunk_half_width) * chunk_width_rcp);
}
// Chunk removal checks:
@@ -641,6 +643,7 @@ void TerrainGenerator::Generation_Update()
const float region1 = region1Slider.GetValue();
const float region2 = region2Slider.GetValue();
const float region3 = region3Slider.GetValue();
bool generated_something = false;
auto request_chunk = [&](int offset_x, int offset_z)
{
@@ -660,7 +663,7 @@ void TerrainGenerator::Generation_Update()
TransformComponent& transform = *generation_scene.transforms.GetComponent(chunk_data.entity);
transform.ClearTransform();
const XMFLOAT3 chunk_pos = XMFLOAT3(float(chunk.x * (width - 1)), 0, float(chunk.z * (width - 1)));
const XMFLOAT3 chunk_pos = XMFLOAT3(float(chunk.x * (chunk_width - 1)), 0, float(chunk.z * (chunk_width - 1)));
transform.Translate(chunk_pos);
transform.UpdateTransform();
@@ -690,10 +693,10 @@ void TerrainGenerator::Generation_Update()
// Do a parallel for loop over all the chunk's vertices and compute their properties:
wi::jobsystem::context ctx;
wi::jobsystem::Dispatch(ctx, vertexCount, width, [&](wi::jobsystem::JobArgs args) {
wi::jobsystem::Dispatch(ctx, vertexCount, chunk_width, [&](wi::jobsystem::JobArgs args) {
uint32_t index = args.jobIndex;
const float x = float(index % width) - half_width;
const float z = float(index / width) - half_width;
const float x = float(index % chunk_width) - chunk_half_width;
const float z = float(index / chunk_width) - chunk_half_width;
XMVECTOR corners[3];
XMFLOAT2 corner_offsets[3] = {
XMFLOAT2(0, 0),
@@ -763,7 +766,7 @@ void TerrainGenerator::Generation_Update()
mesh.vertex_positions[index] = XMFLOAT3(x, height, z);
mesh.vertex_normals[index] = normal;
mesh.vertex_colors[index] = wi::Color::fromFloat4(materialBlendWeights);
const XMFLOAT2 uv = XMFLOAT2(x * width_rcp + 0.5f, z * width_rcp + 0.5f);
const XMFLOAT2 uv = XMFLOAT2(x * chunk_width_rcp + 0.5f, z * chunk_width_rcp + 0.5f);
mesh.vertex_uvset_0[index] = uv;
XMFLOAT3 vertex_pos(chunk_pos.x + x, height, chunk_pos.z + z);
@@ -793,7 +796,7 @@ void TerrainGenerator::Generation_Update()
chunk_data.grass = std::move(grass); // the grass will be added to the scene later, only when the chunk is close to the camera (center chunk's neighbors)
chunk_data.grass.meshID = chunk_data.entity;
chunk_data.grass.strandCount = grass_valid_vertex_count.load() * 3;
chunk_data.grass.viewDistance = width;
chunk_data.grass.viewDistance = chunk_width;
generation_scene.materials.Create(chunk_data.entity) = material_GrassParticle;
}
@@ -861,6 +864,7 @@ void TerrainGenerator::Generation_Update()
}
wi::jobsystem::Wait(ctx); // wait until mesh.CreateRenderData() async task finishes
generated_something = true;
}
// Grass patch placement:
@@ -884,12 +888,13 @@ void TerrainGenerator::Generation_Update()
grass.CreateRenderData(*mesh);
}
chunk_data.grass_exists = true; // don't generate more grass here
generated_something = true;
}
}
}
}
if (timer.elapsed_milliseconds() > generation_time_budget_milliseconds)
if (generated_something && timer.elapsed_milliseconds() > generation_time_budget_milliseconds)
{
generation_cancelled.store(true);
}
+5 -5
View File
@@ -39,11 +39,11 @@ struct ChunkData
struct TerrainGenerator : public wi::gui::Window
{
inline static const int width = 64 + 3; // + 3: filler vertices for lod apron and grid perimeter
inline static const float half_width = (width - 1) * 0.5f;
inline static const float width_rcp = 1.0f / (width - 1);
inline static const uint32_t vertexCount = width * width;
inline static const int max_lod = (int)std::log2(width - 3) + 1;
inline static const int chunk_width = 64 + 3; // + 3: filler vertices for lod apron and grid perimeter
inline static const float chunk_half_width = (chunk_width - 1) * 0.5f;
inline static const float chunk_width_rcp = 1.0f / (chunk_width - 1);
inline static const uint32_t vertexCount = chunk_width * chunk_width;
inline static const int max_lod = (int)std::log2(chunk_width - 3) + 1;
wi::scene::Scene* scene = &wi::scene::GetScene(); // by default it uses the global scene, but this can be changed
wi::ecs::Entity terrainEntity = wi::ecs::INVALID_ENTITY;
wi::ecs::Entity materialEntity_Base = wi::ecs::INVALID_ENTITY;
+10
View File
@@ -162,6 +162,15 @@ void WeatherWindow::Create(EditorComponent* editor)
});
AddWidget(&skyExposureSlider);
starsSlider.Create(0, 1, 0.5f, 10000, "Stars: ");
starsSlider.SetTooltip("Amount of stars in the night sky (0 to disable). \nIt will only work with the realistic sky enabled. \nThey will be more visible at night time.");
starsSlider.SetSize(XMFLOAT2(100, hei));
starsSlider.SetPos(XMFLOAT2(x, y += step));
starsSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().stars = args.fValue;
});
AddWidget(&starsSlider);
simpleskyCheckBox.Create("Simple sky: ");
simpleskyCheckBox.SetTooltip("Simple sky will simply blend horizon and zenith color from bottom to top.");
simpleskyCheckBox.SetSize(XMFLOAT2(hei, hei));
@@ -686,6 +695,7 @@ void WeatherWindow::Update()
windWaveSizeSlider.SetValue(weather.windWaveSize);
windRandomnessSlider.SetValue(weather.windRandomness);
skyExposureSlider.SetValue(weather.skyExposure);
starsSlider.SetValue(weather.stars);
windMagnitudeSlider.SetValue(XMVectorGetX(XMVector3Length(XMLoadFloat3(&weather.windDirection))));
switch (colorComboBox.GetSelected())
+1
View File
@@ -32,6 +32,7 @@ public:
wi::gui::Slider windWaveSizeSlider;
wi::gui::Slider windRandomnessSlider;
wi::gui::Slider skyExposureSlider;
wi::gui::Slider starsSlider;
wi::gui::CheckBox simpleskyCheckBox;
wi::gui::CheckBox realisticskyCheckBox;
wi::gui::Button skyButton;
+1
View File
@@ -1,5 +1,6 @@
This file contains changelog of wi::Archive versions
78: serialized stars parameter in weather
77: serialized cloud shadow properties
76: serialized LOD parameters
75: PreviousFrameTransformComponent is no longer serialized
@@ -303,6 +303,11 @@ struct ShaderWeather
float cloud_shadow_scale;
float cloud_shadow_speed;
float3 padding;
float stars; // number of stars (0: disable stars, >0: increase number of stars)
float4x4 stars_rotation;
ShaderFog fog;
ShaderWind wind;
ShaderOcean ocean;
+24 -11
View File
@@ -411,22 +411,35 @@ float3 GetSunLuminance(float3 worldPosition, float3 worldDirection, float3 sunDi
float sunHalfApexAngleRadian = 0.5 * sunApexAngleDegree * PI / 180.0;
float sunCosHalfApexAngle = cos(sunHalfApexAngleRadian);
float VdotL = dot(worldDirection, normalize(sunDirection)); // weird... the sun disc shrinks near the horizon if we don't normalize sun direction
float3 retval = 0;
if (VdotL > sunCosHalfApexAngle)
{
float t = RaySphereIntersectNearest(worldPosition, worldDirection, float3(0.0f, 0.0f, 0.0f), atmosphere.bottomRadius);
if (t < 0.0f) // no intersection
{
const float3 atmosphereTransmittance = GetAtmosphereTransmittance(worldPosition, worldDirection, atmosphere, transmittanceLutTexture);
// Edge fade
float t = RaySphereIntersectNearest(worldPosition, worldDirection, float3(0.0f, 0.0f, 0.0f), atmosphere.bottomRadius);
if (t < 0.0f) // no intersection
{
float VdotL = dot(worldDirection, normalize(sunDirection)); // weird... the sun disc shrinks near the horizon if we don't normalize sun direction
if (VdotL > sunCosHalfApexAngle)
{
// Edge fade
const float halfCosHalfApex = sunCosHalfApexAngle + (1.0f - sunCosHalfApexAngle) * 0.25; // Start fading when at 75% distance from light disk center
const float weight = 1.0 - saturate((halfCosHalfApex - VdotL) / (halfCosHalfApex - sunCosHalfApexAngle));
retval = atmosphereTransmittance * weight * sunIlluminance;
retval = weight * sunIlluminance;
}
if (GetWeather().stars > 0)
{
float3 stars_direction = mul(worldDirection, (float3x3)GetWeather().stars_rotation);
float stars_visibility = pow(saturate(1 - sunDirection.y), 2);
float stars_density_at_maximum = lerp(22, 8, GetWeather().stars);
float stars_threshold = lerp(32, stars_density_at_maximum, stars_visibility); // modifies the number of stars that are visible
float stars_exposure = lerp(0, 512, stars_visibility); // modifies the overall strength of the stars
float stars = saturate(pow(noise_gradient_3D(stars_direction * 300), stars_threshold)) * stars_exposure;
stars *= lerp(0.4, 1.4, noise_gradient_3D(stars_direction * 256 + GetTime())); // time based flickering
retval += stars;
}
const float3 atmosphereTransmittance = GetAtmosphereTransmittance(worldPosition, worldDirection, atmosphere, transmittanceLutTexture);
retval *= atmosphereTransmittance;
}
return retval;
+1 -1
View File
@@ -5,7 +5,7 @@ namespace wi
{
// this should always be only INCREMENTED and only if a new serialization is implemeted somewhere!
static constexpr uint64_t __archiveVersion = 77;
static constexpr uint64_t __archiveVersion = 78;
// this is the version number of which below the archive is not compatible with the current version
static constexpr uint64_t __archiveVersionBarrier = 22;
+3
View File
@@ -1906,6 +1906,8 @@ namespace wi::scene
shaderscene.weather.ocean.patch_size_rcp = 1.0f / weather.oceanParameters.patch_length;
shaderscene.weather.ocean.texture_displacementmap = device->GetDescriptorIndex(ocean.getDisplacementMap(), SubresourceType::SRV);
shaderscene.weather.ocean.texture_gradientmap = device->GetDescriptorIndex(ocean.getGradientMap(), SubresourceType::SRV);
shaderscene.weather.stars = weather.stars;
XMStoreFloat4x4(&shaderscene.weather.stars_rotation, XMMatrixRotationQuaternion(XMLoadFloat4(&weather.stars_rotation_quaternion)));
shaderscene.ddgi.color_texture = device->GetDescriptorIndex(&ddgiColorTexture[0], SubresourceType::SRV);
shaderscene.ddgi.depth_texture = device->GetDescriptorIndex(&ddgiDepthTexture[0], SubresourceType::SRV);
@@ -3755,6 +3757,7 @@ namespace wi::scene
weather.sunColor = light.color;
weather.sunDirection = light.direction;
weather.sunEnergy = light.energy;
weather.stars_rotation_quaternion = light.rotation;
}
locker.unlock();
break;
+2
View File
@@ -1172,6 +1172,7 @@ namespace wi::scene
float windRandomness = 5;
float windWaveSize = 1;
float windSpeed = 1;
float stars = 0.5f;
wi::Ocean::OceanParameters oceanParameters;
AtmosphereParameters atmosphereParameters;
@@ -1184,6 +1185,7 @@ namespace wi::scene
uint32_t most_important_light_index = ~0u;
wi::Resource skyMap;
wi::Resource colorGradingMap;
XMFLOAT4 stars_rotation_quaternion = XMFLOAT4(0, 0, 0, 1);
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};
+10
View File
@@ -1114,6 +1114,11 @@ namespace wi::scene
archive >> cloud_shadow_scale;
archive >> cloud_shadow_speed;
}
if (archive.GetVersion() >= 78)
{
archive >> stars;
}
}
else
{
@@ -1254,6 +1259,11 @@ namespace wi::scene
archive << cloud_shadow_scale;
archive << cloud_shadow_speed;
}
if (archive.GetVersion() >= 78)
{
archive << stars;
}
}
}
void SoundComponent::Serialize(wi::Archive& archive, EntitySerializer& seri)
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 60;
// minor bug fixes, alterations, refactors, updates
const int revision = 59;
const int revision = 60;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);