Welcome, Guest! Login | Register

Add Far Clipping/Fading to Particles [Print this Article]
Posted by: trepid_jon
Date posted: Oct 11 2005
User Rating: 5 out of 5.0
Number of views: 5578
Number of comments: 0
Description: This will let you optionally set far clipping/fading on particles, so you can fade particles out at a certain distance from you.
As far as I can tell, Valve only made it possible to clip/fade particles when you get near them. But they didn't make an option to clip/fade particles when you get far away from them. I needed this option for one of my mods, and since I got it working, I figured I would post an article to help out anyone who needs or wants to do this as well.

First thing we'll do is go into cl_dll\particle_util.h and look for the GetAlphaDistanceFade inline function...

 CODE  
inline float GetAlphaDistanceFade(
    const Vector &pos,
    const float fadeNearDist,
    const float fadeFarDist)
{
    if(-pos.z > fadeFarDist)
    {
        return 1;
    }
    else if(-pos.z > fadeNearDist)
    {
        return (-pos.z - fadeNearDist) / (fadeFarDist - fadeNearDist);
    }
    else
    {
        return 0;
    }
}


Either comment that code or erase it (I commented mine), then put this new code in its place...

 CODE  
// If you can find a MAX_VIEW_DISTANCE or something, maybe use that instead of 65536.
inline float GetAlphaDistanceFade(
    const Vector &pos,
    const float fadeNearMin,
    const float fadeNearMax,
    const float fadeFarMin = 65536,
    const float fadeFarMax = 65536)
{
    if ( -pos.z < fadeNearMin || -pos.z > fadeFarMax )
    {
        return 0;
    }
    else if ( -pos.z < fadeNearMax && fadeNearMax != fadeNearMin )
    {
        return ( -pos.z - fadeNearMin ) / ( fadeNearMax - fadeNearMin );
    }
    else if( -pos.z > fadeFarMin && fadeFarMax != fadeFarMin )
    {
        return 1 - ( ( -pos.z - fadeFarMin ) / ( fadeFarMax - fadeFarMin ) );
    }
    else
    {
        return 1;
    }
}


I made a picture with example settings to help explain what's happening...

user posted image

In case you're curious, we're defaulting fadeFarMin and fadeFarMax, because we want all previous calls to GetAlphaDistanceFade to still work without us having to change them. I used 65536 as the defaults, because that seems like a good number and I don't think the player will ever get that far away from the particles anyway. I actually first tried just doing the 3D distance formula from points (16384,16384,16384) to (-16384,-16384,-16384), and got 56755.84086241697. But I don't think it really matters, so I just put 65536 in there.

Now, to take advantage of the new GetAlphaDistanceFade function, we need to find out where it's being called that would be useful to us. If you search in files for that function, you will find it being called in a few different places. The two places we're going to worry with are in cl_dll\particles_localspace.cpp and cl_dll\particles_simple.cpp. We'll leave the other calls in the other files the way they are, so they'll be using the defaults that we setup in GetAlphaDistanceFade.

So moving on, open cl_dll\particles_localspace.cpp, go into void CLocalSpaceEmitter::RenderParticles( CParticleRenderIterator *pIterator ), and look for this...

 CODE  
        // Render it
        RenderParticle_ColorSizeAngle(
            pIterator->GetParticleDraw(),
            screenPos,
            UpdateColor( pParticle ),
            UpdateAlpha( pParticle ) * GetAlphaDistanceFade( screenPos, m_flNearClipMin, m_flNearClipMax ),
            UpdateScale( pParticle ),
            pParticle->m_flRoll
            );


Change that to this...

 CODE  
        // Render it
        RenderParticle_ColorSizeAngle(
            pIterator->GetParticleDraw(),
            screenPos,
            UpdateColor( pParticle ),
            UpdateAlpha( pParticle ) * GetAlphaDistanceFade( screenPos, m_flNearClipMin, m_flNearClipMax, m_flFarClipMin, m_flFarClipMax ),
            UpdateScale( pParticle ),
            pParticle->m_flRoll
            );


If you were to compile right now, you would get errors because m_flFarClipMin and m_flFarClipMax are not members of the class CLocalSpaceEmitter. But we're not going to declare them in CLocalSpaceEmitter. Instead, we're going to declare them in CSimpleEmitter, which is CLocalSpaceEmitter's parent.

So open cl_dll\particles_simple.h, and find these...

 CODE  
    float           m_flNearClipMin;
    float           m_flNearClipMax;


Right under those, we're going to add m_flFarClipMin and m_flFarClipMax...

 CODE  
    float           m_flFarClipMin;
    float           m_flFarClipMax;


We have the member varialbes now, but we need to set the default values in the CSimpleEmitter Constructor so we don't get any chode...because chode is bad!

Open cl_dll\particles_simple.cpp and find the Constructor...

 CODE  
CSimpleEmitter::CSimpleEmitter( const char *pDebugName ) : CParticleEffect( pDebugName )
{
    m_pDebugName = pDebugName;

    m_flNearClipMin = 16.0f;
    m_flNearClipMax = 64.0f;
}


Change that to this...

 CODE  
CSimpleEmitter::CSimpleEmitter( const char *pDebugName ) : CParticleEffect( pDebugName )
{
    m_pDebugName = pDebugName;

    m_flNearClipMin = 16.0f;
    m_flNearClipMax = 64.0f;

    m_flFarClipMin = 65536;
    m_flFarClipMax = 65536;
}


