public int shadowResolution ;
}
public class LightweightPipeline : RenderPipeline , IComparer < VisibleLight >
public class LightweightPipeline : RenderPipeline
// Max amount of visible lights. This controls the lights constant buffers in shader but not the max shaded lights.
// Lights are set per-object and the max shaded lights for each object are controlled by the max pixel lights in pipeline asset and kMaxVertexLights.
private static readonly int kMaxVisibleLights = 1 6 ;
private static readonly int kMaxVertexLights = 4 ;
private Vector4 [ ] m_LightPositions = new Vector4 [ kMaxVisibleLights ] ;
private Vector4 [ ] m_LightColors = new Vector4 [ kMaxVisibleLights ] ;
private Vector4 [ ] m_LightAttenuations = new Vector4 [ kMaxVisibleLights ] ;
private Vector4 [ ] m_LightSpotDirections = new Vector4 [ kMaxVisibleLights ] ;
// Amount of light indices buffer set per object.
// TODO: Change cullresults to return amount of renderers so we can allocate/reallocate enough buffer data
// As off now allocating a enough buffer to hold a scene that should enough for a small demo/game
private static readonly int kMaxLightIndices = 1 0 2 4 * kMaxVisibleLights ;
private ComputeBuffer m_LightIndexListBuffer ;
private static readonly int kMaxLights = 8 ;
private static readonly int kMaxVertexLights = 4 ;
private int m_ShadowLightIndex = - 1 ;
private readonly int [ ] m_LightTypePriority = new int [ 4 ] { 2 , 1 , 2 , 0 } ; // Spot and Point lights have max priority
private int m_ShadowLightIndex = - 1 ;
private static readonly ShaderPassName m_ForwardBasePassName = new ShaderPassName ( "LightweightForward" ) ;
private Vector4 [ ] m_LightPositions = new Vector4 [ kMaxLights ] ;
private Vector4 [ ] m_LightColors = new Vector4 [ kMaxLights ] ;
private Vector4 [ ] m_LightAttenuations = new Vector4 [ kMaxLights ] ;
private Vector4 [ ] m_LightSpotDirections = new Vector4 [ kMaxLights ] ;
private static readonly ShaderPassName m_ForwardBasePassName = new ShaderPassName ( "LightweightForward" ) ;
public LightweightPipeline ( LightweightPipelineAsset asset )
{
m_Asset = asset ;
m_ShadowMapRTID = new RenderTargetIdentifier ( m_ShadowMapProperty ) ;
Shader . globalRenderPipeline = "LightweightPipeline" ;
// TODO: Change cullresults to return amount of renderers so we can allocate/reallocate enough buffer data
m_LightIndexListBuffer = new ComputeBuffer ( kMaxLightIndices , sizeof ( uint ) ) ;
m_LightIndexListBuffer . Dispose ( ) ;
base . Render ( context , cameras ) ;
base . Render ( context , cameras ) ;
foreach ( Camera camera in cameras )
{
int pixelLightsCount , vertexLightsCount ;
GetMaxSupportedLights ( visibleLights . Length , out pixelLightsCount , out vertexLightsCount ) ;
SortLights ( ref visibleLights , pixelLightsCount ) ;
InitializeMainShadowLightIndex ( visibleLights ) ;
if ( m_ShadowLightIndex > - 1 )
shadowsRendered = RenderShadows ( cull , visibleLights [ m_ShadowLightIndex ] , context ) ;
cmd . Dispose ( ) ;
// Setup light and shadow shader constants
cull . FillLightIndices ( m_LightIndexListBuffer ) ;
SetupLightShaderVariables ( visibleLights , pixelLightsCount , vertexLightsCount , context ) ;
if ( shadowsRendered )
SetupShadowShaderVariables ( context , m_ShadowCasterCascadesCount ) ;
if ( m_Asset . EnableAmbientProbe )
settings . rendererConfiguration | = RendererConfiguration . PerObjectLightProbe ;
settings . rendererConfiguration | = RendererConfiguration . ProvideLightIndices ;
context . DrawRenderers ( ref settings ) ;
private void InitializeLightData ( )
{
for ( int i = 0 ; i < kMaxLights ; + + i )
for ( int i = 0 ; i < kMaxVisible Lights ; + + i )
{
m_LightPositions [ i ] = Vector4 . zero ;
m_LightColors [ i ] = Vector4 . zero ;
private void SetupLightShaderVariables ( VisibleLight [ ] lights , int pixelLightCount , int vertexLightCount , ScriptableRenderContext context )
{
int totalLightCount = pixelLightCount + vertexLightCount ;
for ( int i = 0 ; i < totalLightCount ; + + i )
int maxLights = Math . Min ( kMaxVisibleLights , lights . Length ) ;
for ( int i = 0 ; i < maxLights ; + + i )
{
VisibleLight currLight = lights [ i ] ;
if ( currLight . lightType = = LightType . Directional )
}
else
{
m_LightSpotDirections [ i ] = new Vector4 ( 0.0f , 0.0f , 1.0f , 0.0f ) ;
m_LightSpotDirections [ i ] = new Vector4 ( 0.0f , 0.0f , 1.0f , 0.0f ) ;
m_LightAttenuations [ i ] = new Vector4 ( - 1.0f , 1.0f , quadAtten , rangeSq ) ;
}
}
cmd . SetGlobalVectorArray ( "globalLightColor" , m_LightColors ) ;
cmd . SetGlobalVectorArray ( "globalLightAtten" , m_LightAttenuations ) ;
cmd . SetGlobalVectorArray ( "globalLightSpotDir" , m_LightSpotDirections ) ;
float shadowMinNormalBias = m_Asset . ShadowMinNormalBias ;
float shadowNormalBias = m_Asset . ShadowNormalBias ;
cmd . SetGlobalVector ( "globalLightData" , new Vector4 ( pixelLightCount , totalLightCount , shadowMinNormalBias , shadowNormalBias ) ) ;
cmd . SetGlobalBuffer ( "globalLightIndexList" , m_LightIndexListBuffer ) ;
cmd . SetGlobalVector ( "globalLightData" , new Vector4 ( pixelLightCount , m_ShadowLightIndex , m_Asset . ShadowMinNormalBias , m_Asset . ShadowNormalBias ) ) ;
SetShaderKeywords ( cmd , vertexLightCount > 0 ) ;
context . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
return resolution ;
}
void SetupShadowShaderVariables ( ScriptableRenderContext context , int cascadeCount )
private void SetupShadowShaderVariables ( ScriptableRenderContext context , int cascadeCount )
{
float shadowResolution = m_ShadowSlices [ 0 ] . shadowResolution ;
setupShadow . Dispose ( ) ;
}
void SetShaderKeywords ( CommandBuffer cmd , bool vertexLightSupport )
private void SetShaderKeywords ( CommandBuffer cmd , bool vertexLightSupport )
{
if ( vertexLightSupport )
cmd . EnableShaderKeyword ( "_VERTEX_LIGHTS" ) ;
cmd . DisableShaderKeyword ( "_LIGHT_PROBES_ON" ) ;
}
// Finds main light and main shadow casters and places them in the beginning of array.
// Sort the remaining array based on custom IComparer criteria.
private void SortLights ( ref VisibleLight [ ] lights , int pixelLightsCount )
private void InitializeMainShadowLightIndex ( VisibleLight [ ] lights )
if ( lights . Length = = 0 )
return ;
bool shadowsSupported = m_Asset . CurrShadowType ! = ShadowType . NO_SHADOW & & pixelLightsCount > 0 ;
int mainLightIndex = - 1 ;
float maxIntensity = - 1 ;
VisibleLight currLight = lights [ i ] ;
if ( currLight . lightType = = LightType . Directional )
if ( mainLightIndex = = - 1 | | currLight . light . intensity > lights [ mainLightIndex ] . light . intensity )
mainLightIndex = i ;
if ( shadowsSupported & & ( currLight . light . shadows ! = LightShadows . None ) & & IsSupportedShadowType ( currLight . lightType ) )
// Prefer directional shadows, if not sort by intensity
if ( m_ShadowLightIndex = = - 1 | | currLight . lightType > lights [ m_ShadowLightIndex ] . lightType )
m_ShadowLightIndex = i ;
}
// If supports a single directional light only, main light is main shadow light.
if ( pixelLightsCount = = 1 & & m_ShadowLightIndex > - 1 )
mainLightIndex = m_ShadowLightIndex ;
int startIndex = 0 ;
if ( mainLightIndex > - 1 )
{
SwapLights ( ref lights , 0 , mainLightIndex ) ;
startIndex + + ;
}
if ( mainLightIndex ! = m_ShadowLightIndex & & m_ShadowLightIndex > 0 )
{
SwapLights ( ref lights , 1 , m_ShadowLightIndex ) ;
m_ShadowLightIndex = 1 ;
startIndex + + ;
Light light = lights [ i ] . light ;
if ( light . shadows ! = LightShadows . None & & IsSupportedShadowType ( light . type ) & & light . intensity > maxIntensity )
{
m_ShadowLightIndex = i ;
maxIntensity = light . intensity ;
}
Array . Sort ( lights , startIndex , lights . Length - startIndex , this ) ;
}
private bool IsSupportedShadowType ( LightType type )
private void SwapLights ( ref VisibleLight [ ] lights , int lhsIndex , int rhsIndex )
{
if ( lhsIndex = = rhsIndex )
return ;
VisibleLight temp = lights [ lhsIndex ] ;
lights [ lhsIndex ] = lights [ rhsIndex ] ;
lights [ rhsIndex ] = temp ;
}
// Prioritizes Spot and Point lights by intensity. If any directional light, it will be the main
// light and will not be considered in the computation.
// TODO: Move to a better sorting solution, e.g, prioritize lights per object.
public int Compare ( VisibleLight lhs , VisibleLight rhs )
{
int lhsLightTypePriority = m_LightTypePriority [ ( int ) lhs . lightType ] ;
int rhsLightTypePriority = m_LightTypePriority [ ( int ) rhs . lightType ] ;
if ( lhsLightTypePriority ! = rhsLightTypePriority )
return rhsLightTypePriority - lhsLightTypePriority ;
return ( int ) ( rhs . light . intensity - lhs . light . intensity ) ;
}
}
}