Soft Particles

So, is it not working?

Aren’t light volumes pass does it, in DefferedHWDepth and PrepassHWDepth?

Oh, sorry my mistake.
I just do some test with reading from Z and suppose what I got wrong results in readed from Zbuffer.
I thought it was a mistake usage of depth buffer in same time for read and testing.

and other questions:

  1. did you trying to reproject Z sample from depth buffer from (NDC space) to (ViewProj space before div by w) xyz/w value ?

float hwDepth = texture2D(sDepthBuffer, vTexCoord).r; // Read Depth value
float rDepth = ReconstructDepth(hwDepth); // Reconstruct 0…1
What next step?

  1. The value that will be written to DepthBuffer from VS shader:
    gl_Position = GetClipPos(worldPos);
    Is it this - gl_Position.z / gl_Position.w ?

  2. vWorldPos = vec4(worldPos, GetDepth(gl_Position));
    What thing stored into last component (w) ?

Hi again, I have a some process there, but i stuck in place with comparing sceneZ and particleZ.
As you see on this vedeo if i change a position of camera (rotate around) there is bug, particles are disappears.
I guessing this is because I have some problems with math difference between background sceneZ value and particleZ value.
and I do not actually know what of this reprojecties are wrong in my shader.

I have a this algorithm:

RenderPath

    <!-- Render SoftParticles --> 
    <command type="scenepass" pass="softparticles" vertexlights="true" sort="backtofront" metadata="alpha" blend="replace" output="viewport">
        <texture unit="depth" name="depth" />
    </command>

Technique for particles
DiffVColUnlitAlphaSP.xml

<technique vs="UnlitSP" ps="UnlitSP" vsdefines="VERTEXCOLOR SP" psdefines="DIFFMAP VERTEXCOLOR SP">
    <pass name="softparticles" depthtest="always" depthwrite="false" blend="alpha" />
</technique

and shader UnlitSP.glsl

I suppose what I do wrong converting sceneZ into ViewProj space or particleZ into ViewProj space. (mb need get ViewProjInvert matrix from camera to project with sceneZ * ViewProjInvert)
Is any body have some ideas how to solve rotation bug ?

i create material

<material> <technique name="Techniques/DiffVColUnlitAlphaSP.xml" /> <texture unit="diffuse" name="Urho2D/Ball.png" /> </material>

and it is fully transparent

p.s. Where did the variable cProj in shader?

and it is fully transparent
I use for testing tweaked smoke.xml

p.s. Where did the variable cProj in shader?
actually I add this matrixes and pass they in:

void View::SetCameraShaderParameters(Camera* camera, bool setProjection) { graphics_->SetShaderParameter(VSP_VIEWPROJ, projection * camera->GetView()); graphics_->SetShaderParameter(VSP_VIEW, Matrix4::IDENTITY * camera->GetView()); graphics_->SetShaderParameter(VSP_PROJ, projection); }

also you need after what fix uniforms.glsl to set visible this uniforms for PS shader

// OpenGL 2 uniforms (no constant buffers)

uniform mat4 cViewProj;
uniform mat4 cProj;

#ifdef COMPILEVS
...

I found a solution (and modification of the engine is not required)

CoreData\RenderPaths\ForwardHWDepth_SoftParticles.xml (based on ForwardHWDepth)

<renderpath>
    <rendertarget name="depth" sizedivisor="1 1" format="readabledepth" />
    <command type="clear" depth="1.0" output="depth" />
    <command type="scenepass" pass="shadow" output="depth" />
    <command type="clear" color="fog" depthstencil="depth" />
    <command type="scenepass" pass="base" vertexlights="true" metadata="base" depthstencil="depth" />
    <command type="forwardlights" pass="light" depthstencil="depth" />
    <command type="scenepass" pass="postopaque" depthstencil="depth" />
    <command type="scenepass" pass="refract" depthstencil="depth">
        <texture unit="environment" name="viewport" />
    </command>
    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth"  />
    <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
    <!-- Render SoftParticles -->
    <command type="scenepass" pass="softparticles" vertexlights="true" sort="backtofront" metadata="alpha" blend="replace" output="viewport">
        <texture unit="depth" name="depth" />
    </command>
