Terrain determinism fixes (#1096)

This commit is contained in:
Turánszki János
2025-04-28 18:20:15 +02:00
committed by GitHub
parent 89604436d2
commit 8582ea3dc3
9 changed files with 222 additions and 139 deletions
+89 -68
View File
@@ -19,7 +19,7 @@ ModifierWindow::ModifierWindow(const std::string& name)
blendCombo.OnSelect([=](wi::gui::EventArgs args) {
modifier->blend = (wi::terrain::Modifier::BlendMode)args.userdata;
generation_callback();
});
});
AddWidget(&blendCombo);
weightSlider.Create(0, 1, 0.5f, 10000, "Weight: ");
@@ -28,31 +28,31 @@ ModifierWindow::ModifierWindow(const std::string& name)
weightSlider.OnSlide([=](wi::gui::EventArgs args) {
modifier->weight = args.fValue;
generation_callback();
});
});
AddWidget(&weightSlider);
frequencySlider.Create(0.0001f, 0.01f, 0.0008f, 10000, "Frequency: ");
frequencySlider.SetSize(XMFLOAT2(100, 20));
frequencySlider.SetTooltip("Frequency for the tiling");
frequencySlider.OnSlide([=](wi::gui::EventArgs args) {
modifier->frequency = args.fValue;
scaleSlider.Create(0.1f, 10000, 1000, 10000, "Scale: ");
scaleSlider.SetSize(XMFLOAT2(100, 20));
scaleSlider.SetTooltip("Horizontal world scale of the modifier");
scaleSlider.OnSlide([=](wi::gui::EventArgs args) {
modifier->SetScale(args.fValue);
generation_callback();
});
AddWidget(&frequencySlider);
});
AddWidget(&scaleSlider);
}
void ModifierWindow::Bind(wi::terrain::Modifier* ptr)
{
modifier = ptr;
modifier->blend = (wi::terrain::Modifier::BlendMode)blendCombo.GetItemUserData(blendCombo.GetSelected());
modifier->weight = weightSlider.GetValue();
modifier->frequency = frequencySlider.GetValue();
modifier->SetScale(scaleSlider.GetValue());
}
void ModifierWindow::From(wi::terrain::Modifier* ptr)
{
modifier = ptr;
blendCombo.SetSelectedByUserdataWithoutCallback((uint64_t)ptr->blend);
weightSlider.SetValue(ptr->weight);
frequencySlider.SetValue(ptr->frequency);
scaleSlider.SetValue(ptr->GetScale());
}
PerlinModifierWindow::PerlinModifierWindow() : ModifierWindow("Perlin Noise")
@@ -87,7 +87,7 @@ void PerlinModifierWindow::ResizeLayout()
add(blendCombo);
add(weightSlider);
add(frequencySlider);
add(scaleSlider);
add(octavesSlider);
}
@@ -161,7 +161,7 @@ void VoronoiModifierWindow::ResizeLayout()
add(blendCombo);
add(weightSlider);
add(frequencySlider);
add(scaleSlider);
add(fadeSlider);
add(shapeSlider);
@@ -188,15 +188,15 @@ void VoronoiModifierWindow::From(wi::terrain::VoronoiModifier* ptr)
HeightmapModifierWindow::HeightmapModifierWindow() : ModifierWindow("Heightmap")
{
weightSlider.SetValue(1);
frequencySlider.SetValue(1);
amountSlider.SetValue(1000);
scaleSlider.Create(0, 1, 0.1f, 1000, "Scale: ");
scaleSlider.SetSize(XMFLOAT2(100, 20));
scaleSlider.OnSlide([=](wi::gui::EventArgs args) {
((wi::terrain::HeightmapModifier*)modifier)->scale = args.fValue;
amountSlider.Create(0, 1, 0.1f, 1000, "Amount: ");
amountSlider.SetSize(XMFLOAT2(100, 20));
amountSlider.OnSlide([=](wi::gui::EventArgs args) {
((wi::terrain::HeightmapModifier*)modifier)->amount = args.fValue;
generation_callback();
});
AddWidget(&scaleSlider);
AddWidget(&amountSlider);
loadButton.Create("Load Heightmap...");
loadButton.SetTooltip("Load a heightmap texture, where the red channel corresponds to terrain height and the resolution to dimensions.\nThe heightmap will be placed in the world center.\nIt is recommended to use a 16-bit PNG for heightmaps.");
@@ -275,20 +275,20 @@ void HeightmapModifierWindow::ResizeLayout()
add(blendCombo);
add(weightSlider);
add(frequencySlider);
add(scaleSlider);
add(amountSlider);
add(loadButton);
}
void HeightmapModifierWindow::Bind(wi::terrain::HeightmapModifier* ptr)
{
ModifierWindow::Bind(ptr);
ptr->scale = scaleSlider.GetValue();
ptr->amount = amountSlider.GetValue();
}
void HeightmapModifierWindow::From(wi::terrain::HeightmapModifier* ptr)
{
ModifierWindow::From(ptr);
scaleSlider.SetValue(ptr->scale);
amountSlider.SetValue(ptr->amount);
}
PropWindow::PropWindow(wi::terrain::Terrain* terrain, wi::terrain::Prop* prop, wi::scene::Scene* scene)
@@ -899,10 +899,10 @@ void TerrainWindow::Create(EditorComponent* _editor)
bottomLevelSlider.SetValue(-60);
topLevelSlider.SetValue(380);
perlin->weightSlider.SetValue(0.5f);
perlin->frequencySlider.SetValue(0.0008f);
perlin->scaleSlider.SetValue(1250);
perlin->octavesSlider.SetValue(6);
voronoi->weightSlider.SetValue(0.5f);
voronoi->frequencySlider.SetValue(0.001f);
voronoi->scaleSlider.SetValue(1000);
voronoi->fadeSlider.SetValue(2.59f);
voronoi->shapeSlider.SetValue(0.7f);
voronoi->falloffSlider.SetValue(6);
@@ -917,10 +917,10 @@ void TerrainWindow::Create(EditorComponent* _editor)
bottomLevelSlider.SetValue(-79);
topLevelSlider.SetValue(520);
perlin->weightSlider.SetValue(0.5f);
perlin->frequencySlider.SetValue(0.000991f);
perlin->scaleSlider.SetValue(500);
perlin->octavesSlider.SetValue(6);
voronoi->weightSlider.SetValue(0.5f);
voronoi->frequencySlider.SetValue(0.000317f);
voronoi->scaleSlider.SetValue(3154);
voronoi->fadeSlider.SetValue(8.2f);
voronoi->shapeSlider.SetValue(0.126f);
voronoi->falloffSlider.SetValue(1.392f);
@@ -935,17 +935,17 @@ void TerrainWindow::Create(EditorComponent* _editor)
bottomLevelSlider.SetValue(0);
topLevelSlider.SetValue(2960);
perlin->weightSlider.SetValue(0.5f);
perlin->frequencySlider.SetValue(0.00279f);
perlin->scaleSlider.SetValue(699);
perlin->octavesSlider.SetValue(8);
voronoi->weightSlider.SetValue(0.5f);
voronoi->frequencySlider.SetValue(0.000496f);
voronoi->scaleSlider.SetValue(2016);
voronoi->fadeSlider.SetValue(5.2f);
voronoi->shapeSlider.SetValue(0.412f);
voronoi->falloffSlider.SetValue(1.456f);
voronoi->perturbationSlider.SetValue(0.092f);
region1Slider.SetValue(1);
region2Slider.SetValue(1);
region3Slider.SetValue(0.8f);
region1Slider.SetValue(0.7f);
region2Slider.SetValue(2);
region3Slider.SetValue(0.2f);
break;
case PRESET_ARCTIC:
terrain->weather.SetOceanEnabled(false);
@@ -953,10 +953,10 @@ void TerrainWindow::Create(EditorComponent* _editor)
bottomLevelSlider.SetValue(-50);
topLevelSlider.SetValue(40);
perlin->weightSlider.SetValue(1);
perlin->frequencySlider.SetValue(0.002f);
perlin->scaleSlider.SetValue(500);
perlin->octavesSlider.SetValue(4);
voronoi->weightSlider.SetValue(1);
voronoi->frequencySlider.SetValue(0.004f);
voronoi->scaleSlider.SetValue(250);
voronoi->fadeSlider.SetValue(1.8f);
voronoi->shapeSlider.SetValue(0.518f);
voronoi->falloffSlider.SetValue(0.2f);
@@ -971,10 +971,10 @@ void TerrainWindow::Create(EditorComponent* _editor)
bottomLevelSlider.SetValue(-50);
topLevelSlider.SetValue(40);
perlin->weightSlider.SetValue(1);
perlin->frequencySlider.SetValue(0.002f);
perlin->scaleSlider.SetValue(500);
perlin->octavesSlider.SetValue(4);
voronoi->weightSlider.SetValue(1);
voronoi->frequencySlider.SetValue(0.004f);
voronoi->scaleSlider.SetValue(250);
voronoi->fadeSlider.SetValue(1.8f);
voronoi->shapeSlider.SetValue(0.518f);
voronoi->falloffSlider.SetValue(0.2f);
@@ -1027,7 +1027,7 @@ void TerrainWindow::Create(EditorComponent* _editor)
PerlinModifierWindow* ptr = new PerlinModifierWindow;
std::shared_ptr<wi::terrain::PerlinModifier> modifier = std::make_shared<wi::terrain::PerlinModifier>();
terrain->modifiers.push_back(modifier);
ptr->Bind(modifier.get());
ptr->From(modifier.get());
AddModifier(ptr);
}
break;
@@ -1036,7 +1036,7 @@ void TerrainWindow::Create(EditorComponent* _editor)
VoronoiModifierWindow* ptr = new VoronoiModifierWindow;
std::shared_ptr<wi::terrain::VoronoiModifier> modifier = std::make_shared<wi::terrain::VoronoiModifier>();
terrain->modifiers.push_back(modifier);
ptr->Bind(modifier.get());
ptr->From(modifier.get());
AddModifier(ptr);
}
break;
@@ -1045,7 +1045,7 @@ void TerrainWindow::Create(EditorComponent* _editor)
HeightmapModifierWindow* ptr = new HeightmapModifierWindow;
std::shared_ptr<wi::terrain::HeightmapModifier> modifier = std::make_shared<wi::terrain::HeightmapModifier>();
terrain->modifiers.push_back(modifier);
ptr->Bind(modifier.get());
ptr->From(modifier.get());
AddModifier(ptr);
}
break;
@@ -1371,7 +1371,6 @@ void TerrainWindow::SetEntity(Entity entity)
modifiers_to_remove.push_back(x.get());
}
centerToCamCheckBox.SetCheck(terrain->IsCenterToCamEnabled());
removalCheckBox.SetCheck(terrain->IsRemovalEnabled());
grassCheckBox.SetCheck(terrain->IsGrassEnabled());
@@ -1393,34 +1392,7 @@ void TerrainWindow::SetEntity(Entity entity)
region2Slider.SetValue(terrain->region2);
region3Slider.SetValue(terrain->region3);
auto fillMaterialCombo = [&](wi::gui::ComboBox& comboBox, Entity selected) {
comboBox.ClearItems();
comboBox.AddItem("NO MATERIAL", INVALID_ENTITY);
for (size_t i = 0; i < scene.materials.GetCount(); ++i)
{
Entity entity = scene.materials.GetEntity(i);
if (scene.names.Contains(entity))
{
const NameComponent& name = *scene.names.GetComponent(entity);
comboBox.AddItem(name.name, entity);
}
else
{
comboBox.AddItem(std::to_string(entity), entity);
}
if (selected == entity)
{
comboBox.SetSelectedWithoutCallback(int(i + 1));
}
}
};
for (size_t i = 0; i < arraysize(materialCombos); ++i)
{
fillMaterialCombo(materialCombos[i], terrain->materialEntities[i]);
}
fillMaterialCombo(materialCombo_GrassParticle, terrain->grassEntity);
RefreshMaterialComboBoxes();
for (auto& x : terrain->modifiers)
{
@@ -1455,6 +1427,38 @@ void TerrainWindow::SetEntity(Entity entity)
editor->paintToolWnd.RecreateTerrainMaterialButtons();
}
void TerrainWindow::RefreshMaterialComboBoxes()
{
wi::scene::Scene& scene = editor->GetCurrentScene();
auto fillMaterialCombo = [&](wi::gui::ComboBox& comboBox, Entity selected) {
comboBox.ClearItems();
comboBox.AddItem("NO MATERIAL", INVALID_ENTITY);
for (size_t i = 0; i < scene.materials.GetCount(); ++i)
{
Entity entity = scene.materials.GetEntity(i);
if (scene.names.Contains(entity))
{
const NameComponent& name = *scene.names.GetComponent(entity);
comboBox.AddItem(name.name, entity);
}
else
{
comboBox.AddItem(std::to_string(entity), entity);
}
if (selected == entity)
{
comboBox.SetSelectedWithoutCallback(int(i + 1));
}
}
};
for (size_t i = 0; i < arraysize(materialCombos); ++i)
{
fillMaterialCombo(materialCombos[i], terrain->materialEntities[i]);
}
fillMaterialCombo(materialCombo_GrassParticle, terrain->grassEntity);
}
void TerrainWindow::AddModifier(ModifierWindow* modifier_window)
{
modifier_window->generation_callback = [=]() {
@@ -1488,6 +1492,21 @@ void TerrainWindow::SetupAssets()
{
terrain_preset.materialEntities[i] = CreateEntity();
currentScene.materials.Create(terrain_preset.materialEntities[i]);
switch (i)
{
case wi::terrain::MATERIAL_BASE:
currentScene.names.Create(terrain_preset.materialEntities[i]) = "Base";
break;
case wi::terrain::MATERIAL_SLOPE:
currentScene.names.Create(terrain_preset.materialEntities[i]) = "Slope";
break;
case wi::terrain::MATERIAL_LOW_ALTITUDE:
currentScene.names.Create(terrain_preset.materialEntities[i]) = "LowAltitude";
break;
case wi::terrain::MATERIAL_HIGH_ALTITUDE:
currentScene.names.Create(terrain_preset.materialEntities[i]) = "HighAltitude";
break;
}
currentScene.Component_Attach(terrain_preset.materialEntities[i], entity);
}
@@ -1833,6 +1852,8 @@ void TerrainWindow::SetupAssets()
presetCombo.SetSelected(0);
editor->paintToolWnd.RecreateTerrainMaterialButtons();
RefreshMaterialComboBoxes();
}
void TerrainWindow::Update(const wi::Canvas& canvas, float dt)
+4 -2
View File
@@ -7,7 +7,7 @@ struct ModifierWindow : public wi::gui::Window
std::function<void()> generation_callback;
wi::gui::ComboBox blendCombo;
wi::gui::Slider weightSlider;
wi::gui::Slider frequencySlider;
wi::gui::Slider scaleSlider;
virtual ~ModifierWindow() = default;
@@ -38,7 +38,7 @@ struct VoronoiModifierWindow : public ModifierWindow
};
struct HeightmapModifierWindow : public ModifierWindow
{
wi::gui::Slider scaleSlider;
wi::gui::Slider amountSlider;
wi::gui::Button loadButton;
HeightmapModifierWindow();
@@ -149,6 +149,8 @@ public:
void AddModifier(ModifierWindow* modifier_window);
void SetupAssets();
void RefreshMaterialComboBoxes();
void Update(const wi::Canvas& canvas, float dt) override;
void ResizeLayout() override;
};
+4 -3
View File
@@ -6667,6 +6667,8 @@ std::mutex queue_locker;
commandlist.GetGraphicsCommandList()->IASetPrimitiveTopology(internal_state->primitiveTopology);
}
}
else
return; // early exit for static pso
commandlist.prev_pipeline_hash = {};
commandlist.dirty_pso = false;
@@ -6678,7 +6680,8 @@ std::mutex queue_locker;
pipeline_hash.renderpass_hash = commandlist.renderpass_info.get_hash();
if (commandlist.prev_pipeline_hash == pipeline_hash)
{
return;
commandlist.active_pso = pso;
return; // early exit for dynamic pso|renderpass
}
commandlist.prev_pipeline_hash = pipeline_hash;
commandlist.dirty_pso = true;
@@ -6700,9 +6703,7 @@ std::mutex queue_locker;
{
CommandList_DX12& commandlist = GetCommandList(cmd);
if (commandlist.active_cs == cs)
{
return;
}
commandlist.active_pso = nullptr;
commandlist.active_rt = nullptr;
+3 -3
View File
@@ -8257,8 +8257,6 @@ using namespace vulkan_internal;
void GraphicsDevice_Vulkan::BindPipelineState(const PipelineState* pso, CommandList cmd)
{
CommandList_Vulkan& commandlist = GetCommandList(cmd);
if (commandlist.active_pso == pso)
return;
commandlist.active_cs = nullptr;
commandlist.active_rt = nullptr;
@@ -8270,6 +8268,8 @@ using namespace vulkan_internal;
{
vkCmdBindPipeline(commandlist.GetCommandBuffer(), VK_PIPELINE_BIND_POINT_GRAPHICS, internal_state->pipeline);
}
else
return; // early exit for static pso
commandlist.prev_pipeline_hash = {};
commandlist.dirty_pso = false;
@@ -8282,7 +8282,7 @@ using namespace vulkan_internal;
if (commandlist.prev_pipeline_hash == pipeline_hash)
{
commandlist.active_pso = pso;
return;
return; // early exit for dynamic pso|renderpass
}
commandlist.prev_pipeline_hash = pipeline_hash;
commandlist.dirty_pso = true;
+101 -26
View File
@@ -1,8 +1,11 @@
#pragma once
#include "CommonInclude.h"
#include "wiMath.h"
#include "wiArchive.h"
#include "wiRandom.h"
#include "wiMath.h"
// Note: these should be implemented independently of math library optimizations to be cross platform deterministic!
// Otherwise the terrain generation might be different across platforms
namespace wi::noise
{
@@ -119,52 +122,124 @@ namespace wi::noise
// Based on: https://www.shadertoy.com/view/MslGD8
namespace voronoi
{
inline XMVECTOR fract(XMVECTOR p)
constexpr float dot(XMFLOAT2 a, XMFLOAT2 b)
{
return p - XMVectorFloor(p);
return a.x * b.x + a.y * b.y;
}
inline XMVECTOR hash(XMVECTOR p)
inline XMFLOAT2 fract(XMFLOAT2 p)
{
p = XMVectorSet(
XMVectorGetX(XMVector2Dot(p, XMVectorSet(127.1f, 311.7f, 0, 0))),
XMVectorGetX(XMVector2Dot(p, XMVectorSet(269.5f, 183.3f, 0, 0))),
0,
0
return XMFLOAT2(
p.x - std::floor(p.x),
p.y - std::floor(p.y)
);
return fract(XMVectorSin(p) * 18.5453f);
}
inline XMFLOAT2 floor(XMFLOAT2 p)
{
return XMFLOAT2(
std::floor(p.x),
std::floor(p.y)
);
}
// Backwards compatibility implementation for XMVectorSin() without FMA instruction:
inline XMVECTOR XM_CALLCONV FMADD_COMPAT(XMVECTOR a, XMVECTOR b, XMVECTOR c) noexcept { return _mm_add_ps(_mm_mul_ps((a), (b)), (c)); }
inline XMVECTOR XM_CALLCONV FNMADD_COMPAT(XMVECTOR a, XMVECTOR b, XMVECTOR c) noexcept { return _mm_sub_ps((c), _mm_mul_ps((a), (b))); }
inline XMVECTOR XM_CALLCONV XMVectorModAngles_COMPAT(FXMVECTOR Angles) noexcept
{
// Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
XMVECTOR vResult = _mm_mul_ps(Angles, g_XMReciprocalTwoPi);
// Use the inline function due to complexity for rounding
vResult = XMVectorRound(vResult);
return FNMADD_COMPAT(vResult, g_XMTwoPi, Angles);
}
inline XMFLOAT2 sin(XMFLOAT2 p)
{
XMVECTOR P = XMLoadFloat2(&p);
//P = XMVectorSin(P);
{
// Force the value within the bounds of pi
XMVECTOR x = XMVectorModAngles_COMPAT(P);
// Map in [-pi/2,pi/2] with sin(y) = sin(x).
__m128 sign = _mm_and_ps(x, g_XMNegativeZero);
__m128 c = _mm_or_ps(g_XMPi, sign); // pi when x >= 0, -pi when x < 0
__m128 absx = _mm_andnot_ps(sign, x); // |x|
__m128 rflx = _mm_sub_ps(c, x);
__m128 comp = _mm_cmple_ps(absx, g_XMHalfPi);
__m128 select0 = _mm_and_ps(comp, x);
__m128 select1 = _mm_andnot_ps(comp, rflx);
x = _mm_or_ps(select0, select1);
__m128 x2 = _mm_mul_ps(x, x);
// Compute polynomial approximation
const XMVECTOR SC1 = g_XMSinCoefficients1;
__m128 vConstantsB = XM_PERMUTE_PS(SC1, _MM_SHUFFLE(0, 0, 0, 0));
const XMVECTOR SC0 = g_XMSinCoefficients0;
__m128 vConstants = XM_PERMUTE_PS(SC0, _MM_SHUFFLE(3, 3, 3, 3));
__m128 Result = FMADD_COMPAT(vConstantsB, x2, vConstants);
vConstants = XM_PERMUTE_PS(SC0, _MM_SHUFFLE(2, 2, 2, 2));
Result = FMADD_COMPAT(Result, x2, vConstants);
vConstants = XM_PERMUTE_PS(SC0, _MM_SHUFFLE(1, 1, 1, 1));
Result = FMADD_COMPAT(Result, x2, vConstants);
vConstants = XM_PERMUTE_PS(SC0, _MM_SHUFFLE(0, 0, 0, 0));
Result = FMADD_COMPAT(Result, x2, vConstants);
Result = FMADD_COMPAT(Result, x2, g_XMOne);
Result = _mm_mul_ps(Result, x);
P = Result;
}
XMFLOAT2 ret;
XMStoreFloat2(&ret, P);
return ret;
}
inline XMFLOAT2 hash(XMFLOAT2 p)
{
XMFLOAT2 ret = XMFLOAT2(
dot(XMFLOAT2(p.x, p.y), XMFLOAT2(127.1f, 311.7f)),
dot(XMFLOAT2(p.x, p.y), XMFLOAT2(269.5f, 183.3f))
);
ret = sin(ret);
return fract(XMFLOAT2(ret.x * 18.5453f, ret.y * 18.5453f));
}
struct Result
{
float distance;
float cell_id;
float distance = 0;
float cell_id = 0;
};
inline Result compute(float x, float y, float seed)
{
Result result = {};
Result result;
XMVECTOR p = XMVectorSet(x, y, 0, 0);
XMVECTOR n = XMVectorFloor(p);
XMVECTOR f = fract(p);
XMFLOAT2 p = XMFLOAT2(x, y);
XMFLOAT2 n = floor(p);
XMFLOAT2 f = fract(p);
XMVECTOR m = XMVectorSet(8, 0, 0, 0);
XMFLOAT3 m = XMFLOAT3(8, 0, 0);
for (int j = -1; j <= 1; j++)
{
for (int i = -1; i <= 1; i++)
{
XMVECTOR g = XMVectorSet(float(i), float(j), 0, 0);
XMVECTOR o = hash(n + g);
//XMVECTOR r = g - f + o;
XMVECTOR r = g - f + (XMVectorReplicate(0.5f) + 0.5f * XMVectorSin(seed * o));
float d = XMVectorGetX(XMVector2Dot(r, r));
if (d < XMVectorGetX(m))
XMFLOAT2 g = XMFLOAT2(float(i), float(j));
XMFLOAT2 o = hash(XMFLOAT2(n.x + g.x, n.y + g.y));
XMFLOAT2 r;
r.x = g.x - f.x + (0.5f + 0.5f * std::sin(seed * o.x));
r.y = g.y - f.y + (0.5f + 0.5f * std::sin(seed * o.y));
float d = dot(r, r);
if (d < m.x)
{
m = XMVectorSet(d, XMVectorGetX(o), XMVectorGetY(o), 0);
m = XMFLOAT3(d, o.x, o.y);
}
}
}
result.distance = XMVectorGetX(XMVectorSqrt(m));
result.cell_id = XMVectorGetY(m) + XMVectorGetZ(m);
result.distance = std::sqrt(m.x);
result.cell_id = m.y + m.z;
return result;
}
+4 -4
View File
@@ -22,9 +22,9 @@ namespace wi::random
// gives an uint in range [0, UINT64_MAX]
constexpr uint64_t next_uint()
{
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
state ^= state >> 12ull;
state ^= state << 25ull;
state ^= state >> 27ull;
return state * 0x2545F4914F6CDD1DULL;
}
// gives an uint64 in range [min, max]
@@ -76,7 +76,7 @@ namespace wi::random
uint32_t u;
float f;
} value = {};
value.u = 0x3f800000 | (uint32_t(next_uint()) >> 9);
value.u = 0x3f800000u | (uint32_t(next_uint()) >> 9);
return value.f - 1.0f;
}
// gives a float in range [min, max]
+8 -28
View File
@@ -498,26 +498,6 @@ namespace wi::terrain
{
scene->materials.Create(materialEntities[i]);
}
if (i < MATERIAL_COUNT && !scene->names.Contains(materialEntities[i]))
{
NameComponent& name = scene->names.Create(materialEntities[i]);
switch (i)
{
default:
case MATERIAL_BASE:
name = "material_base";
break;
case MATERIAL_SLOPE:
name = "material_slope";
break;
case MATERIAL_LOW_ALTITUDE:
name = "material_low_altitude";
break;
case MATERIAL_HIGH_ALTITUDE:
name = "material_high_altitude";
break;
}
}
*scene->materials.GetComponent(materialEntities[i]) = materials[i];
}
}
@@ -1189,9 +1169,9 @@ namespace wi::terrain
{
if (prop.data.empty())
continue;
const int gen_count = (int)rng.next_uint(
uint32_t(prop.min_count_per_chunk * chunk_data.prop_density_current),
std::max(1u, uint32_t(prop.max_count_per_chunk * chunk_data.prop_density_current))
const int gen_count = rng.next_int(
int(std::floor(float(prop.min_count_per_chunk) * chunk_data.prop_density_current)),
int(std::ceil(float(prop.max_count_per_chunk) * chunk_data.prop_density_current))
);
for (int i = 0; i < gen_count; ++i)
{
@@ -1205,6 +1185,9 @@ namespace wi::terrain
XMFLOAT4 region0 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind0], chunk_data.blendmap_layers[1].pixels[ind0], chunk_data.blendmap_layers[2].pixels[ind0], chunk_data.blendmap_layers[3].pixels[ind0]);
XMFLOAT4 region1 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind1], chunk_data.blendmap_layers[1].pixels[ind1], chunk_data.blendmap_layers[2].pixels[ind1], chunk_data.blendmap_layers[3].pixels[ind1]);
XMFLOAT4 region2 = wi::Color(chunk_data.blendmap_layers[0].pixels[ind2], chunk_data.blendmap_layers[1].pixels[ind2], chunk_data.blendmap_layers[2].pixels[ind2], chunk_data.blendmap_layers[3].pixels[ind2]);
weight_norm(region0);
weight_norm(region1);
weight_norm(region2);
float spline_factor0 = 0;
float spline_factor1 = 0;
float spline_factor2 = 0;
@@ -1221,9 +1204,6 @@ namespace wi::terrain
spline_factor1 *= rcp;
spline_factor2 *= rcp;
}
weight_norm(region0);
weight_norm(region1);
weight_norm(region2);
// random barycentric coords on the triangle:
float f = rng.next_float();
float g = rng.next_float();
@@ -2305,7 +2285,7 @@ namespace wi::terrain
{
std::shared_ptr<HeightmapModifier> modifier = std::make_shared<HeightmapModifier>();
modifiers[i] = modifier;
archive >> modifier->scale;
archive >> modifier->amount;
archive >> modifier->data;
archive >> modifier->width;
archive >> modifier->height;
@@ -2422,7 +2402,7 @@ namespace wi::terrain
((VoronoiModifier*)modifier.get())->perlin_noise.Serialize(archive);
break;
case Modifier::Type::Heightmap:
archive << ((HeightmapModifier*)modifier.get())->scale;
archive << ((HeightmapModifier*)modifier.get())->amount;
archive << ((HeightmapModifier*)modifier.get())->data;
archive << ((HeightmapModifier*)modifier.get())->width;
archive << ((HeightmapModifier*)modifier.get())->height;
+8 -4
View File
@@ -18,7 +18,7 @@ namespace wi::terrain
{
struct
{
int x, z;
int32_t x, z;
};
uint64_t raw = 0;
};
@@ -383,6 +383,10 @@ namespace wi::terrain
float weight = 0.5f;
float frequency = 0.0008f;
// helpers for more user friendly setup with scaling in world space:
constexpr void SetScale(float scale) { frequency = 1.0f / scale; }
constexpr float GetScale() const { return 1.0f / frequency; }
virtual void Seed(uint32_t seed) {}
virtual void Apply(const XMFLOAT2& world_pos, float& height) = 0;
constexpr void Blend(float& height, float value)
@@ -455,13 +459,13 @@ namespace wi::terrain
};
struct HeightmapModifier : public Modifier
{
float scale = 0.1f;
float amount = 0.1f; // multiplier for height values
wi::vector<uint8_t> data;
int width = 0;
int height = 0;
HeightmapModifier() { type = Type::Heightmap; }
HeightmapModifier() { type = Type::Heightmap; SetScale(1.0f); }
void Apply(const XMFLOAT2& world_pos, float& height) override
{
XMFLOAT2 p = world_pos;
@@ -480,7 +484,7 @@ namespace wi::terrain
{
value = ((float)((uint16_t*)data.data())[idx] / 65535.0f);
}
Blend(height, value * scale);
Blend(height, value * amount);
}
}
};
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 751;
const int revision = 752;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);