📄 softparticles.fx
字号:
//
// PS for the particles
//
PSParticleOut PSBillboardParticleDepthmain(PSParticleIn input, uniform bool bSoftParticles )
{
PSParticleOut output;
float2 screenTex = 0.5*( (input.ScreenTex) + float2(1,1));
screenTex.y = 1 - screenTex.y;
float4 particleSample = g_txVolumeDiff.Sample( g_samVolume, input.Tex );
float3 particleNormal = g_txVolumeNorm.Sample( g_samVolume, input.Tex );
float size = g_fSizeZScale*input.Size; //move the size into the depth buffer space
float particleDepth = input.Depth.x - size*2.0*(particleSample.a); //augment it by the depth stored in the texture
particleDepth /= input.Depth.y;
float depthFade = 1;
if( bSoftParticles )
{
// We need to determine the distance between the value stored in the depth buffer
// and the value that came in from the GS
// Because the depth values aren't linear, we need to transform the depthsample back into view space
// in order for the comparison to give us an accurate distance
float depthSample = g_txDepth.Sample( g_samPoint, screenTex );
float4 depthViewSample = mul( float4( input.ScreenTex, depthSample, 1 ), g_mInvProj );
float4 depthViewParticle = mul( float4( input.ScreenTex, particleDepth, 1 ), g_mInvProj );
float depthDiff = depthViewSample.z/depthViewSample.w - depthViewParticle.z/depthViewParticle.w;
if( depthDiff < 0 )
discard;
depthFade = saturate( depthDiff / g_fFadeDistance );
}
float4 Light = g_directional1 + g_ambient;
particleSample.rgb *= Light.xyz*input.particleColor;
particleSample.a *= depthFade;
output.Color = particleSample;
output.Depth = particleDepth;
return output;
}
// ray-sphere intersection
#define DIST_BIAS 0.01
bool RaySphereIntersect( float3 rO, float3 rD, float3 sO, float sR, inout float tnear, inout float tfar )
{
float3 delta = rO - sO;
float A = dot( rD, rD );
float B = 2*dot( delta, rD );
float C = dot( delta, delta ) - sR*sR;
float disc = B*B - 4.0*A*C;
if( disc < DIST_BIAS )
{
return false;
}
else
{
float sqrtDisc = sqrt( disc );
tnear = (-B - sqrtDisc ) / (2*A);
tfar = (-B + sqrtDisc ) / (2*A);
return true;
}
}
float4 Noise3D( float3 uv, int octaves )
{
float4 noiseVal = float4(0,0,0,0);
float4 octaveVal = float4(0,0,0,0);
float3 uvOffset;
float freq = 1;
float pers = 1;
for( int i=0; i<octaves; i++ )
{
uvOffset = uv + g_OctaveOffsets[i].xyz;
octaveVal = g_txVolumeDiff.SampleLevel( g_samVolume, uvOffset*freq, 0 );
noiseVal += pers * octaveVal;
freq *= 3.0;
pers *= 0.5;
}
noiseVal.a = abs( noiseVal.a ); //turbulence
return noiseVal;
}
//
// PS for the volume particles
//
#define MAX_STEPS 8
float4 PSVolumeParticlemain( PSParticleIn input, uniform bool bSoftParticles ) : SV_Target
{
float2 screenTex = 0.5*( (input.ScreenTex) + float2(1,1));
screenTex.y = 1 - screenTex.y;
float depthSample = g_txDepth.Sample( g_samPoint, screenTex );
float4 depthViewSample = mul( float4( input.ScreenTex, depthSample, 1 ), g_mInvProj );
float sampleDepth = depthViewSample.z/depthViewSample.w;
// ray sphere intersection
float3 worldPos = input.worldPos;
float3 viewRay = g_vViewDir;
float3 sphereO = input.particleOrig;
float rad = input.Size;
float tnear,tfar;
if( !RaySphereIntersect( worldPos, viewRay, sphereO, rad, tnear, tfar ) )
discard;
float3 worldNear = worldPos + viewRay*tnear;
float3 worldFar = worldPos + viewRay*tfar;
float4 viewNear = mul( float4(worldNear,1), g_mWorldView );
float4 viewFar = mul( float4(worldFar,1), g_mWorldView );
float currentDepth = viewNear.z/viewNear.w;
float farDepth = viewFar.z/viewFar.w;
float lifePower = input.Tex.z;//*input.Tex.z;
float depthDiff = farDepth - sampleDepth;
if( depthDiff > 0 ) //make sure we don't trace past the depth buffer
{
// if we do, adjust tfar accordingly
tfar -= depthDiff;
if( tfar < tnear )
discard;
worldFar = worldPos + viewRay*tfar;
farDepth = sampleDepth;
}
float3 unitTex = (worldNear - sphereO)/(rad);
float3 localTexNear,localTexFar;
if(false)
{
localTexNear = (worldNear - sphereO)/(rad*2) + float3(0.5,0.5,0.5);
localTexFar = (worldFar - sphereO)/(rad*2) + float3(0.5,0.5,0.5);
}
else
{
float fNoiseSizeAdjust = 1 / g_noiseSize;
localTexNear = worldNear * fNoiseSizeAdjust;
localTexFar = worldFar * fNoiseSizeAdjust;
}
// trace through the volume texture
int iSteps = length(localTexFar - localTexNear)/g_stepSize;
iSteps = min( iSteps, MAX_STEPS-2 ) + 2;
float3 currentTex = localTexNear;
float3 localTexDelta = (localTexFar - localTexNear)/(iSteps-1);
float depthDelta = (farDepth - currentDepth)/(iSteps-1);
float opacityAdjust = g_noiseOpacity/(iSteps-1);
float lightAdjust = 1.0/(iSteps-1);
float runningOpacity = 0;
float4 runningLight = float4(0,0,0,0);
for( int i=0; i<iSteps; i++ )
{
float4 noiseCell = Noise3D( currentTex, 4 );
noiseCell.xyz += normalize( unitTex );
noiseCell.xyz = normalize( noiseCell.xyz );
// fade out near edges
float depthFade = 1;
if( bSoftParticles )
{
depthFade = saturate( (sampleDepth-currentDepth) / g_fFadeDistance );
}
//falloff as well
float lenSq = dot( unitTex, unitTex );
float falloff = 1.0 - lenSq; //1 - len^2 falloff
// calculate our local opacity for this point
float localOpacity = noiseCell.a*falloff*depthFade;
// add it to our running total
runningOpacity += localOpacity;
// calc lighting from our gradient map and add it to the running total
// dot*0.5 + 0.5 basically makes the dot product wrap around
// giving us more of a volumetric lighting effect
// Also just use one overhead directional light. It gives more contrast and looks cooler.
float4 localLight = g_directional1*saturate( dot( noiseCell.xyz, float3(0,1,0) )*0.5 + 0.5 );
//for rendering the particle alone
//float4 localLight = saturate( dot( noiseCell.xyz, float3(0,1,0) )*0.5 + 0.5 );
runningLight += localLight;
currentTex += localTexDelta;
unitTex += localTexDelta;
currentDepth += depthDelta;
}
float4 col = float4(input.particleColor,1)*(runningLight*lightAdjust)*0.8 + 0.2;// + g_ambient;
runningOpacity = saturate( runningOpacity*opacityAdjust )*(1-lifePower);// - 0.5*lifePower;
//for rendering the particle alone
//float4 col = (runningLight*lightAdjust)*0.8 + 0.2;// + g_ambient;
//col.xyz = runningOpacity.rrr;
//runningOpacity = 1;
float4 color = float4(col.xyz,runningOpacity);
return color;
}
//
// RenderScene
//
technique10 RenderScene
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSScenemain() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PSScenemain() ) );
SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( EnableDepth, 0 );
}
}
//
// RenderScene
//
technique10 RenderSky
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSScenemain() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PSSkymain() ) );
SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepthTest, 0 );
}
}
//
// RenderBillboardParticles_Hard
//
technique10 RenderBillboardParticles_Hard
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSBillboardParticlemain(false) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepthWrite, 0 );
}
}
//
// RenderBillboardParticles_ODepth
//
technique10 RenderBillboardParticles_ODepth
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSBillboardParticleDepthmain(false) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepthWrite, 0 );
}
}
//
// RenderBillboardParticles_Soft
//
technique10 RenderBillboardParticles_Soft
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSBillboardParticlemain(true) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepthWrite, 0 );
}
}
//
// RenderBillboardParticles_Soft
//
technique10 RenderBillboardParticles_ODepthSoft
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSBillboardParticleDepthmain(true) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepth, 0 );
}
}
//
// RenderVolumeParticles_Hard
//
technique10 RenderVolumeParticles_Hard
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSVolumeParticlemain(false) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepth, 0 );
}
}
//
// RenderVolumeParticles_Soft
//
technique10 RenderVolumeParticles_Soft
{
pass p0
{
SetVertexShader( CompileShader( vs_4_0, VSParticlemain() ) );
SetGeometryShader( CompileShader( gs_4_0, GSParticlemain() ) );
SetPixelShader( CompileShader( ps_4_0, PSVolumeParticlemain(true) ) );
SetBlendState( AlphaBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
SetDepthStencilState( DisableDepth, 0 );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -