sdk_particle

From Valve Developer Community
Jump to: navigation, search

sdk_particle is a sample Shader that was provided with the original Source SDK, it has since been replaced by the current set of SDK Shaders.

Warning: This shader relies on deprecated functionality of the materialsystem that has been removed from the Source 2007 SDK and upwards.

sdk_particle_ps11.fxc

sampler BumpmapSampler		: register( s0 );

struct PS_INPUT
{
	float2 vBumpTexCoord			: TEXCOORD0;
	float3 vTangentSpaceLightDir	: TEXCOORD1;
	
	float4 vDirLightScale	: COLOR0;
	float3 vAmbientColor	: COLOR1;
};

float4 main( PS_INPUT i ) : COLOR
{
	float4 baseColor = tex2D( BumpmapSampler, i.vBumpTexCoord );
	
	// Dot the bump normal and the light vector.
	float4 vBumpMapNormal = (baseColor - 0.5);				// The format of the sphere map is 0 to 1, 
															// so this is now -0.5 to 0.5.

	float3 vTangentSpaceLightDir = (i.vTangentSpaceLightDir - 0.5) * 2;	// This is  -1  to 1
	float4 vOutput = dot( vBumpMapNormal, vTangentSpaceLightDir ) + 0.5;
	
	// Scale by the light color outputted by the vertex shader (ie: based on distance).
	vOutput *= i.vDirLightScale;

	// Add ambient.
	vOutput += float4( i.vAmbientColor.x, i.vAmbientColor.y, i.vAmbientColor.z, 0 );

	// Alpha = normal map alpha * vertex alpha
	vOutput.a = baseColor.a * i.vDirLightScale.a;

	return vOutput;
}

sdk_particle_vs11.fxc

// DYNAMIC: "FOGTYPE" "0..1"

#include "common_vs_fxc.h"

static const int g_FogType = FOGTYPE;
const float4 cCustomConstants[6]	:  register( SHADER_SPECIFIC_CONST_0 );

const float4 g_vLightPosition : register( SHADER_SPECIFIC_CONST_0 );
const float4 g_vLightColor : register( SHADER_SPECIFIC_CONST_1 );		// range 0-1
const float  g_flLightIntensity : register( SHADER_SPECIFIC_CONST_2 );	// scales g_vLightColor

struct VS_INPUT
{
	// If this is float4, and the input is float3, the w component default to one.
	float4 vPos							: POSITION; 
	float2 vBumpTexCoord				: TEXCOORD0;
	float4 vAmbientColor				: COLOR0;
};

struct VS_OUTPUT
{
    float4 projPos				: POSITION;	
	float  fog					: FOG;
	
	float2 vBumpTexCoord			: TEXCOORD0;
	float3 vTangentSpaceLightDir	: TEXCOORD1;
	
	float4 vDirLightScale	: COLOR0;
	float3 vAmbientColor	: COLOR1;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o;

	// Transform the input position.
	float4 projPos = mul( v.vPos, cModelViewProj );
	o.projPos = projPos;

	// Setup fog.
	o.fog = CalcFog( mul( v.vPos, cModel[0] ), projPos, g_FogType );

	// Copy texcoords over.
	o.vBumpTexCoord = v.vBumpTexCoord;

	// Copy the vertex color over.
	o.vAmbientColor = v.vAmbientColor;

	// ------------------------------------------------------------------------------
	//  Generate a tangent space and rotate L.
	//  This can be thought of as rotating the normal map to face the viewer.
	// 
	//  This is useful when a particle is way off to the side of the screen.
	//  You should be looking at the half-sphere with a normal pointing from the
	//  particle to the viewer. Instead, you're looking at the half-sphere with
	//  a normal along Z. This tangent space builder code fixes the problem.
	// 
	//  Note that since the model and view matrices are identity, the coordinate
	//  system has X=right, Y=up, and Z=behind you  (negative Z goes into the screen).
	// ------------------------------------------------------------------------------
	
	// This basis wants Z positive going into the screen so flip it here.
	float4 vForward = normalize( float4( v.vPos.x, v.vPos.y, -v.vPos.z, 1 ) );

	// This is the same as CrossProduct( vForward, Vector( 1, 0, 0 ) )
	float4 vUp = normalize( float4( 0, vForward.z, -vForward.y, vForward.w ) );
	
	// vRight = CrossProduct( vUp, vForward )
	float4 vRight =  vUp.yzxw * vForward.zxyw;
	vRight       += -vUp.zxyw * vForward.yzxw;

	
	// Put the light in tangent space.
	float4 vToLight = g_vLightPosition - v.vPos;
	float4 vTangentSpaceLight = vRight*vToLight.x + vUp*vToLight.y + vForward*vToLight.z;