</renderpath>

CoreData\Shaders\GLSL\UnlitSP.glsl (based on unlit)

#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"
#include "Fog.glsl"

varying vec2 vTexCoord;
varying vec4 vWorldPos;
varying vec4 vScreenPos;
#ifdef VERTEXCOLOR
    varying vec4 vColor;
#endif

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    vTexCoord = GetTexCoord(iTexCoord);
    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
    vScreenPos = GetScreenPos(gl_Position);

    #ifdef VERTEXCOLOR
        vColor = iColor;
    #endif
}

void PS()
{
    // Get material diffuse albedo
    #ifdef DIFFMAP
        vec4 diffColor = cMatDiffColor * texture2D(sDiffMap, vTexCoord);
        #ifdef ALPHAMASK
            if (diffColor.a < 0.5)
                discard;
        #endif
    #else
        vec4 diffColor = cMatDiffColor;
    #endif

    #ifdef VERTEXCOLOR
        diffColor *= vColor;
    #endif

    // Get fog factor
    #ifdef HEIGHTFOG
        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
    #else
        float fogFactor = GetFogFactor(vWorldPos.w);
    #endif

    #if defined(PREPASS)
        // Fill light pre-pass G-Buffer
        gl_FragData[0] = vec4(0.5, 0.5, 0.5, 1.0);
        gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
    #elif defined(DEFERRED)
        gl_FragData[0] = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
        gl_FragData[1] = vec4(0.0, 0.0, 0.0, 0.0);
        gl_FragData[2] = vec4(0.5, 0.5, 0.5, 1.0);
        gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
    #else

        float particleDepth = vWorldPos.w;
        float solidGeometrydepth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r); // use ReconstructDepth when HWDEPTH
    
        if (solidGeometrydepth <= particleDepth)
        {
            float deltaDepth = (particleDepth - solidGeometrydepth) * 1000;
            diffColor.a -= deltaDepth;
        }
    
        gl_FragColor = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
    
    #endif
}

CoreData\Techniques\DiffVColUnlitAlphaSP.xml (based on DiffVColUnlitAlpha)

<technique vs="UnlitSP" ps="UnlitSP" vsdefines="VERTEXCOLOR SP" psdefines="DIFFMAP VERTEXCOLOR SP">
    <pass name="softparticles" depthtest="always" depthwrite="false" blend="alpha" />
</technique>

Data\Materials\SmokeSoftParticle.xml (based on Smoke)

<material>
    <technique name="Techniques/DiffVColUnlitAlphaSP.xml" />
    <texture unit="diffuse" name="Textures/Smoke.dds" />
</material>

Data\Particle\SmokeStackSoftParticle.xml (based on Smoke)

<?xml version="1.0"?>
<particleeffect>
	<material name="Materials/SmokeSoftParticle.xml" />
	<numparticles value="1000" />
	<updateinvisible enable="true" />
	<relative enable="false" />
	<scaled enable="true" />
	<sorted enable="true" />
	<animlodbias value="0" />
	<emittertype value="Box" />
	<emittersize value="1 1 1" />
	<direction min="-0.15 1 -0.15" max="0.15 1 0.15" />
	<constantforce value="0 2 0" />
	<dampingforce value="2" />
	<activetime value="0" />
	<inactivetime value="0" />
	<emissionrate min="100" max="200" />
	<particlesize min="0.1 0.2" max="0.6 0.7" />
	<timetolive min="4" max="4" />
	<velocity min="0.5" max="3" />
	<rotation min="0" max="0" />
	<rotationspeed min="60" max="60" />
	<sizedelta add="0" mul="1.3" />
	<colorfade color="1 1 1 0" time="0" />
	<colorfade color="0.69 0.33 0.2 0.5" time="0.64" />
	<colorfade color="0 0 0 0" time="1.98" />
	<colorfade color="0 0 0 0" time="4" />
