diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp index ea1222add..4ae39176f 100644 --- a/Editor/WeatherWindow.cpp +++ b/Editor/WeatherWindow.cpp @@ -68,23 +68,38 @@ WeatherWindow::WeatherWindow(wiGUI* gui) : GUI(gui) }); weatherWindow->AddWidget(cloudSpeedSlider); - windSpeedSlider = new wiSlider(0.001f, 0.2f, 0.1f, 10000, "Wind Speed: "); + windSpeedSlider = new wiSlider(0.0f, 0.2f, 0.0f, 10000, "Wind Speed: "); windSpeedSlider->SetSize(XMFLOAT2(100, 30)); windSpeedSlider->SetPos(XMFLOAT2(x, y += step)); + windSpeedSlider->OnSlide([&](wiEventArgs args) { + UpdateWind(); + }); weatherWindow->AddWidget(windSpeedSlider); windDirectionSlider = new wiSlider(0, 1, 0, 10000, "Wind Direction: "); windDirectionSlider->SetSize(XMFLOAT2(100, 30)); windDirectionSlider->SetPos(XMFLOAT2(x, y += step)); windDirectionSlider->OnSlide([&](wiEventArgs args) { - XMMATRIX rot = XMMatrixRotationY(args.fValue * XM_PI * 2); - XMVECTOR dir = XMVectorSet(1, 0, 0, 0); - dir = XMVector3TransformNormal(dir, rot); - dir *= windSpeedSlider->GetValue(); - XMStoreFloat3(&GetWeather().windDirection, dir); + UpdateWind(); }); weatherWindow->AddWidget(windDirectionSlider); + windWaveSizeSlider = new wiSlider(0, 1, 0, 10000, "Wind Wave Size: "); + windWaveSizeSlider->SetSize(XMFLOAT2(100, 30)); + windWaveSizeSlider->SetPos(XMFLOAT2(x, y += step)); + windWaveSizeSlider->OnSlide([&](wiEventArgs args) { + GetWeather().windWaveSize = args.fValue; + }); + weatherWindow->AddWidget(windWaveSizeSlider); + + windRandomnessSlider = new wiSlider(0, 1, 0, 10000, "Wind Randomness: "); + windRandomnessSlider->SetSize(XMFLOAT2(100, 30)); + windRandomnessSlider->SetPos(XMFLOAT2(x, y += step)); + windRandomnessSlider->OnSlide([&](wiEventArgs args) { + GetWeather().windRandomness = args.fValue; + }); + weatherWindow->AddWidget(windRandomnessSlider); + skyButton = new wiButton("Load Sky"); skyButton->SetTooltip("Load a skybox cubemap texture..."); @@ -508,3 +523,12 @@ void WeatherWindow::InvalidateProbes() const scene.probes[i].SetDirty(); } } + +void WeatherWindow::UpdateWind() +{ + XMMATRIX rot = XMMatrixRotationY(windDirectionSlider->GetValue() * XM_PI * 2); + XMVECTOR dir = XMVectorSet(1, 0, 0, 0); + dir = XMVector3TransformNormal(dir, rot); + dir *= windSpeedSlider->GetValue(); + XMStoreFloat3(&GetWeather().windDirection, dir); +} diff --git a/Editor/WeatherWindow.h b/Editor/WeatherWindow.h index d0a7b36b5..2d318061f 100644 --- a/Editor/WeatherWindow.h +++ b/Editor/WeatherWindow.h @@ -10,6 +10,7 @@ class wiButton; class WeatherWindow { + void UpdateWind(); public: WeatherWindow(wiGUI* gui); ~WeatherWindow(); @@ -30,6 +31,8 @@ public: wiSlider* cloudSpeedSlider; wiSlider* windSpeedSlider; wiSlider* windDirectionSlider; + wiSlider* windWaveSizeSlider; + wiSlider* windRandomnessSlider; wiButton* skyButton; wiColorPicker* ambientColorPicker; wiColorPicker* horizonColorPicker; diff --git a/WickedEngine/hairparticleVS.hlsl b/WickedEngine/hairparticleVS.hlsl index 28401ad1c..f8dac2141 100644 --- a/WickedEngine/hairparticleVS.hlsl +++ b/WickedEngine/hairparticleVS.hlsl @@ -76,8 +76,9 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID) patchPos.xyz *= frame.xyx * 0.5f; // simplistic wind effect only affects the top, but leaves the base as is: - float3 wind = sin(g_xFrame_Time + (position.x + position.y + position.z)) * g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; - float3 windPrev = sin(g_xFrame_TimePrev + (position.x + position.y + position.z)) * g_xFrame_WindDirection.xyz * patchPos.y * 0.03f; + const float3 posrand = (position.x + position.y + position.z) * g_xFrame_WindRandomness; + float3 wind = sin(g_xFrame_Time * (1 + g_xFrame_WindWaveSize) + posrand) * g_xFrame_WindDirection * patchPos.y; + float3 windPrev = sin(g_xFrame_TimePrev * (1 + g_xFrame_WindWaveSize) + posrand) * g_xFrame_WindDirection * patchPos.y; // rotate the patch into the tangent space of the emitting triangle: float3x3 TBN = float3x3(tangent, normal, binormal); // don't derive binormal, because we want the shear! diff --git a/WickedEngine/hairparticle_simulateCS.hlsl b/WickedEngine/hairparticle_simulateCS.hlsl index cf2172200..b311c1ada 100644 --- a/WickedEngine/hairparticle_simulateCS.hlsl +++ b/WickedEngine/hairparticle_simulateCS.hlsl @@ -17,7 +17,16 @@ struct LDS_ForceField float range_rcp; float3 normal; }; -groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS]; +groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS]; + +// https://www.shadertoy.com/view/llGSzw +float hash1(uint n) +{ + // integer hash copied from Hugo Elias + n = (n << 13U) ^ n; + n = n * (n * n * 15731U + 789221U) + 1376312589U; + return float(n & 0x7fffffffU) / float(0x7fffffff); +} [numthreads(THREADCOUNT_SIMULATEHAIR, 1, 1)] void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) @@ -35,14 +44,16 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn forceFields[groupIndex].range_rcp = forceField.range; // it is actually uploaded from CPU as 1.0f / range forceFields[groupIndex].normal = forceField.directionWS; } + GroupMemoryBarrierWithGroupSync(); + if (DTid.x >= xHairParticleCount) + return; // Generate patch: - float2 uv = float2((Gid.x + 1.0f) / (float)xHairNumDispatchGroups, (DTid.x + 1.0f) / (float)THREADCOUNT_SIMULATEHAIR); - float seed = xHairRandomSeed; // random triangle on emitter surface: - uint tri = (uint)((xHairBaseMeshIndexCount / 3) * rand(seed, uv)); + // (Note that the usual rand() function is not used because that introduces unnatural clustering with high triangle count) + uint tri = (uint)((xHairBaseMeshIndexCount / 3) * hash1(DTid.x)); // load indices of triangle from index buffer uint i0 = meshIndexBuffer[tri * 3 + 0]; @@ -61,6 +72,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn float length2 = meshVertexBuffer_length[i2]; // random barycentric coords: + float2 uv = hammersley2d(DTid.x, xHairStrandCount); + float seed = xHairRandomSeed; float f = rand(seed, uv); float g = rand(seed, uv); [flatten] @@ -95,10 +108,10 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn // Transform particle by the emitter object matrix: float3 base = mul(xWorld, float4(position.xyz, 1)).xyz; target = normalize(mul((float3x3)xWorld, target)); + const float3 root = base; float3 normal = 0; - GroupMemoryBarrierWithGroupSync(); for (uint segmentID = 0; segmentID < xHairSegmentCount; ++segmentID) { // Identifies the hair strand segment particle: diff --git a/WickedEngine/objectHF.hlsli b/WickedEngine/objectHF.hlsli index b60fc5cad..979882e9f 100644 --- a/WickedEngine/objectHF.hlsli +++ b/WickedEngine/objectHF.hlsli @@ -753,7 +753,6 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) #ifndef SIMPLE_INPUT float3 bumpColor = 0; - float opacity = color.a; float depth = input.pos.z; #ifndef ENVMAPRENDERING input.pos2D.xy /= input.pos2D.w; @@ -900,9 +899,6 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) #endif // ENVMAPRENDERING #endif // WATER - ApplyLighting(surface, lighting, color); - - #ifdef WATER // REFRACTION const float lineardepth = input.pos2D.w; @@ -911,9 +907,10 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) const float3 refractiveColor = texture_refraction.SampleLevel(sampler_linear_mirror, ScreenCoord.xy + bumpColor.rg * saturate(0.5 * depth_difference), 0).rgb; // WATER FOG - color.rgb = lerp(refractiveColor, color.rgb, saturate(surface.baseColor.a * 0.1f * depth_difference)); + surface.albedo = lerp(refractiveColor, color.rgb, saturate(surface.baseColor.a * 0.1f * depth_difference)); #endif // WATER + ApplyLighting(surface, lighting, color); ApplyFog(dist, color); diff --git a/WickedEngine/oceanSurfacePS.hlsl b/WickedEngine/oceanSurfacePS.hlsl index b6712c2fd..02bf0770b 100644 --- a/WickedEngine/oceanSurfacePS.hlsl +++ b/WickedEngine/oceanSurfacePS.hlsl @@ -37,8 +37,6 @@ float4 main(PSIn input) : SV_TARGET TiledLighting(pixel, surface, lighting); - ApplyLighting(surface, lighting, color); - // REFRACTION const float lineardepth = input.pos2D.w; const float sampled_lineardepth = texture_lineardepth.SampleLevel(sampler_point_clamp, ScreenCoord.xy + surface.N.xz * 0.04f, 0) * g_xCamera_ZFarP; @@ -46,7 +44,9 @@ float4 main(PSIn input) : SV_TARGET const float3 refractiveColor = texture_refraction.SampleLevel(sampler_linear_mirror, ScreenCoord.xy + surface.N.xz * 0.04f * saturate(0.5 * depth_difference), 0).rgb; // WATER FOG - color.rgb = lerp(refractiveColor, color.rgb, saturate(0.1f * depth_difference)); + surface.albedo = lerp(refractiveColor, color.rgb, saturate(0.1f * depth_difference)); + + ApplyLighting(surface, lighting, color); ApplyFog(dist, color); diff --git a/WickedEngine/wiHairParticle.cpp b/WickedEngine/wiHairParticle.cpp index 3647f1dc7..24555d612 100644 --- a/WickedEngine/wiHairParticle.cpp +++ b/WickedEngine/wiHairParticle.cpp @@ -168,7 +168,7 @@ void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponen hcb.xHairBaseMeshIndexCount = (indices.empty() ? (uint)mesh.indices.size() : (uint)indices.size()); hcb.xHairBaseMeshVertexPositionStride = sizeof(MeshComponent::Vertex_POS); // segmentCount will be loop in the shader, not a threadgroup so we don't need it here: - hcb.xHairNumDispatchGroups = (uint)ceilf((float)strandCount / (float)THREADCOUNT_SIMULATEHAIR); + hcb.xHairNumDispatchGroups = (hcb.xHairParticleCount + THREADCOUNT_SIMULATEHAIR - 1) / THREADCOUNT_SIMULATEHAIR; device->UpdateBuffer(&cb, &hcb, cmd); device->BindConstantBuffer(CS, &cb, CB_GETBINDSLOT(HairParticleCB), cmd); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 1e95dcbc6..28469f5f3 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 39; // minor bug fixes, alterations, refactors, updates - const int revision = 34; + const int revision = 35; long GetVersion() diff --git a/models/playground.wiscene b/models/playground.wiscene index 57f952ea9..d0281fc2e 100644 Binary files a/models/playground.wiscene and b/models/playground.wiscene differ