	// Output texcoord 1 holds the normalized transformed light direction.
	o.vTangentSpaceLightDir = normalize( vTangentSpaceLight ) * 0.5 + 0.5; // make it 0-1 for the pixel shader
	
	
	// Handle oversaturation here. The shader code already scaled the light color so its max value is 1,
	// so if our intensity/distance scale is > 1, then all we need to do is use the light color.
	float flTransposedLenSqr = dot( vTangentSpaceLight, vTangentSpaceLight );
	float flScaledIntensity = g_flLightIntensity / flTransposedLenSqr;
	if ( flScaledIntensity > 1 )
	{
		o.vDirLightScale.xyz = g_vLightColor;
	}
	else
	{
		o.vDirLightScale.xyz = g_vLightColor * flScaledIntensity;
	}
	
	// Alpha comes right from the vertex color.
	o.vDirLightScale.a = v.vAmbientColor.a;
	return o;
}

sdk_particle.cpp

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $Header: $
// $NoKeywords: $
//=============================================================================//

#include "BaseVSShader.h"
#include "sdk_particle_vs11.inc"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

BEGIN_VS_SHADER( SDK_Particle, 
			  "Help for SDK_Particle" )
			   
	BEGIN_SHADER_PARAMS
		SHADER_PARAM( USINGPIXELSHADER, SHADER_PARAM_TYPE_BOOL, "0", "Tells to client code whether the shader is using DX8 vertex/pixel shaders or not" )
		SHADER_PARAM( BUMPMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/BaseTexture", "base texture" )
		SHADER_PARAM( LIGHTS, SHADER_PARAM_TYPE_FOURCC, "", "array of lights" )
		SHADER_PARAM( LIGHT_POSITION, SHADER_PARAM_TYPE_VEC3, "0 0 0", "This is the directional light position." )
		SHADER_PARAM( LIGHT_COLOR, SHADER_PARAM_TYPE_VEC3, "1 1 1", "This is the directional light color." )
	END_SHADER_PARAMS

	bool UsePixelShaders( IMaterialVar **params ) const
	{
		return params[BUMPMAP]->IsDefined() && g_pHardwareConfig->SupportsVertexAndPixelShaders();
	}

	SHADER_INIT
	{
		// If this would return false, then we should have fallen back to the DX6 one.
		Assert( UsePixelShaders( params ) );

		params[USINGPIXELSHADER]->SetIntValue( true );
		LoadBumpMap( BUMPMAP );
	}

	SHADER_FALLBACK
	{
		// If their hardware doesn't support pixel shaders, or if there is 
		// no bump map specified in the materal, then fall back to a simple shader.
		if( !UsePixelShaders(params) )
		{
			return "UnlitGeneric_DX6";
		}
		return 0;
	}

	SHADER_DRAW
	{
		SHADOW_STATE
		{
			pShaderShadow->EnableTexture( SHADER_TEXTURE_STAGE0, true );
			
			int tCoordDimensions[] = {2};
			pShaderShadow->VertexShaderVertexFormat( 
				VERTEX_POSITION | VERTEX_COLOR, 1, tCoordDimensions, 0, 0 );

			pShaderShadow->EnableBlending( true );
			pShaderShadow->BlendFunc( SHADER_BLEND_SRC_ALPHA, SHADER_BLEND_ONE_MINUS_SRC_ALPHA );
			pShaderShadow->EnableDepthWrites( false );
			
			sdk_particle_vs11_Static_Index vshIndex;
			pShaderShadow->SetVertexShader( "sdk_particle_vs11", vshIndex.GetIndex() );

			pShaderShadow->SetPixelShader( "sdk_particle_ps11" );
			FogToFogColor();
		}
		DYNAMIC_STATE
		{
			BindTexture( SHADER_TEXTURE_STAGE0, BUMPMAP );

			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, params[LIGHT_POSITION]->GetVecValue() );
			
			// Separate the light color into something that has a max value of 1 and a scale
			// so the vertex shader can determine if it's going to overflow the color and scale back
			// if it needs to.
			//
			// (It does this by seeing if the intensity*1/distSqr is > 1. If so, then it scales it so
			// it is equal to 1).
			const float *f = params[LIGHT_COLOR]->GetVecValue();
			Vector vLightColor( f[0], f[1], f[2] );
			float flScale = max( vLightColor.x, max( vLightColor.y, vLightColor.z ) );
			if ( flScale < 0.01f )
				flScale = 0.01f;
			float vScaleVec[3] = { flScale, flScale, flScale };
			vLightColor /= flScale;

			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, vLightColor.Base() );
			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, vScaleVec );

			// Compute the vertex shader index.
			sdk_particle_vs11_Dynamic_Index vshIndex;
			vshIndex.SetFOGTYPE( s_pShaderAPI->GetSceneFogMode() == MATERIAL_FOG_LINEAR_BELOW_FOG_Z );
			s_pShaderAPI->SetVertexShaderIndex( vshIndex.GetIndex() );
		}
		Draw();
	}
END_SHADER