Terrain determinism fixes (#1096)
This commit is contained in:
+89
-68
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user