public bool enableTonemap = true ;
public float exposure = 0 ;
public bool useSinglePassLightLoop = true ;
}
DebugParameters m_DebugParameters = new DebugParameters ( ) ;
ShadowRenderPass m_ShadowPass ;
public const int k_MaxDirectionalLightsOnSCreen = 3 ;
public const int k_MaxPunctualLightsOnSCreen = 5 1 2 ;
public const int k_MaxAreaLightsOnSCreen = 1 2 8 ;
public const int k_MaxEnvLightsOnSCreen = 6 4 ;
public const int k_MaxShadowOnScreen = 1 6 ;
public const int k_MaxCascadeCount = 4 ; //Should be not less than m_Settings.directionalLightCascadeCount;
[SerializeField]
TextureSettings m_TextureSettings = TextureSettings . Default ;
RenderTargetIdentifier m_CameraDepthBufferRT ;
RenderTargetIdentifier m_VelocityBufferRT ;
RenderTargetIdentifier m_DistortionBufferRT ;
public class LightList
{
public List < DirectionalLightData > directionalLights ;
public List < DirectionalShadowData > directionalShadows ;
public List < LightData > punctualLights ;
public List < PunctualShadowData > punctualShadows ;
public List < LightData > areaLights ;
public List < EnvLightData > envLights ;
public Vector4 [ ] directionalShadowSplitSphereSqr ;
// Index mapping list to go from GPU lights (above) to CPU light (in cullResult)
public List < int > directionalCullIndices ;
public List < int > punctualCullIndices ;
public List < int > areaCullIndices ;
public List < int > envCullIndices ;
public void Clear ( )
{
directionalLights . Clear ( ) ;
directionalShadows . Clear ( ) ;
punctualLights . Clear ( ) ;
punctualShadows . Clear ( ) ;
areaLights . Clear ( ) ;
envLights . Clear ( ) ;
directionalCullIndices . Clear ( ) ;
punctualCullIndices . Clear ( ) ;
areaCullIndices . Clear ( ) ;
envCullIndices . Clear ( ) ;
}
public void Allocate ( )
{
directionalLights = new List < DirectionalLightData > ( ) ;
punctualLights = new List < LightData > ( ) ;
areaLights = new List < LightData > ( ) ;
envLights = new List < EnvLightData > ( ) ;
punctualShadows = new List < PunctualShadowData > ( ) ;
directionalShadows = new List < DirectionalShadowData > ( ) ;
directionalShadowSplitSphereSqr = new Vector4 [ k_MaxCascadeCount ] ;
directionalCullIndices = new List < int > ( ) ;
punctualCullIndices = new List < int > ( ) ;
areaCullIndices = new List < int > ( ) ;
envCullIndices = new List < int > ( ) ;
}
}
LightList m_lightList ;
// TODO: Find a way to automatically create/iterate through lightloop
// This must be init externally else The value can't be set in the inspector... (as it will recreate the class with default value)
SinglePass . LightLoop m_SinglePassLightLoop = new SinglePass . LightLoop ( ) ;
TilePass . LightLoop m_TilePassLightLoop = new TilePass . LightLoop ( ) ;
public TilePass . LightLoop tilePassLightLoop
// This must be allocate outside of Rebuild() else the option in the class can't be set in the inspector (as it will in this case recreate the class with default value)
BaseLightLoop m_lightLoop = new TilePass . LightLoop ( ) ;
public BaseLightLoop lightLoop
get { return m_TilePassLightLoop ; }
get { return m_lightLoop ; }
TextureCacheCubemap m_CubeReflTexArray ;
TextureCache2D m_CookieTexArray ;
TextureCacheCubemap m_CubeCookieTexArray ;
public void OnValidate ( )
{
m_DistortionBufferRT = new RenderTargetIdentifier ( m_DistortionBuffer ) ;
m_LitRenderLoop . Rebuild ( ) ;
m_CookieTexArray = new TextureCache2D ( ) ;
m_CookieTexArray . AllocTextureArray ( 8 , m_TextureSettings . spotCookieSize , m_TextureSettings . spotCookieSize , TextureFormat . RGBA32 , true ) ;
m_CubeCookieTexArray = new TextureCacheCubemap ( ) ;
m_CubeCookieTexArray . AllocTextureArray ( 4 , m_TextureSettings . pointCookieSize , TextureFormat . RGBA32 , true ) ;
m_CubeReflTexArray = new TextureCacheCubemap ( ) ;
m_CubeReflTexArray . AllocTextureArray ( 3 2 , m_TextureSettings . reflectionCubemapSize , TextureFormat . BC6H , true ) ;
// Init various light loop
m_SinglePassLightLoop . Rebuild ( ) ;
tilePassLightLoop . Rebuild ( ) ;
m_lightList = new LightList ( ) ;
m_lightList . Allocate ( ) ;
m_lightLoop . Rebuild ( m_TextureSettings ) ;
m_Dirty = false ;
}
public override void Cleanup ( )
{
m_LitRenderLoop . Cleanup ( ) ;
m_SinglePassLightLoop . Cleanup ( ) ;
m_TilePassLightLoop . Cleanup ( ) ;
m_lightLoop . Cleanup ( ) ;
if ( m_CubeReflTexArray ! = null )
{
m_CubeReflTexArray . Release ( ) ;
m_CubeReflTexArray = null ;
}
if ( m_CookieTexArray ! = null )
{
m_CookieTexArray . Release ( ) ;
m_CookieTexArray = null ;
}
if ( m_CubeCookieTexArray ! = null )
{
m_CubeCookieTexArray . Release ( ) ;
m_CubeCookieTexArray = null ;
}
if ( m_SkyRenderer ! = null )
{
m_SkyRenderer . Cleanup ( ) ;
#endif
}
void NewFrame ( )
{
m_CookieTexArray . NewFrame ( ) ;
m_CubeCookieTexArray . NewFrame ( ) ;
m_CubeReflTexArray . NewFrame ( ) ;
}
// We clear only the depth buffer, no need to clear the various color buffer as we overwrite them.
// Clear depth/stencil and init buffers
// We clear only the depth buffer, no need to clear the various color buffer as we overwrite them.
// Clear depth/stencil and init buffers
cmd . name = "" ;
cmd . name = "" ;
// Init buffer
// With scriptable render loop we must allocate ourself depth and color buffer (We must be independent of backbuffer for now, hope to fix that later).
// TEMP: As we are in development and have not all the setup pass we still clear the color in emissive buffer and gbuffer, but this will be removed later.
// Clear HDR target
using ( new Utilities . ProfilingSample ( "Clear HDR target" , renderLoop ) )
using ( new Utilities . ProfilingSample ( "Clear HDR target" , renderLoop ) )
Utilities . SetRenderTarget ( renderLoop , m_CameraColorBufferRT , m_CameraDepthBufferRT , ClearFlag . ClearColor , Color . black ) ;
Utilities . SetRenderTarget ( renderLoop , m_CameraColorBufferRT , m_CameraDepthBufferRT , ClearFlag . ClearColor , Color . black ) ;
using ( new Utilities . ProfilingSample ( "Clear GBuffer" , renderLoop ) )
using ( new Utilities . ProfilingSample ( "Clear GBuffer" , renderLoop ) )
Utilities . SetRenderTarget ( renderLoop , m_gbufferManager . GetGBuffers ( ) , m_CameraDepthBufferRT , ClearFlag . ClearColor , Color . black ) ;
Utilities . SetRenderTarget ( renderLoop , m_gbufferManager . GetGBuffers ( ) , m_CameraDepthBufferRT , ClearFlag . ClearColor , Color . black ) ;
}
// END TEMP
if ( debugParameters . useDepthPrepass )
return ;
using ( new Utilities . ProfilingSample ( "Depth Prepass" , renderLoop ) )
using ( new Utilities . ProfilingSample ( "Forward opaque depth" , renderLoop ) )
// or use the new MAterial.SetPassEnable ?
Utilities . SetRenderTarget ( renderLoop , m_CameraDepthBufferRT ) ;
RenderOpaqueRenderList ( cull , camera , renderLoop , "DepthOnly" ) ;
}
// Bind material data
m_LitRenderLoop . Bind ( ) ;
if ( debugParameters . useSinglePassLightLoop )
{
m_SinglePassLightLoop . RenderDeferredLighting ( camera , renderLoop , m_CameraColorBuffer ) ;
}
else
{
tilePassLightLoop . RenderDeferredLighting ( camera , renderLoop , m_CameraColorBufferRT ) ;
}
m_lightLoop . RenderDeferredLighting ( camera , renderLoop , m_CameraColorBuffer ) ;
}
void RenderSky ( Camera camera , RenderLoop renderLoop )
void RenderForward ( CullResults cullResults , Camera camera , RenderLoop renderLoop )
void RenderForward ( CullResults cullResults , Camera camera , RenderLoop renderLoop , bool renderOpaque )
// TODO: Currently we can't render opaque object forward when deferred is enabled
// miss option
if ( ! debugParameters . useForwardRenderingOnly & & renderOpaque )
return ;
using ( new Utilities . ProfilingSample ( "Forward Pass" , renderLoop ) )
{
// Bind material data
if ( debugParameters . useForwardRenderingOnly )
m_lightLoop . RenderForward ( camera , renderLoop , renderOpaque ) ;
if ( renderOpaque )
RenderTransparentRenderList ( cullResults , camera , renderLoop , "Forward" , Utilities . kRendererConfigurationBakedLighting ) ;
else
{
RenderTransparentRenderList ( cullResults , camera , renderLoop , "Forward" , Utilities . kRendererConfigurationBakedLighting ) ;
}
}
}
}
}
void PrepareLightsForGPU ( CullResults cullResults , Camera camera , ref ShadowOutput shadowOutput , ref LightList lightList )
void PrepareLightsForGPU ( CullResults cullResults , Camera camera , ref ShadowOutput shadowOutput )
lightList . Clear ( ) ;
for ( int lightIndex = 0 , numLights = cullResults . visibleLights . Length ; lightIndex < numLights ; + + lightIndex )
{
var light = cullResults . visibleLights [ lightIndex ] ;
// We only process light with additional data
var additionalData = light . light . GetComponent < AdditionalLightData > ( ) ;
if ( additionalData = = null )
{
Debug . LogWarning ( "Light entity detected without additional data, will not be taken into account " + light . light . name ) ;
continue ;
}
// Linear intensity calculation (different Unity 5.5)
var lightColorR = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . r ) ;
var lightColorG = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . g ) ;
var lightColorB = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . b ) ;
if ( light . lightType = = LightType . Directional )
{
if ( lightList . directionalLights . Count > = k_MaxDirectionalLightsOnSCreen )
continue ;
var directionalLightData = new DirectionalLightData ( ) ;
// Light direction for directional and is opposite to the forward direction
directionalLightData . direction = - light . light . transform . forward ;
directionalLightData . up = light . light . transform . up ;
directionalLightData . right = light . light . transform . right ;
directionalLightData . positionWS = light . light . transform . position ;
directionalLightData . color = new Vector3 ( lightColorR , lightColorG , lightColorB ) ;
directionalLightData . diffuseScale = additionalData . affectDiffuse ? 1.0f : 0.0f ;
directionalLightData . specularScale = additionalData . affectSpecular ? 1.0f : 0.0f ;
directionalLightData . invScaleX = 1.0f / light . light . transform . localScale . x ;
directionalLightData . invScaleY = 1.0f / light . light . transform . localScale . y ;
directionalLightData . cosAngle = 0.0f ;
directionalLightData . sinAngle = 0.0f ;
directionalLightData . shadowIndex = - 1 ;
directionalLightData . cookieIndex = - 1 ;
if ( light . light . cookie ! = null )
{
directionalLightData . tileCookie = ( light . light . cookie . wrapMode = = TextureWrapMode . Repeat ) ;
directionalLightData . cookieIndex = m_CookieTexArray . FetchSlice ( light . light . cookie ) ;
}
bool hasDirectionalShadows = light . light . shadows ! = LightShadows . None & & shadowOutput . GetShadowSliceCountLightIndex ( lightIndex ) ! = 0 ;
bool hasDirectionalNotReachMaxLimit = lightList . directionalShadows . Count = = 0 ; // Only one cascade shadow allowed
if ( hasDirectionalShadows & & hasDirectionalNotReachMaxLimit ) // Note < MaxShadows should be check at shadowOutput creation
{
// When we have a point light, we assumed that there is 6 consecutive PunctualShadowData
directionalLightData . shadowIndex = 0 ;
for ( int sliceIndex = 0 ; sliceIndex < shadowOutput . GetShadowSliceCountLightIndex ( lightIndex ) ; + + sliceIndex )
{
DirectionalShadowData directionalShadowData = new DirectionalShadowData ( ) ;
int shadowSliceIndex = shadowOutput . GetShadowSliceIndex ( lightIndex , sliceIndex ) ;
directionalShadowData . worldToShadow = shadowOutput . shadowSlices [ shadowSliceIndex ] . shadowTransform . transpose ; // Transpose for hlsl reading ?
directionalShadowData . bias = light . light . shadowBias ;
lightList . directionalShadows . Add ( directionalShadowData ) ;
}
// Fill split information for shaders
for ( int s = 0 ; s < k_MaxCascadeCount ; + + s )
{
lightList . directionalShadowSplitSphereSqr [ s ] = shadowOutput . directionalShadowSplitSphereSqr [ s ] ;
}
}
lightList . directionalLights . Add ( directionalLightData ) ;
lightList . directionalCullIndices . Add ( lightIndex ) ;
continue ;
}
// Note: LightType.Area is offline only, use for baking, no need to test it
var lightData = new LightData ( ) ;
// Test whether we should treat this punctual light as an area light.
// It's a temporary hack until the proper UI support is added.
if ( additionalData . archetype ! = LightArchetype . Punctual )
{
// Early out if we reach the maximum
if ( lightList . areaLights . Count > = k_MaxAreaLightsOnSCreen )
continue ;
if ( additionalData . archetype = = LightArchetype . Rectangle )
{
lightData . lightType = GPULightType . Rectangle ;
}
else
{
lightData . lightType = GPULightType . Line ;
}
}
else
{
if ( lightList . punctualLights . Count > = k_MaxPunctualLightsOnSCreen )
continue ;
switch ( light . lightType )
{
case LightType . Directional : lightData . lightType = GPULightType . Directional ; break ;
case LightType . Spot : lightData . lightType = GPULightType . Spot ; break ;
case LightType . Point : lightData . lightType = GPULightType . Point ; break ;
}
}
lightData . positionWS = light . light . transform . position ;
lightData . invSqrAttenuationRadius = 1.0f / ( light . range * light . range ) ;
lightData . color = new Vector3 ( lightColorR , lightColorG , lightColorB ) ;
lightData . forward = light . light . transform . forward ; // Note: Light direction is oriented backward (-Z)
lightData . up = light . light . transform . up ;
lightData . right = light . light . transform . right ;
if ( lightData . lightType = = GPULightType . Spot )
{
var spotAngle = light . spotAngle ;
var innerConePercent = additionalData . GetInnerSpotPercent01 ( ) ;
var cosSpotOuterHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ;
var sinSpotOuterHalfAngle = Mathf . Sqrt ( 1.0f - cosSpotOuterHalfAngle * cosSpotOuterHalfAngle ) ;
var cosSpotInnerHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * innerConePercent * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ; // inner cone
var val = Mathf . Max ( 0.001f , ( cosSpotInnerHalfAngle - cosSpotOuterHalfAngle ) ) ;
lightData . angleScale = 1.0f / val ;
lightData . angleOffset = - cosSpotOuterHalfAngle * lightData . angleScale ;
// TODO: find a proper place to store the cotangent.
lightData . size . x = cosSpotOuterHalfAngle / sinSpotOuterHalfAngle ;
}
else
{
// 1.0f, 2.0f are neutral value allowing GetAngleAnttenuation in shader code to return 1.0
lightData . angleScale = 1.0f ;
lightData . angleOffset = 2.0f ;
}
lightData . diffuseScale = additionalData . affectDiffuse ? 1.0f : 0.0f ;
lightData . specularScale = additionalData . affectSpecular ? 1.0f : 0.0f ;
lightData . shadowDimmer = additionalData . shadowDimmer ;
lightData . IESIndex = - 1 ;
lightData . cookieIndex = - 1 ;
lightData . shadowIndex = - 1 ;
if ( light . light . cookie ! = null )
{
// TODO: add texture atlas support for cookie textures.
switch ( light . lightType )
{
case LightType . Spot :
lightData . cookieIndex = m_CookieTexArray . FetchSlice ( light . light . cookie ) ;
break ;
case LightType . Point :
lightData . cookieIndex = m_CubeCookieTexArray . FetchSlice ( light . light . cookie ) ;
break ;
}
}
// Setup shadow data arrays
bool hasShadows = light . light . shadows ! = LightShadows . None & & shadowOutput . GetShadowSliceCountLightIndex ( lightIndex ) ! = 0 ;
bool hasNotReachMaxLimit = lightList . punctualShadows . Count + ( lightData . lightType = = GPULightType . Point ? 6 : 1 ) < = k_MaxShadowOnScreen ;
if ( hasShadows & & hasNotReachMaxLimit ) // Note < MaxShadows should be check at shadowOutput creation
{
// When we have a point light, we assumed that there is 6 consecutive PunctualShadowData
lightData . shadowIndex = lightList . punctualShadows . Count ;
for ( int sliceIndex = 0 ; sliceIndex < shadowOutput . GetShadowSliceCountLightIndex ( lightIndex ) ; + + sliceIndex )
{
PunctualShadowData punctualShadowData = new PunctualShadowData ( ) ;
int shadowSliceIndex = shadowOutput . GetShadowSliceIndex ( lightIndex , sliceIndex ) ;
punctualShadowData . worldToShadow = shadowOutput . shadowSlices [ shadowSliceIndex ] . shadowTransform . transpose ; // Transpose for hlsl reading ?
punctualShadowData . lightType = lightData . lightType ;
punctualShadowData . bias = light . light . shadowBias ;
lightList . punctualShadows . Add ( punctualShadowData ) ;
}
}
if ( additionalData . archetype = = LightArchetype . Punctual )
{
lightList . punctualLights . Add ( lightData ) ;
lightList . punctualCullIndices . Add ( lightIndex ) ;
}
else
{
lightData . twoSided = additionalData . isDoubleSided ;
lightData . size = new Vector2 ( additionalData . areaLightLength ,
additionalData . areaLightWidth ) ;
// Area and line lights are both currently stored as area lights on the GPU.
lightList . areaLights . Add ( lightData ) ;
lightList . areaCullIndices . Add ( lightIndex ) ;
}
}
for ( int probeIndex = 0 , numProbes = cullResults . visibleReflectionProbes . Length ; probeIndex < numProbes ; probeIndex + + )
{
var probe = cullResults . visibleReflectionProbes [ probeIndex ] ;
// If probe have not been rendered discard
if ( probe . texture = = null )
continue ;
if ( lightList . envLights . Count > = k_MaxEnvLightsOnSCreen )
continue ;
var envLightData = new EnvLightData ( ) ;
// CAUTION: localToWorld is the transform for the widget of the reflection probe. i.e the world position of the point use to do the cubemap capture (mean it include the local offset)
envLightData . positionWS = probe . localToWorld . GetColumn ( 3 ) ;
envLightData . envShapeType = EnvShapeType . None ;
// TODO: Support sphere in the interface
if ( probe . boxProjection ! = 0 )
{
envLightData . envShapeType = EnvShapeType . Box ;
}
// remove scale from the matrix (Scale in this matrix is use to scale the widget)
envLightData . right = probe . localToWorld . GetColumn ( 0 ) ;
envLightData . right . Normalize ( ) ;
envLightData . up = probe . localToWorld . GetColumn ( 1 ) ;
envLightData . up . Normalize ( ) ;
envLightData . forward = probe . localToWorld . GetColumn ( 2 ) ;
envLightData . forward . Normalize ( ) ;
// Artists prefer to have blend distance inside the volume!
// So we let the current UI but we assume blendDistance is an inside factor instead
// Blend distance can't be larger than the max radius
// probe.bounds.extents is BoxSize / 2
float maxBlendDist = Mathf . Min ( probe . bounds . extents . x , Mathf . Min ( probe . bounds . extents . y , probe . bounds . extents . z ) ) ;
float blendDistance = Mathf . Min ( maxBlendDist , probe . blendDistance ) ;
envLightData . innerDistance = probe . bounds . extents - new Vector3 ( blendDistance , blendDistance , blendDistance ) ;
envLightData . envIndex = m_CubeReflTexArray . FetchSlice ( probe . texture ) ;
envLightData . offsetLS = probe . center ; // center is misnamed, it is the offset (in local space) from center of the bounding box to the cubemap capture point
envLightData . blendDistance = blendDistance ;
lightList . envLights . Add ( envLightData ) ;
lightList . envCullIndices . Add ( probeIndex ) ;
}
if ( debugParameters . useSinglePassLightLoop )
{
m_SinglePassLightLoop . PrepareLightsForGPU ( cullResults , camera , m_lightList ) ;
}
else
{
tilePassLightLoop . PrepareLightsForGPU ( cullResults , camera , m_lightList ) ;
}
m_lightLoop . PrepareLightsForGPU ( cullResults , camera , ref shadowOutput ) ;
}
void Resize ( Camera camera )
// For now consider we have only one camera that go to this code, the main one.
m_SkyRenderer . Resize ( m_SkyParameters ) ; // TODO: Also a bad naming, here we just want to realloc texture if skyparameters change (usefull for lookdev)
if ( camera . pixelWidth ! = m_WidthOnRecord | | camera . pixelHeight ! = m_HeightOnRecord | | tilePassL ightLoop. NeedResize ( ) )
if ( camera . pixelWidth ! = m_WidthOnRecord | | camera . pixelHeight ! = m_HeightOnRecord | | m_l ightLoop. NeedResize ( ) )
tilePassL ightLoop. ReleaseResolutionDependentBuffers ( ) ;
m_l ightLoop. ReleaseResolutionDependentBuffers ( ) ;
tilePassL ightLoop. AllocResolutionDependentBuffers ( camera . pixelWidth , camera . pixelHeight ) ;
m_l ightLoop. AllocResolutionDependentBuffers ( camera . pixelWidth , camera . pixelHeight ) ;
// update recorded window resolution
m_WidthOnRecord = camera . pixelWidth ;
public void PushGlobalParams ( Camera camera , RenderLoop renderLoop , HDRenderLoop . LightList lightList )
public void PushGlobalParams ( Camera camera , RenderLoop renderLoop )
Shader . SetGlobalTexture ( "_CookieTextures" , m_CookieTexArray . GetTexCache ( ) ) ;
Shader . SetGlobalTexture ( "_CookieCubeTextures" , m_CubeCookieTexArray . GetTexCache ( ) ) ;
Shader . SetGlobalTexture ( "_EnvTextures" , m_CubeReflTexArray . GetTexCache ( ) ) ;
if ( m_SkyRenderer . IsSkyValid ( m_SkyParameters ) )
{
m_SkyRenderer . SetGlobalSkyTexture ( ) ;
Shader . SetGlobalInt ( "_EnvLightSkyEnabled" , 0 ) ;
}
if ( debugParameters . useSinglePassLightLoop )
{
m_SinglePassLightLoop . PushGlobalParams ( camera , renderLoop , lightList ) ;
}
else
{
tilePassLightLoop . PushGlobalParams ( camera , renderLoop , lightList ) ;
}
m_lightLoop . PushGlobalParams ( camera , renderLoop ) ;
}
public override void Render ( Camera [ ] cameras , RenderLoop renderLoop )
}
// Do anything we need to do upon a new frame.
NewFrame ( ) ;
m_lightLoop . NewFrame ( ) ;
// Set Frame constant buffer
// TODO...
RenderDepthPrepass ( cullResults , camera , renderLoop ) ;
RenderGBuffer ( cullResults , camera , renderLoop ) ;
RenderGBuffer ( cullResults , camera , renderLoop ) ;
// For tile lighting with forward opaque
// Forward opaque with deferred tile require that we fill the depth buffer
// correctly to build the light list.
// TODO: avoid double lighting by tagging stencil or gbuffer that we must not lit.
// TODO: ask Morten why this pass is not before GBuffer ? Will make more sense and avoid
// to do gbuffer pass on unseen mesh.
// TODO: how do we select only the object that must be render forward ?
// this is all object with gbuffer pass disabled ?
//RenderForwardOpaqueDepth(cullResults, camera, renderLoop);
if ( debugParameters . debugViewMaterial ! = 0 )
using ( new Utilities . ProfilingSample ( "Build Light list" , renderLoop ) )
{
PrepareLightsForGPU ( cullResults , camera , ref shadows , ref m_lightList ) ;
if ( ! debugParameters . useSinglePassLightLoop )
tilePassLightLoop . BuildGPULightLists ( camera , renderLoop , m_lightList , m_CameraDepthBufferRT ) ;
m_lightLoop . PrepareLightsForGPU ( cullResults , camera , ref shadows ) ;
m_lightLoop . BuildGPULightLists ( camera , renderLoop , m_CameraDepthBufferRT ) ;
PushGlobalParams ( camera , renderLoop , m_lightList ) ;
PushGlobalParams ( camera , renderLoop ) ;
RenderForward ( cullResults , camera , renderLoop , true ) ;
RenderForward ( cullResults , camera , renderLoop ) ; // Note: We want to render forward opaque before RenderSky, then RenderTransparent - can only do that once we have material.SetPass feature...
RenderForward ( cullResults , camera , renderLoop , false ) ;
RenderForwardUnlit ( cullResults , camera , renderLoop ) ;
RenderVelocity ( cullResults , camera , renderLoop ) ; // Note we may have to render velocity earlier if we do temporalAO, temporal volumetric etc... Mean we will not take into account forward opaque in case of deferred rendering ?