diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp
index cb884004a..6ae9f2ad6 100644
--- a/Editor/EmitterWindow.cpp
+++ b/Editor/EmitterWindow.cpp
@@ -83,7 +83,7 @@ EmitterWindow::EmitterWindow(wiGUI* gui) : GUI(gui)
emitCountSlider->SetTooltip("Set the number of particles to emit per second.");
emitterWindow->AddWidget(emitCountSlider);
- emitSizeSlider = new wiSlider(0.01f, 1000.0f, 1.0f, 100000, "Size: ");
+ emitSizeSlider = new wiSlider(0.01f, 10.0f, 1.0f, 100000, "Size: ");
emitSizeSlider->SetSize(XMFLOAT2(200, 30));
emitSizeSlider->SetPos(XMFLOAT2(x, y += step));
emitSizeSlider->OnSlide([&](wiEventArgs args) {
diff --git a/Editor/ForceFieldWindow.cpp b/Editor/ForceFieldWindow.cpp
index 4d23a3a3c..acbb64987 100644
--- a/Editor/ForceFieldWindow.cpp
+++ b/Editor/ForceFieldWindow.cpp
@@ -48,7 +48,7 @@ ForceFieldWindow::ForceFieldWindow(wiGUI* gui) : GUI(gui)
forceFieldWindow->AddWidget(typeComboBox);
- gravitySlider = new wiSlider(-0.01f, 0.01f, 0, 100000, "Gravity: ");
+ gravitySlider = new wiSlider(-10, 10, 0, 100000, "Gravity: ");
gravitySlider->SetSize(XMFLOAT2(200, 30));
gravitySlider->SetPos(XMFLOAT2(x, y += step));
gravitySlider->OnSlide([&](wiEventArgs args) {
@@ -62,7 +62,7 @@ ForceFieldWindow::ForceFieldWindow(wiGUI* gui) : GUI(gui)
forceFieldWindow->AddWidget(gravitySlider);
- rangeSlider = new wiSlider(0.0f, 1000.0f, 10, 100000, "Range: ");
+ rangeSlider = new wiSlider(0.0f, 100.0f, 10, 100000, "Range: ");
rangeSlider->SetSize(XMFLOAT2(200, 30));
rangeSlider->SetPos(XMFLOAT2(x, y += step));
rangeSlider->OnSlide([&](wiEventArgs args) {
diff --git a/Editor/config.ini b/Editor/config.ini
index db7591a73..fcbe7ab01 100644
--- a/Editor/config.ini
+++ b/Editor/config.ini
@@ -1,7 +1,7 @@
enabled 1
x 0
y 0
-w 1920
-h 1080
+w 3840
+h 2160
fullscreen 0
borderless 1
\ No newline at end of file
diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
index 09b98f95b..05df703ca 100644
--- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
+++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
@@ -612,16 +612,16 @@
CS
-
+
CS
-
+
CS
CS
-
+
CS
diff --git a/WickedEngine/emittedparticle_simulateCS.hlsl b/WickedEngine/emittedparticle_simulateCS.hlsl
index dd57749d0..988ac924c 100644
--- a/WickedEngine/emittedparticle_simulateCS.hlsl
+++ b/WickedEngine/emittedparticle_simulateCS.hlsl
@@ -13,15 +13,23 @@ struct LDS_ForceField
uint type;
float3 position;
float gravity;
- float range;
+ float range_inverse;
+ float3 normal;
};
groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS];
+groupshared uint aliveParticleCount = 0;
[numthreads(THREADCOUNT_SIMULATION, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
{
- // First, load the forcefields to LDS:
+ // Read alive particle count and store in LDS:
+ if (Gid == 0)
+ {
+ aliveParticleCount = counterBuffer[0][0];
+ }
+
+ // Load the forcefields into LDS:
uint numForceFields = min(g_xFrame_ForceFieldCount, NUM_LDS_FORCEFIELDS);
if (Gid < numForceFields)
{
@@ -31,17 +39,15 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
forceFields[Gid].type = (uint)forceField.type;
forceFields[Gid].position = forceField.positionWS;
forceFields[Gid].gravity = forceField.energy;
- forceFields[Gid].range = max(0.001f, forceField.range);
+ forceFields[Gid].range_inverse = forceField.range;
+ forceFields[Gid].normal = forceField.directionWS;
}
GroupMemoryBarrierWithGroupSync();
-
- uint aliveCount = counterBuffer[0][0];
-
- if (DTid.x < aliveCount)
+ if (DTid.x < aliveParticleCount)
{
- uint dt = g_xFrame_DeltaTime * 60.0f;
+ const float dt = g_xFrame_DeltaTime;
uint particleIndex = aliveBuffer_OLD[DTid.x];
Particle particle = particleBuffer[particleIndex];
@@ -54,9 +60,19 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
{
LDS_ForceField forceField = forceFields[i];
- float3 diff = forceField.position - particle.position;
- float dist = length(diff);
- float3 force = diff * forceField.gravity * (1 - saturate(dist / forceField.range));
+ float3 dir = forceField.position - particle.position;
+ float dist;
+ if (forceField.type == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
+ {
+ dist = length(dir);
+ }
+ else // planar force field
+ {
+ dist = dot(forceField.normal, dir);
+ dir = forceField.normal;
+ }
+
+ float3 force = dir * forceField.gravity * (1 - saturate(dist * forceField.range_inverse));
particle.velocity += force * dt;
}
diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp
index e0278127a..1f76b4f6a 100644
--- a/WickedEngine/wiEmittedParticle.cpp
+++ b/WickedEngine/wiEmittedParticle.cpp
@@ -221,9 +221,9 @@ void wiEmittedParticle::UpdateRenderData(GRAPHICSTHREAD threadID)
cb.xEmitterMeshVertexNormalStride = sizeof(Mesh::Vertex_NOR);
cb.xEmitterRandomness = wiRandom::getRandom(0, 1000) * 0.001f;
cb.xEmitCount = (UINT)emit;
- cb.xParticleLifeSpan = life;
+ cb.xParticleLifeSpan = life / 60.0f;
cb.xParticleLifeSpanRandomness = random_life;
- cb.xParticleNormalFactor = normal_factor / 60.0f;
+ cb.xParticleNormalFactor = normal_factor;
cb.xParticleRandomFactor = random_factor;
cb.xParticleScaling = scaleX;
cb.xParticleSize = size;
diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp
index fae0b3c56..38a7114ad 100644
--- a/WickedEngine/wiRenderer.cpp
+++ b/WickedEngine/wiRenderer.cpp
@@ -2104,9 +2104,10 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
entityArray[entityCounter].type = force->type;
entityArray[entityCounter].positionWS = force->translation;
- XMStoreFloat3(&entityArray[entityCounter].directionWS, XMVector3TransformNormal(XMVectorSet(0, 1, 0, 0), XMLoadFloat4x4(&force->world)));
entityArray[entityCounter].energy = force->gravity;
- entityArray[entityCounter].range = force->range;
+ entityArray[entityCounter].range = 1.0f / max(0.0001f, force->range); // avoid division in shader
+ // The default planar force field is facing upwards, and thus the pull direction is downwards:
+ XMStoreFloat3(&entityArray[entityCounter].directionWS, XMVector3Normalize(XMVector3TransformNormal(XMVectorSet(0, -1, 0, 0), XMLoadFloat4x4(&force->world))));
entityCounter++;
}
diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp
index dcf18045d..363074fab 100644
--- a/WickedEngine/wiVersion.cpp
+++ b/WickedEngine/wiVersion.cpp
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 13;
// minor bug fixes, alterations, refactors, updates
- const int revision = 67;
+ const int revision = 68;
long GetVersion()
diff --git a/features.txt b/features.txt
index d8c69bca4..e1f9e147f 100644
--- a/features.txt
+++ b/features.txt
@@ -69,3 +69,4 @@ Real time Voxel Cone traced reflections
Temporal Antialiasing
Tiled deferred rendering
Huge draw distance support with reversed Z-buffer
+Force Fields GPU simulation
diff --git a/models/Emitter/profiling_10_30_9_49_12.csv b/models/Emitter/profiling_10_30_9_49_12.csv
new file mode 100644
index 000000000..f8a9400da
--- /dev/null
+++ b/models/Emitter/profiling_10_30_9_49_12.csv
@@ -0,0 +1,136 @@
+HUD frame time nsec:,16670000
+
+Range Index,Elapsed Time, First Event,Last Event
+0,11552,302,302
+1,26464,304,304
+2,6752,306,306
+3,13312,308,308
+4,6752,310,310
+5,8544,327,327
+6,26720,329,329
+7,13568,331,331
+8,14080,333,333
+9,10880,335,335
+10,8032,352,352
+11,23808,354,354
+12,6976,356,356
+13,15264,358,358
+14,6624,360,360
+15,21760,384,384
+16,21312,389,389
+17,21312,394,394
+18,36928,433,433
+19,47008,466,466
+20,63712,499,499
+21,394240,559,559
+22,925120,584,584
+23,10289696,609,609
+24,1822656,651,651
+25,469856,682,682
+26,565760,703,703
+27,26624,717,717
+28,26592,731,731
+29,1583776,751,751
+30,2679520,838,838
+31,5802240,853,853
+32,6654112,873,873
+33,416768,890,890
+34,641024,906,906
+35,1735904,920,920
+36,3130688,937,937
+37,3904352,953,953
+38,3941088,983,983
+39,3938144,997,997
+40,3938080,1014,1014
+41,3933120,1017,1017
+42,3933280,1034,1034
+43,3933120,1037,1037
+44,3933056,1054,1054
+45,3933152,1057,1057
+46,3936288,1071,1071
+47,3936128,1089,1089
+48,3936032,1092,1092
+49,3936064,1106,1106
+50,3935520,1124,1124
+51,3935488,1127,1127
+52,3935360,1141,1141
+53,3935264,1159,1159
+54,3935360,1162,1162
+55,3936064,1176,1176
+56,3936064,1194,1194
+57,3935136,1197,1197
+58,3934688,1211,1211
+59,3934848,1229,1229
+60,3934784,1232,1232
+61,3935456,1246,1246
+62,3935584,1264,1264
+63,3932416,1267,1267
+64,3933152,1281,1281
+65,3932384,1299,1299
+66,3932224,1302,1302
+67,3933984,1316,1316
+68,3934176,1334,1334
+69,3933056,1337,1337
+70,3932480,1351,1351
+71,3932480,1369,1369
+72,3932544,1372,1372
+73,3933664,1386,1386
+74,3933760,1404,1404
+75,3933536,1407,1407
+76,3934432,1421,1421
+77,3934496,1439,1439
+78,3932864,1442,1442
+79,3937216,1456,1456
+80,3937248,1474,1474
+81,3936160,1477,1477
+82,3936160,1491,1491
+83,3936096,1509,1509
+84,3935936,1512,1512
+85,3935872,1526,1526
+86,3935264,1543,1543
+87,3935168,1546,1546
+88,3935072,1560,1560
+89,3935072,1577,1577
+90,3935008,1580,1580
+91,3935008,1594,1594
+92,3934976,1611,1611
+93,3934464,1614,1614
+94,3934432,1628,1628
+95,3934432,1642,1642
+96,3934208,1659,1659
+97,3934176,1662,1662
+98,3934144,1676,1676
+99,3934112,1694,1694
+100,3932416,1697,1697
+101,3934080,1711,1711
+102,3934240,1729,1729
+103,3934272,1732,1732
+104,3935328,1746,1746
+105,3935392,1764,1764
+106,3935072,1767,1767
+107,3933696,1781,1781
+108,3933792,1799,1799
+109,3933792,1802,1802
+110,3934816,1816,1816
+111,3951552,1834,1834
+112,3951008,1837,1837
+113,3951840,1851,1851
+114,3951968,1869,1869
+115,3952000,1872,1872
+116,3952480,1886,1886
+117,3951104,1904,1904
+118,3950304,1907,1907
+119,3950464,1921,1921
+120,3950336,1939,1939
+121,3950304,1942,1942
+122,3950624,1956,1956
+123,3950592,1974,1974
+124,3950560,1977,1977
+125,5083744,1996,1996
+126,6175968,2009,2009
+127,6180064,2023,2023
+128,6183200,2037,2037
+129,6182624,2054,2054
+130,6182848,2057,2057
+131,6188480,2074,2074
+132,6199360,2077,2077
diff --git a/models/Emitter/temp/history0 b/models/Emitter/temp/history0
new file mode 100644
index 000000000..38166fc9e
Binary files /dev/null and b/models/Emitter/temp/history0 differ
diff --git a/models/Emitter/temp/history1 b/models/Emitter/temp/history1
new file mode 100644
index 000000000..f487f8fbe
Binary files /dev/null and b/models/Emitter/temp/history1 differ
diff --git a/models/Emitter/temp/history2 b/models/Emitter/temp/history2
new file mode 100644
index 000000000..06052b687
Binary files /dev/null and b/models/Emitter/temp/history2 differ