Manipulating Particles alpha channel according to the Depth

Started by
9 comments, last by Medo Mex 10 years, 8 months ago

I'm trying to implement soft particles for the first time, I created a depth texture using MRT, sent it to the shader, now I'm trying to manipulate the particles alpha channel based on the depth texture.

What's going wrong with the following code? It's not working as expected.

Shader:


texture depthMapTexture;
sampler2D depthMap = sampler_state
{
    Texture = <depthMapTexture>;
    MagFilter = Point;
    MinFilter = Point;
    MipFilter = None;
};

VS_OUTPUT VS( VS_INPUT IN )
{
    ...
    ...
    ...
    OUT.DepthPos = mul(float4(IN.Pos.xyz, 1.0), mul(World, View)).xyz;
    return OUT;
}

float4 PS( VS_OUTPUT IN ) : COLOR
{
    float4 texDiffuse = tex2D(colorMap, IN.UV);
    float particleDepth = IN.DepthPos.z;
    float sceneDepth = tex2D(depthMap, IN.UV).x;
    float scale = 1.0;
    float zFade = saturate(scale * (particleDepth - sceneDepth)); 
    IN.Color.a *= zFade;
    return texDiffuse * IN.Color;
}
Advertisement

I think I need to change this line to sample the depth texture according to the screen resolution?

float sceneDepth = tex2D(depthMap, IN.UV).x;

Any idea how do I fix my code?

This is my first time testing "Soft Particles" so i might be wrong somewhere, but for now it looks good:

OFF

nosoft.jpg

ON

yessoft.jpg

relevant shader parts:

float4 ScreenParams;
...
struct FS_VS_OUTPUT
{
    float4 Position  : POSITION;
    float2 TexCoord0 : TEXCOORD0;
    float4 TexCoord1 : TEXCOORD1;
    float3 PosWV     : TEXCOORD2;
};

struct FS_PS_OUTPUT
{
    float4 Color : COLOR0;
};

void VertexProgram(in FS_VERTEX IN, out FS_VS_OUTPUT OUT)
{
    float4 oPosition = mul(float4(IN.Position, 1.0f), WorldViewProjection);
    OUT.Position     = oPosition;
    oPosition.x      = ((oPosition.x + oPosition.w) * ScreenParams.x + oPosition.w) * ScreenParams.z;
    oPosition.y      = ((oPosition.w - oPosition.y) * ScreenParams.y + oPosition.w) * ScreenParams.w;
    OUT.TexCoord0    = IN.TexCoord0;
    OUT.TexCoord1    = oPosition;
    OUT.PosWV        = mul(float4(IN.Position, 1.0f), WorldView).xyz;
}
 
// function from NVIDIA sample
float Contrast(float Input, float ContrastPower)
{
#if 1
     //piecewise contrast function
     bool IsAboveHalf = Input > 0.5 ;
     float ToRaise = saturate(2*(IsAboveHalf ? 1-Input : Input));
     float Output = 0.5*pow(ToRaise, ContrastPower);
     Output = IsAboveHalf ? 1-Output : Output;
     return Output;
#else
    // another solution to create a kind of contrast function
    return 1.0 - exp2(-2*pow(2.0*saturate(Input), ContrastPower));
#endif
}

void PixelProgram(in FS_VS_OUTPUT IN, out FS_PS_OUTPUT OUT)
{
    float scene_z    = tex2Dproj(DepthSamp, IN.TexCoord1).z;
    float particle_z = IN.PosWV.z;
    float depthDiff  = (scene_z - particle_z);
    float fade       = Contrast(depthDiff * 0.82f, 2.0f);
    float4 color     = tex2D(ColorSamp, IN.TexCoord0);
    color.a         *= fade;
    OUT.Color        = color;
}

technique tTech2
{
    pass p0
    {
        VertexShader = compile vs_3_0 VertexProgram();
        PixelShader  = compile ps_3_0 PixelProgram();

        ALPHABLENDENABLE = TRUE;
        SRCBLEND         = SRCALPHA;
        DESTBLEND        = INVSRCALPHA;
        ZWRITEENABLE     = FALSE;
    }
}

Where ScreenParams is:

D3DXVECTOR4 screenParams((float)WIN_DIM.cx, (float)WIN_DIM.cy, 1.0f / (2.0f * (float)WIN_DIM.cx), 1.0f / (2.0f * (float)WIN_DIM.cy));

It didn't work for me, I can't see the particles most of the time, here is the shader code:


float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProj;

float4 ScreenParams;

struct VS_INPUT
{
   float3 Pos : POSITION;
   float4 Color : COLOR;
   float2 UV : TEXCOORD0;
   float3 Normal : NORMAL;
};