</particleeffect>

Old:

New:

Here is possible make some improvements:
send to shader a coefficient (replacing 1000) from material in the case of large sprites (Like explosions)

Wow, great job.
Did you tried to create some solid blocs around smoke to test overlaying effect?
I also find this different functions:

//vec2 vScreenPos = GetScreenPosPreDiv(gl_Position);
    vec4 vScreenPos = GetScreenPos(gl_Position);[/code]

in what case we may use each of them ? I do not understand.

>float sceneZ = texture2DProj(sDepthBuffer, vScreenPos).r;   // read depthstencil texture(readabledepth)
the using texture2DProj is providing from previous operation step because size of  vScreenPos is vec4 and not vec2, or there is another reason? ( why we use texture projection? and no simple texture2D )

there is magic number I guess 1000 ? If we change this block of code to NV's code from whitepaper is still will be working properly?
[code]        if (solidGeometrydepth <= particleDepth)
        {
            float deltaDepth = (particleDepth - solidGeometrydepth) * 1000;
            diffColor.a -= deltaDepth;
        }

to

[code] float scale = 1.0;
float diffZ = (particleDepth - solidGeometrydepth)

        float input = clamp(diffZ, 0.0, 1.0);
        float contrastPower = 1.0;
        float output = 0.5 * pow(clamp(2*((input > 0.5) ? 1 - input : input), 0.0, 1.0), contrastPower);
        float weight = (input > 0.5) ? 1 - output : output; 
        
        diffColor.a *= weight;

[/code]

I mean in using NV’s tech we got two controls values what very handy: the control of contrast and scale.

in what case we may use each of them ? I do not understand.
the using texture2DProj is providing from previous operation step because size of vScreenPos is vec4 and not vec2, or there is another reason?

i just copy random code from PrepassLight.glss xD

there is magic number I guess 1000 ? If we change this block of code to NV’s code from whitepaper is still will be working properly?

I did not study the documentation in detail. The higher the number, the greater the depth difference will affect the transparency (most of the hidden part of sprite will be visible).

I’m tesing you shader and “overlaying” is not presented I guess it work fine for now.

i just copy random code from PrepassLight.glss xD
i am always wanted to write shaders in this manner, and in same time i wanted to they should work as I expect xD

I did not study the documentation in detail.
There is no documentation about shaders using )
For example what differences between: this -> GetScreenPosPreDiv() and this -> GetScreenPos() and many other things…

Anyway I think you may try to create pull request with your SoftParticles.
In future we can polish they )

[quote=“codingmonkey”]
Anyway I think you may try to create pull request with your SoftParticles.
In future we can polish they )[/quote]

It will not work in all RenderPaths. I do not think it will take to master. Just rename this post to “Soft Particles” and and anyone can take shader here.

Ok, but may be you create small repo for store all stuff in one place also for fixes and updating ?

  • also need add hlsl shader for SoftParticles

[quote=“codingmonkey”]Ok, but may be you create small repo for store all stuff in one place also for fixes and updating ?

  • also need add hlsl shader for SoftParticles[/quote]

no problems :slight_smile:

EDIT: github.com/1vanK/Urho3DSoftParticles

https://github.com/1vanK/Urho3DSoftParticles

cool, but I found what it no working in ortho projection (when you press key 5 on numpad)

[quote=“codingmonkey”]
cool, but I found what it no working in ortho projection (when you press key 5 on numpad)[/quote]

Oh, sorry I understood, I’m use not your original shader )
anyway I found there this 1000 value are lay (Editor settings camera far clip) - this is camera far value.
In PS shader this is cFarClipPS uniform
I guessing the scale may be calc with this way:
float scale = cFarClipPS - cNearClipPS;

Nice, would be that also possible on the deffered render path?

