diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj b/WickedEngine/WickedEngine_SHADERS.vcxproj
index 1f2420671..2ebf374b8 100644
--- a/WickedEngine/WickedEngine_SHADERS.vcxproj
+++ b/WickedEngine/WickedEngine_SHADERS.vcxproj
@@ -316,9 +316,15 @@
Compute
5.0
+
+ Pixel
+
Pixel
+
+ Pixel
+
Compute
5.0
diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
index 469e02be9..9048309ed 100644
--- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
+++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters
@@ -810,6 +810,12 @@
CS
+
+ PS
+
+
+ PS
+
diff --git a/WickedEngine/hairparticlePS_alphatestonly.hlsl b/WickedEngine/hairparticlePS_alphatestonly.hlsl
index 68706bf85..73fe13df9 100644
--- a/WickedEngine/hairparticlePS_alphatestonly.hlsl
+++ b/WickedEngine/hairparticlePS_alphatestonly.hlsl
@@ -3,7 +3,7 @@
void main(VertexToPixel input)
{
- clip(dither(input.pos.xy) - input.fade);
+ clip(dither(input.pos.xy + GetTemporalAASampleRotation()) - input.fade);
float4 color = texture_0.Sample(sampler_linear_clamp,input.tex);
ALPHATEST(color.a)
diff --git a/WickedEngine/hairparticlePS_deferred.hlsl b/WickedEngine/hairparticlePS_deferred.hlsl
index 8d88e01b2..6fe2040a3 100644
--- a/WickedEngine/hairparticlePS_deferred.hlsl
+++ b/WickedEngine/hairparticlePS_deferred.hlsl
@@ -4,7 +4,7 @@
GBUFFEROutputType main(VertexToPixel input)
{
- clip(dither(input.pos.xy) - input.fade);
+ clip(dither(input.pos.xy + GetTemporalAASampleRotation()) - input.fade);
float4 color = texture_0.Sample(sampler_linear_clamp, input.tex);
color.rgb = DEGAMMA(color.rgb);
diff --git a/WickedEngine/hairparticlePS_forward.hlsl b/WickedEngine/hairparticlePS_forward.hlsl
index c2e10fe8f..931ada915 100644
--- a/WickedEngine/hairparticlePS_forward.hlsl
+++ b/WickedEngine/hairparticlePS_forward.hlsl
@@ -2,12 +2,18 @@
#include "objectHF.hlsli"
#include "hairparticleHF.hlsli"
+#ifndef TRANSPARENT
+[earlydepthstencil]
+#endif // TRANSPARENT
GBUFFEROutputType_Thin main(VertexToPixel input)
{
float4 color = texture_0.Sample(sampler_linear_clamp, input.tex);
color.rgb = DEGAMMA(color.rgb);
color.rgb *= input.color;
- ALPHATEST(color.a)
+#ifdef TRANSPARENT
+ color.a *= 1.0 - input.fade;
+ clip(color.a - 1.0f / 255.0f); // cancel heaviest overdraw for the alpha composition effect
+#endif // TRANSPARENT
float opacity = 1; // keep edge diffuse shading
float3 V = g_xCamera_CamPos - input.pos3D;
float dist = length(V);
diff --git a/WickedEngine/hairparticlePS_forward_transparent.hlsl b/WickedEngine/hairparticlePS_forward_transparent.hlsl
new file mode 100644
index 000000000..caa0a1bca
--- /dev/null
+++ b/WickedEngine/hairparticlePS_forward_transparent.hlsl
@@ -0,0 +1,2 @@
+#define TRANSPARENT
+#include "hairparticlePS_forward.hlsl"
diff --git a/WickedEngine/hairparticlePS_tiledforward.hlsl b/WickedEngine/hairparticlePS_tiledforward.hlsl
index 2e9642d3f..012d8024f 100644
--- a/WickedEngine/hairparticlePS_tiledforward.hlsl
+++ b/WickedEngine/hairparticlePS_tiledforward.hlsl
@@ -4,14 +4,18 @@
#include "objectHF.hlsli"
#include "hairparticleHF.hlsli"
+#ifndef TRANSPARENT
[earlydepthstencil]
+#endif // TRANSPARENT
GBUFFEROutputType_Thin main(VertexToPixel input)
{
float4 color = texture_0.Sample(sampler_linear_wrap, input.tex);
color.rgb = DEGAMMA(color.rgb);
color.rgb *= input.color;
+#ifdef TRANSPARENT
color.a *= 1.0 - input.fade;
clip(color.a - 1.0f / 255.0f); // cancel heaviest overdraw for the alpha composition effect
+#endif // TRANSPARENT
float opacity = 1;
float3 V = g_xCamera_CamPos - input.pos3D;
float dist = length(V);
diff --git a/WickedEngine/hairparticlePS_tiledforward_transparent.hlsl b/WickedEngine/hairparticlePS_tiledforward_transparent.hlsl
new file mode 100644
index 000000000..0e14af4b7
--- /dev/null
+++ b/WickedEngine/hairparticlePS_tiledforward_transparent.hlsl
@@ -0,0 +1,2 @@
+#define TRANSPARENT
+#include "hairparticlePS_tiledforward.hlsl"
diff --git a/WickedEngine/hairparticleVS.hlsl b/WickedEngine/hairparticleVS.hlsl
index dafd6787c..9cdc32d16 100644
--- a/WickedEngine/hairparticleVS.hlsl
+++ b/WickedEngine/hairparticleVS.hlsl
@@ -2,8 +2,6 @@
#include "hairparticleHF.hlsli"
#include "ShaderInterop_HairParticle.h"
-static const float hairPopDistanceThreshold = 0.9f;
-
// billboard cross section:
static const float3 HAIRPATCH[] = {
float3(-1, -1, 0),
@@ -32,75 +30,84 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID)
const uint segmentID = (fakeIndex / 12) % xHairSegmentCount;
const uint particleID = fakeIndex / 12;
- // convert the raw loaded particle data:
float3 position = particleBuffer[particleID].position;
- uint tangent_random = particleBuffer[particleID].tangent_random;
- float3 normal = particleBuffer[particleID].normal;
- uint binormal_length = particleBuffer[particleID].binormal_length;
+ Out.fade = saturate(distance(position.xyz, g_xCamera_CamPos.xyz) / xHairViewDistance);
+ Out.fade = saturate(Out.fade - 0.8f) * 5.0f; // fade will be on edge and inwards 20%
- float3 tangent;
- tangent.x = (tangent_random >> 0) & 0x000000FF;
- tangent.y = (tangent_random >> 8) & 0x000000FF;
- tangent.z = (tangent_random >> 16) & 0x000000FF;
- tangent = tangent / 255.0f * 2 - 1;
+ [branch]
+ if (Out.fade < 1.0 - 1.0f / 255.0f)
+ {
+ uint tangent_random = particleBuffer[particleID].tangent_random;
+ float3 normal = particleBuffer[particleID].normal;
+ uint binormal_length = particleBuffer[particleID].binormal_length;
- uint rand = (tangent_random >> 24) & 0x000000FF;
+ float3 tangent;
+ tangent.x = (tangent_random >> 0) & 0x000000FF;
+ tangent.y = (tangent_random >> 8) & 0x000000FF;
+ tangent.z = (tangent_random >> 16) & 0x000000FF;
+ tangent = tangent / 255.0f * 2 - 1;
- float3 binormal;
- binormal.x = (binormal_length >> 0) & 0x000000FF;
- binormal.y = (binormal_length >> 8) & 0x000000FF;
- binormal.z = (binormal_length >> 16) & 0x000000FF;
- binormal = binormal / 255.0f * 2 - 1;
+ uint rand = (tangent_random >> 24) & 0x000000FF;
- float len = (binormal_length >> 24) & 0x000000FF;
- len /= 255.0f;
- len += 1;
- len *= xLength;
+ float3 binormal;
+ binormal.x = (binormal_length >> 0) & 0x000000FF;
+ binormal.y = (binormal_length >> 8) & 0x000000FF;
+ binormal.z = (binormal_length >> 16) & 0x000000FF;
+ binormal = binormal / 255.0f * 2 - 1;
- // expand the particle into a billboard cross section, the patch:
- float3 patchPos = HAIRPATCH[vertexID];
- float2 uv = vertexID < 6 ? patchPos.xy : patchPos.zy;
- uv = uv * float2(0.5f, 0.5f) + 0.5f;
- uv.y = lerp((float)segmentID / (float)xHairSegmentCount, ((float)segmentID + 1) / (float)xHairSegmentCount, uv.y);
- uv.y = 1 - uv.y;
- uv.x = rand % 2 == 0 ? uv.x : 1 - uv.x;
- patchPos.y += 1;
+ float len = (binormal_length >> 24) & 0x000000FF;
+ len /= 255.0f;
+ len += 1;
+ len *= xLength;
- // scale the billboard by the texture aspect:
- float2 frame;
- texture_0.GetDimensions(frame.x, frame.y);
- frame.xy /= frame.y;
- frame.xy *= len;
- patchPos.xyz *= frame.xyx * 0.5f;
+ // expand the particle into a billboard cross section, the patch:
+ float3 patchPos = HAIRPATCH[vertexID];
+ float2 uv = vertexID < 6 ? patchPos.xy : patchPos.zy;
+ uv = uv * float2(0.5f, 0.5f) + 0.5f;
+ uv.y = lerp((float)segmentID / (float)xHairSegmentCount, ((float)segmentID + 1) / (float)xHairSegmentCount, uv.y);
+ uv.y = 1 - uv.y;
+ uv.x = rand % 2 == 0 ? uv.x : 1 - uv.x;
+ patchPos.y += 1;
- // 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;
+ // scale the billboard by the texture aspect:
+ float2 frame;
+ texture_0.GetDimensions(frame.x, frame.y);
+ frame.xy /= frame.y;
+ frame.xy *= len;
+ patchPos.xyz *= frame.xyx * 0.5f;
- // 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!
- patchPos = mul(patchPos, TBN);
+ // 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;
- // inset to the emitter a bit, to avoid disconnect:
- position.xyz -= normal * 0.1 * len;
+ // 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!
+ patchPos = mul(patchPos, TBN);
+
+ // inset to the emitter a bit, to avoid disconnect:
+ position.xyz -= normal * 0.1 * len;
- // copy to output:
- Out.pos = float4(position, 1);
- Out.pos.xyz += patchPos;
- float3 savedPos = Out.pos.xyz;
- Out.pos.xyz += wind;
- Out.pos3D = Out.pos.xyz;
- Out.pos = mul(g_xCamera_VP, Out.pos);
+ // copy to output:
+ Out.pos = float4(position, 1);
+ Out.pos.xyz += patchPos;
+ float3 savedPos = Out.pos.xyz;
+ Out.pos.xyz += wind;
+ Out.pos3D = Out.pos.xyz;
+ Out.pos = mul(g_xCamera_VP, Out.pos);
- Out.nor = normal;
- Out.tex = uv;
-
- Out.fade = pow(saturate(distance(position.xyz, g_xCamera_CamPos.xyz) / (xHairViewDistance*hairPopDistanceThreshold)), 10);
- Out.pos2D = Out.pos;
- Out.pos2DPrev = mul(g_xFrame_MainCamera_PrevVP, float4(savedPos + windPrev, 1));
+ Out.nor = normal;
+ Out.tex = uv;
- Out.color = xColor.rgb;
+ Out.pos2D = Out.pos;
+ Out.pos2DPrev = mul(g_xFrame_MainCamera_PrevVP, float4(savedPos + windPrev, 1));
+
+ Out.color = xColor.rgb;
+ }
+ else
+ {
+ Out = (VertexToPixel)0;
+ }
return Out;
}
diff --git a/WickedEngine/wiHairParticle.cpp b/WickedEngine/wiHairParticle.cpp
index f1896402d..3cf67c348 100644
--- a/WickedEngine/wiHairParticle.cpp
+++ b/WickedEngine/wiHairParticle.cpp
@@ -19,7 +19,12 @@ namespace wiSceneSystem
{
static const VertexShader *vs = nullptr;
-static const PixelShader *ps[RENDERPASS_COUNT] = {};
+static const PixelShader* ps_alphatestonly = nullptr;
+static const PixelShader* ps_deferred = nullptr;
+static const PixelShader* ps_forward = nullptr;
+static const PixelShader* ps_forward_transparent = nullptr;
+static const PixelShader* ps_tiledforward = nullptr;
+static const PixelShader* ps_tiledforward_transparent = nullptr;
static const PixelShader *ps_simplest = nullptr;
static const ComputeShader *cs_simulate = nullptr;
static DepthStencilState dss_default, dss_equal, dss_rejectopaque_keeptransparent;
@@ -213,68 +218,91 @@ void wiHairParticle::LoadShaders()
vs = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticleVS.cso", wiResourceManager::VERTEXSHADER));
- ps[RENDERPASS_DEPTHONLY] = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_alphatestonly.cso", wiResourceManager::PIXELSHADER));
- ps[RENDERPASS_DEFERRED] = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_deferred.cso", wiResourceManager::PIXELSHADER));
- ps[RENDERPASS_FORWARD] = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_forward.cso", wiResourceManager::PIXELSHADER));
- ps[RENDERPASS_TILEDFORWARD] = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_tiledforward.cso", wiResourceManager::PIXELSHADER));
+ ps_alphatestonly = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_alphatestonly.cso", wiResourceManager::PIXELSHADER));
+ ps_deferred = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_deferred.cso", wiResourceManager::PIXELSHADER));
+ ps_forward = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_forward.cso", wiResourceManager::PIXELSHADER));
+ ps_forward_transparent = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_forward_transparent.cso", wiResourceManager::PIXELSHADER));
+ ps_tiledforward = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_tiledforward.cso", wiResourceManager::PIXELSHADER));
+ ps_tiledforward_transparent = static_cast(wiResourceManager::GetShaderManager().add(path + "hairparticlePS_tiledforward_transparent.cso", wiResourceManager::PIXELSHADER));
GraphicsDevice* device = wiRenderer::GetDevice();
for (int i = 0; i < RENDERPASS_COUNT; ++i)
{
- if (ps[i] == nullptr)
+ if (i == RENDERPASS_DEPTHONLY || i == RENDERPASS_DEFERRED || i == RENDERPASS_FORWARD || i == RENDERPASS_TILEDFORWARD)
{
- continue;
- }
-
- for (int j = 0; j < 2; ++j)
- {
- if ((i == RENDERPASS_DEPTHONLY || i == RENDERPASS_DEFERRED) && j == 1)
+ for (int j = 0; j < 2; ++j)
{
- continue;
+ if ((i == RENDERPASS_DEPTHONLY || i == RENDERPASS_DEFERRED) && j == 1)
+ {
+ continue;
+ }
+
+ PipelineStateDesc desc;
+ desc.vs = vs;
+ desc.bs = &bs[j];
+ desc.rs = &ncrs;
+ desc.dss = &dss_default;
+
+ desc.DSFormat = wiRenderer::DSFormat_full;
+
+ switch (i)
+ {
+ case RENDERPASS_DEPTHONLY:
+ desc.ps = ps_alphatestonly;
+ break;
+ case RENDERPASS_DEFERRED:
+ desc.ps = ps_deferred;
+ break;
+ case RENDERPASS_FORWARD:
+ if (j == 0)
+ {
+ desc.ps = ps_forward;
+ }
+ else
+ {
+ desc.ps = ps_forward_transparent;
+ }
+ break;
+ case RENDERPASS_TILEDFORWARD:
+ if (j == 0)
+ {
+ desc.ps = ps_tiledforward;
+ }
+ else
+ {
+ desc.ps = ps_tiledforward_transparent;
+ }
+ break;
+ }
+
+ switch (i)
+ {
+ case RENDERPASS_FORWARD:
+ case RENDERPASS_TILEDFORWARD:
+ desc.numRTs = 2;
+ desc.RTFormats[0] = wiRenderer::RTFormat_hdr;
+ desc.RTFormats[1] = wiRenderer::RTFormat_gbuffer_1;
+ desc.dss = &dss_equal; // opaque
+ break;
+ case RENDERPASS_DEFERRED:
+ desc.numRTs = 5;
+ desc.RTFormats[0] = wiRenderer::RTFormat_gbuffer_0;
+ desc.RTFormats[1] = wiRenderer::RTFormat_gbuffer_1;
+ desc.RTFormats[2] = wiRenderer::RTFormat_gbuffer_2;
+ desc.RTFormats[3] = wiRenderer::RTFormat_deferred_lightbuffer;
+ desc.RTFormats[4] = wiRenderer::RTFormat_deferred_lightbuffer;
+ }
+
+ if (j == 1)
+ {
+ desc.dss = &dss_rejectopaque_keeptransparent; // transparent
+ desc.numRTs = 1;
+ }
+
+ device->CreatePipelineState(&desc, &PSO[i][j]);
}
-
- PipelineStateDesc desc;
- desc.vs = vs;
- desc.ps = ps[i];
- desc.bs = &bs[j];
- desc.rs = &ncrs;
- desc.dss = &dss_default;
-
- desc.DSFormat = wiRenderer::DSFormat_full;
-
- switch (i)
- {
- case RENDERPASS_TEXTURE:
- desc.numRTs = 1;
- desc.RTFormats[0] = wiRenderer::RTFormat_hdr;
- break;
- case RENDERPASS_FORWARD:
- case RENDERPASS_TILEDFORWARD:
- desc.numRTs = 2;
- desc.RTFormats[0] = wiRenderer::RTFormat_hdr;
- desc.RTFormats[1] = wiRenderer::RTFormat_gbuffer_1;
- desc.dss = &dss_equal; // opaque
- break;
- case RENDERPASS_DEFERRED:
- desc.numRTs = 5;
- desc.RTFormats[0] = wiRenderer::RTFormat_gbuffer_0;
- desc.RTFormats[1] = wiRenderer::RTFormat_gbuffer_1;
- desc.RTFormats[2] = wiRenderer::RTFormat_gbuffer_2;
- desc.RTFormats[3] = wiRenderer::RTFormat_deferred_lightbuffer;
- desc.RTFormats[4] = wiRenderer::RTFormat_deferred_lightbuffer;
- default:
- break;
- }
-
- if (j == 1)
- {
- desc.dss = &dss_rejectopaque_keeptransparent; // transparent
- desc.numRTs = 1;
- }
-
- device->CreatePipelineState(&desc, &PSO[i][j]);
}
}
diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp
index 90733b0de..03060861b 100644
--- a/WickedEngine/wiVersion.cpp
+++ b/WickedEngine/wiVersion.cpp
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 31;
// minor bug fixes, alterations, refactors, updates
- const int revision = 9;
+ const int revision = 10;
long GetVersion()