struct VS_OUTPUT
{
    float4 Pos : POSITION;
    float4 Color : COLOR;
    float2 UV : TEXCOORD0;
    float3 Normal : TEXCOORD1;
    float3 worldPos : TEXCOORD2;
    float3 WPos : TEXCOORD3;
    float3 DepthPos : TEXCOORD4;
    float4 screenPos : TEXCOORD5;
};


texture colorMapTexture;
sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};


texture depthMapTexture;
sampler2D depthMap = sampler_state
{
    Texture = <depthMapTexture>;
    MIPFILTER   = LINEAR;
    MAGFILTER   = LINEAR;
    MINFILTER   = LINEAR;
};

//-----------------------------------------------------------------------
// Vertex shader function
//-----------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    OUT = (VS_OUTPUT)0;
    float4 oPosition = mul(float4(IN.Pos, 1.0f), WorldViewProj);
    OUT.Pos = oPosition;
    OUT.UV = IN.UV;
    OUT.Color = IN.Color;
    OUT.Normal    = mul(float4(IN.Normal, 0.0f), World).xyz;
    OUT.worldPos  = mul(float4(IN.Pos, 1.0f), World).xyz;
    OUT.WPos = IN.Pos;
    OUT.DepthPos = mul(float4(IN.Pos.xyz, 1.0), mul(World, View)).xyz;
    oPosition.x      = ((oPosition.x + oPosition.w) * ScreenParams.x + oPosition.w) * ScreenParams.z;
    oPosition.y      = ((oPosition.w - oPosition.y) * ScreenParams.y + oPosition.w) * ScreenParams.w;
    OUT.screenPos = oPosition;
    return OUT;
}

// function from NVIDIA sample
float Contrast(float Input, float ContrastPower)
{
#if 1
     //piecewise contrast function
     bool IsAboveHalf = Input > 0.5 ;
     float ToRaise = saturate(2*(IsAboveHalf ? 1-Input : Input));
     float Output = 0.5*pow(ToRaise, ContrastPower);
     Output = IsAboveHalf ? 1-Output : Output;
     return Output;
#else
    // another solution to create a kind of contrast function
    return 1.0 - exp2(-2*pow(2.0*saturate(Input), ContrastPower));
#endif
}

//-----------------------------------------------------------------------
// Pixel shader function
//-----------------------------------------------------------------------
float4 PS( VS_OUTPUT IN ) : COLOR
{
    float4 texDiffuse = tex2D(colorMap, IN.UV);
    float scene_z    = tex2Dproj(depthMap, IN.screenPos).z;
    float particle_z = IN.DepthPos.z;
    float depthDiff  = (scene_z - particle_z);
    float fade       = Contrast(depthDiff * 0.82f, 2.0f);

    float4 color = texDiffuse * IN.Color;
    color.a *= fade;
    return color;
}


technique PTech
{
    pass
    {
        AlphaBlendEnable = TRUE;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        ZEnable = TRUE;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS();
    }
}
@belfegor: Please check if I'm even creating a valid depth map, I shared the screenshot:
You might also want to share the sample project that you have created with working soft particles so I can check to see what's going on.

There is a small problem which i did not solve yet:

terrain2013-08-1515-50-0.jpg

EDIT: Temporary fix:

if(depthDiff > 0.0f)
        color.a         *= fade;

@belfegor: When I change the line:


float fade       = Contrast(depthDiff * 0.82f, 2.0f);

To:


float fade       = Contrast(depthDiff * 0.001f, 2.0f);

The soft particles works, but ONLY on the terrain! I see hard particles on other meshes.

I'm rendering the terrain with a shader and all other meshes with another shader.

I also notice that the other meshes never get smoke at all if I rendered the terrain BEFORE the other meshes.

I think that the terrain shader maybe overriding the other meshes depth?

I appreciate your help! :)

That "another shader" must also write to depth texture, and always draw transparent/alphablended stuff last.

@belfegor: It's working now but I can notice some sort of hard edges (not like before) but still noticeable:

[attachment=17411:26226.png]

How do I fix it?

Last thing: How do I enable multisample anti-aliasing? It's not working anymore.


How do I fix it?

I really don't know.

Only samples that i could find was obfuscated with other unrelated stuff so i could not see the main/key points to understand this properly, so i guessed some stuff and

shared my project with you as it is better then nothing, right?


How do I enable multisample anti-aliasing? It's not working anymore

I think you can't have dx "built in" AA with MRTs, research about other AA methods or do multiple render passes.

This topic is closed to new replies.

Advertisement