would be that also possible on the deffered render path?
Yes it possible, few lines to add in deffered

DeferredHWDepthSP.xml (in simple Deferred.xml we do not have possibility to read depth. That’s why this working only with %name%HWDepth )

<renderpath>
    <rendertarget name="albedo" sizedivisor="1 1" format="rgba" />
    <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
    <rendertarget name="depth" sizedivisor="1 1" format="readabledepth" />
    <command type="clear" color="fog" depth="1.0" stencil="0" depthstencil="depth" />
    <command type="clear" color="0 0 0 0" output="albedo" depthstencil="depth" />
    <command type="scenepass" pass="deferred" marktostencil="true" vertexlights="true" metadata="gbuffer" depthstencil="depth">
        <output index="0" name="viewport" />
        <output index="1" name="albedo" />
        <output index="2" name="normal" />
    </command>
    <command type="lightvolumes" vs="DeferredLight" ps="DeferredLight" psdefines="HWDEPTH" depthstencil="depth">
        <texture unit="albedo" name="albedo" />
        <texture unit="normal" name="normal" />
        <texture unit="depth" name="depth" />
    </command>
    <command type="scenepass" pass="postopaque" depthstencil="depth" />
    <command type="scenepass" pass="refract" depthstencil="depth">
        <texture unit="environment" name="viewport" />
    </command>
    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
    
    <command type="scenepass" pass="softparticles" vertexlights="true" sort="backtofront" metadata="alpha" blend="replace" output="viewport">
        <texture unit="depth" name="depth" />
    </command>
    
    <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
</renderpath>

and move soft particle calculations in shader little upper

UnlitSP.glsl

#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"
#include "Fog.glsl"

varying vec2 vTexCoord;
varying vec4 vWorldPos;
varying vec4 vScreenPos;
#ifdef VERTEXCOLOR
    varying vec4 vColor;
#endif

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    vTexCoord = GetTexCoord(iTexCoord);
    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
    vScreenPos = GetScreenPos(gl_Position);
    //vScreenPos = GetScreenPosPreDiv(gl_Position);

    #ifdef VERTEXCOLOR
        vColor = iColor;
    #endif
}

void PS()
{
    // Get material diffuse albedo
    #ifdef DIFFMAP
        vec4 diffColor = cMatDiffColor * texture2D(sDiffMap, vTexCoord);
        #ifdef ALPHAMASK
            if (diffColor.a < 0.5)
                discard;
        #endif
    #else
        vec4 diffColor = cMatDiffColor;
    #endif

    #ifdef VERTEXCOLOR
        diffColor *= vColor;
    #endif

    // Get fog factor
    #ifdef HEIGHTFOG
        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
    #else
        float fogFactor = GetFogFactor(vWorldPos.w);
    #endif
    
    float particleDepth = vWorldPos.w;
    float solidGeometrydepth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r); // use ReconstructDepth when HWDEPTH
        
    if (solidGeometrydepth < particleDepth)
    {
        float scale = cFarClipPS - cNearClipPS;
        float deltaDepth = (particleDepth - solidGeometrydepth) * scale;    
         
        diffColor.a -= deltaDepth;
    }
    
    #if defined(PREPASS)
        // Fill light pre-pass G-Buffer
        gl_FragData[0] = vec4(0.5, 0.5, 0.5, 1.0);
        gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
    #elif defined(DEFERRED)
        gl_FragData[0] = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
        gl_FragData[1] = vec4(0.0, 0.0, 0.0, 0.0);
        gl_FragData[2] = vec4(0.5, 0.5, 0.5, 1.0);
        gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
    #else    
        gl_FragColor = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
    #endif
}

Anyone is planning to make a pull request in master branch to add this ? I think it’s a must have feature for a modern engine :slight_smile:

We had a big discussion with CodingMonkey and came to the conclusion that still need to do much

github.com/1vanK/Urho3DSoftParticles/pull/3 (sorry, the Russian language)