Now our initial values are good to go, which also means all previous calls to CLocalSpaceEmitter::RenderParticles will still work in the same old way, since 65536 is a really long distance that I don't even think is possible in Source without you changing something. If you do that, then you'd have to change the defaults that we've setup so far, so keep that in mind.

But wait, we're not done yet. There's another call to GetAlphaDistanceFade that we need to change like we did to the one in cl_dll\particles_localspace.cpp. This second call to GetAlphaDistanceFade is in the same file that you might still be in.

In cl_dll\particles_simple.cpp, go into void CSimpleEmitter::RenderParticles( CParticleRenderIterator *pIterator ) and look for this (almost the same as above)...

 CODE  
        //Render it
        RenderParticle_ColorSizeAngle(
            pIterator->GetParticleDraw(),
            tPos,
            UpdateColor( pParticle ),
            UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ),
            UpdateScale( pParticle ),
            pParticle->m_flRoll
            );


Go ahead and change that to this...

 CODE  
        //Render it
        RenderParticle_ColorSizeAngle(
            pIterator->GetParticleDraw(),
            tPos,
            UpdateColor( pParticle ),
            UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax, m_flFarClipMin, m_flFarClipMax ),
            UpdateScale( pParticle ),
            pParticle->m_flRoll
            );


So now everything is ready, and you should be all set. However, there is one more thing that you should probably do.

You might have noticed that m_flNearClipMin, m_flNearClipMax, m_flFarClipMin, are m_flFarClipMax are protected inside CSimpleEmitter. Well, m_flNearClipMin and m_flNearClipMax can bet set from the outside with a function called SetNearClip. So what we're going to do next is create SetFarClip to let us do the same thing to m_flFarClipMin and m_flFarClipMax.

In cl_dll\particles_simple.h, look for this...

 CODE  
    void            SetNearClip( float nearClipMin, float nearClipMax );


We'll add SetFarClip right after that...

 CODE  
    void            SetFarClip( float farClipMin, float farClipMax );


Now that SetFarClip is declared, let's head into cl_dll\particles_simple.cpp and look for the SetNearClip definition to keep them together. So look for this...

 CODE  
//-----------------------------------------------------------------------------
// Purpose: Set the internal near clip range for this particle system
// Input  : nearClipMin - beginning of clip range
//          nearClipMax - end of clip range
//-----------------------------------------------------------------------------
void CSimpleEmitter::SetNearClip( float nearClipMin, float nearClipMax )
{
    m_flNearClipMin = nearClipMin;
    m_flNearClipMax = nearClipMax;
}


And add our SetFarClip definition right under that...

 CODE  
//-----------------------------------------------------------------------------
// Purpose: Set the internal far clip range for this particle system
// Input  : farClipMin - beginning of clip range
//          farClipMax - end of clip range
//-----------------------------------------------------------------------------
void CSimpleEmitter::SetFarClip( float farClipMin, float farClipMax )
{
    m_flFarClipMin = farClipMin;
    m_flFarClipMax = farClipMax;
}


Finally. We should now be done and you can fade particles out when they get a certain distance from you or whatever position you want to test.

One way to test the new particle far clipping/fading is to open cl_dll\sdk\c_sdk_env_sparkler.cpp, go into void C_Sparkler::OnDataChanged( DataUpdateType_t updateType ), and look for this...

 CODE  
        // Creat the emitter
        m_hEmitter = CSimpleEmitter::Create( "env_sparkler" );


Under that, add this...

 CODE  
        m_hEmitter->SetNearClip(32, 96);
        m_hEmitter->SetFarClip(160, 192);


Now just run your mod and open the sdk_fx map. If you don't have it compiled yet, the VMF should be in your mod's mapsrc folder. In the map, you just step on the platform to turn the sparklers on or off.

Also, you might notice that if you don't call SetNearClip, the particle will still fade out when you get close to it. That's because back in the CSimpleEmitter Constructor in cl_dll\particles_simple.cpp, m_flNearClipMin and m_flNearClipMax are defaulted to 16 and 64, respectively. You can change those to 0 and 0, and they won't fade out when you get close to them. I left mine at 16 and 64, though, as I think they're defaulted to fade out when you get close to them to help the fill rate...maybe?

Anyway, I think that's all there is to mention. I hope I didn't forget anything, and I hope you can find a good use for this in your mod.

*UPDATE*

I edited the GetAlphaDistanceFade function just a tad by adding in checks to make sure fadeNearMin and fadeNearMax don't equal each other, and to make sure fadeFarMin and fadeFarMax don't equal each other. That way, fadeNearMax - fadeNearMin and fadeFarMax - fadeFarMin won't ever equal 0, thus getting rid of the potential divide by 0 warnings. Plus, there's actually no reason to do any fading calculations if those variables equal each other.

Yup.

Rate This Article
This article is currently rated: 5 out of 5.0 (1 Votes)

You have to register to rate this article.
Related Files
Zip FileFilename: ParticlesNearAndFarFading.jpg
File Size: 43 KB

User Comments

No User Comments

You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 05 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Persuter | Aug 02 2009
 

Site Info
297 Approved Articless
8 Pending Articles
3940 Registered Members
0 People Online (7 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!