using UnityEngine ;
using System.Collections ;
using UnityEngine.Rendering ;
using System.Collections.Generic ;
using System ;
// This HDRenderLoop assume linear lighting. Don't work with gamma.
public class HDRenderLoop : ScriptableRenderLoop
{
private static string m _HDRenderLoopPath = "Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.asset" ;
private con st string k _HDRenderLoopPath = "Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.asset" ;
// Must be in sync with DebugViewMaterial.hlsl
public enum DebugViewVaryingMode
static void CreateHDRenderLoop ( )
{
var instance = ScriptableObject . CreateInstance < HDRenderLoop > ( ) ;
UnityEditor . AssetDatabase . CreateAsset ( instance , m _HDRenderLoopPath) ;
UnityEditor . AssetDatabase . CreateAsset ( instance , k _HDRenderLoopPath) ;
}
#endif
public const int MaxGbuffer = 8 ;
public void SetBufferDescription ( int index , string stringID , RenderTextureFormat inFormat , RenderTextureReadWrite inSRGBWrite )
public void SetBufferDescription ( int index , string stringId , RenderTextureFormat inFormat , RenderTextureReadWrite inSRGBWrite )
IDs [ index ] = Shader . PropertyToID ( stringID ) ;
IDs [ index ] = Shader . PropertyToID ( stringId ) ;
RTIDs [ index ] = new RenderTargetIdentifier ( IDs [ index ] ) ;
formats [ index ] = inFormat ;
sRGBWrites [ index ] = inSRGBWrite ;
Material m_FinalPassMaterial ;
// TODO: Find a way to automatically create/iterate through these kind of class
Lit . RenderLoop m_l itRenderLoop ;
Lit . RenderLoop m_L itRenderLoop ;
// Debug
Material m_DebugViewMaterialGBuffer ;
Material CreateEngineMaterial ( string shaderPath )
{
Material mat = new Material ( Shader . Find ( shaderPath ) as Shader ) ;
mat . hideFlags = HideFlags . HideAndDontSave ;
var mat = new Material ( Shader . Find ( shaderPath ) as Shader )
{
hideFlags = HideFlags . HideAndDontSave
} ;
return mat ;
}
m_cubeReflTexArray . AllocTextureArray ( 3 2 , ( int ) m_TextureSettings . reflectionCubemapSize , TextureFormat . BC6H , true ) ;
// Init Lit material buffer - GBuffer and init
m_l itRenderLoop = new Lit . RenderLoop ( ) ; // Our object can be garbacge collected, so need to be allocate here
m_L itRenderLoop = new Lit . RenderLoop ( ) ; // Our object can be garbacge collected, so need to be allocate here
m_gbufferManager . gbufferCount = m_l itRenderLoop . GetGBufferCount ( ) ;
m_gbufferManager . gbufferCount = m_L itRenderLoop . GetGBufferCount ( ) ;
m_gbufferManager . SetBufferDescription ( gbufferIndex , "_CameraGBufferTexture" + gbufferIndex , m_l itRenderLoop . RTFormat [ gbufferIndex ] , m_l itRenderLoop . RTReadWrite [ gbufferIndex ] ) ;
m_gbufferManager . SetBufferDescription ( gbufferIndex , "_CameraGBufferTexture" + gbufferIndex , m_L itRenderLoop . RTFormat [ gbufferIndex ] , m_L itRenderLoop . RTReadWrite [ gbufferIndex ] ) ;
m_l itRenderLoop . Rebuild ( ) ;
m_L itRenderLoop . Rebuild ( ) ;
m_l itRenderLoop . OnDisable ( ) ;
m_L itRenderLoop . OnDisable ( ) ;
s_punctualLightList . Release ( ) ;
s_envLightList . Release ( ) ;
if ( ! debugParameters . displayTransparentObjects )
return ;
DrawRendererSettings settings = new DrawRendererSettings ( cull , camera , new ShaderPassName ( passName ) ) ;
settings . rendererConfiguration = RendererConfiguration . PerObjectLightProbe | RendererConfiguration . PerObjectReflectionProbes ;
settings . sorting . sortOptions = SortOptions . SortByMaterialThenMesh ;
var settings = new DrawRendererSettings ( cull , camera , new ShaderPassName ( passName ) )
{
rendererConfiguration = RendererConfiguration . PerObjectLightProbe | RendererConfiguration . PerObjectReflectionProbes ,
sorting = { sortOptions = SortOptions . SortByMaterialThenMesh }
} ;
settings . inputCullingOptions . SetQueuesTransparent ( ) ;
renderLoop . DrawRenderers ( ref settings ) ;
}
// setup GBuffer for rendering
var cmd = new CommandBuffer ( ) ;
cmd . name = "GBuffer Pass" ;
var cmd = new CommandBuffer { name = "GBuffer Pass" } ;
cmd . SetRenderTarget ( m_gbufferManager . GetGBuffers ( cmd ) , new RenderTargetIdentifier ( s_CameraDepthBuffer ) ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
{
// Render Opaque forward
{
var cmd = new CommandBuffer ( ) ;
cmd . name = "DebugView Material Mode Pass" ;
var cmd = new CommandBuffer { name = "DebugView Material Mode Pass" } ;
cmd . SetRenderTarget ( new RenderTargetIdentifier ( s_CameraColorBuffer ) , new RenderTargetIdentifier ( s_CameraDepthBuffer ) ) ;
cmd . ClearRenderTarget ( true , true , new Color ( 0 , 0 , 0 , 0 ) ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
// m_gbufferManager.BindBuffers(m_DeferredMaterial);
// TODO: Bind depth textures
var cmd = new CommandBuffer ( ) ;
cmd . name = "GBuffer Debug Pass" ;
var cmd = new CommandBuffer { name = "GBuffer Debug Pass" } ;
cmd . Blit ( null , new RenderTargetIdentifier ( s_CameraColorBuffer ) , m_DebugViewMaterialGBuffer , 0 ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
// Last blit
{
var cmd = new CommandBuffer ( ) ;
cmd . name = "Blit DebugView Material Debug" ;
var cmd = new CommandBuffer { name = "Blit DebugView Material Debug" } ;
cmd . Blit ( s_CameraColorBuffer , BuiltinRenderTextureType . CameraTarget ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
{
// The actual projection matrix used in shaders is actually massaged a bit to work across all platforms
// (different Z value ranges etc.)
Matrix4x4 gpuProj = GL . GetGPUProjectionMatrix ( camera . projectionMatrix , false ) ;
Matrix4x4 gpuVP = gpuProj * camera . worldToCameraMatrix ;
var gpuProj = GL . GetGPUProjectionMatrix ( camera . projectionMatrix , false ) ;
var gpuVP = gpuProj * camera . worldToCameraMatrix ;
return gpuVP ;
}
Vector4 screenSize = new Vector4 ( ) ;
screenSize . x = camera . pixelWidth ;
screenSize . y = camera . pixelHeight ;
screenSize . z = 1.0f / camera . pixelWidth ;
screenSize . w = 1.0f / camera . pixelHeight ;
return screenSize ;
return new Vector4 ( camera . pixelWidth , camera . pixelHeight , 1.0f / camera . pixelWidth , 1.0f / camera . pixelHeight ) ;
m_litRenderLoop . Bind ( ) ;
m_LitRenderLoop . Bind ( ) ;
Matrix4x4 invViewProj = GetViewProjectionMatrix ( camera ) . inverse ;
var invViewProj = GetViewProjectionMatrix ( camera ) . inverse ;
Vector4 screenSize = ComputeScreenSize ( camera ) ;
var screenSize = ComputeScreenSize ( camera ) ;
var cmd = new CommandBuffer ( ) ;
cmd . name = "Deferred Ligthing Pass" ;
var cmd = new CommandBuffer { name = "Deferred Ligthing Pass" } ;
cmd . Blit ( null , new RenderTargetIdentifier ( s_CameraColorBuffer ) , m_DeferredMaterial , 0 ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
{
// Bind material data
m_litRenderLoop . Bind ( ) ;
m_LitRenderLoop . Bind ( ) ;
var cmd = new CommandBuffer ( ) ;
cmd . name = "Forward Pass" ;
var cmd = new CommandBuffer { name = "Forward Pass" } ;
cmd . SetRenderTarget ( new RenderTargetIdentifier ( s_CameraColorBuffer ) , new RenderTargetIdentifier ( s_CameraDepthBuffer ) ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
cmd . Dispose ( ) ;
void FinalPass ( RenderLoop renderLoop )
{
// Those could be tweakable for the neutral tonemapper, but in the case of the LookDev we don't need that
const float B lackIn = 0.02f ;
const float W hiteIn = 1 0.0f ;
const float B lackOut = 0.0f ;
const float W hiteOut = 1 0.0f ;
const float W hiteLevel = 5.3f ;
const float W hiteClip = 1 0.0f ;
const float D ialUnits = 2 0.0f ;
const float HalfDialUnits = D ialUnits * 0.5f ;
const float b lackIn = 0.02f ;
const float w hiteIn = 1 0.0f ;
const float b lackOut = 0.0f ;
const float w hiteOut = 1 0.0f ;
const float w hiteLevel = 5.3f ;
const float w hiteClip = 1 0.0f ;
const float d ialUnits = 2 0.0f ;
const float halfDialUnits = d ialUnits * 0.5f ;
Vector4 tonemapCoeff1 = new Vector4 ( ( BlackIn * D ialUnits) + 1.0f , ( BlackOut * H alfDialUnits) + 1.0f , ( WhiteIn / D ialUnits) , ( 1.0f - ( WhiteOut / D ialUnits) ) ) ;
Vector4 tonemapCoeff2 = new Vector4 ( 0.0f , 0.0f , WhiteLevel , WhiteClip / H alfDialUnits) ;
var tonemapCoeff1 = new Vector4 ( ( blackIn * d ialUnits) + 1.0f , ( blackOut * h alfDialUnits) + 1.0f , ( whiteIn / d ialUnits) , ( 1.0f - ( whiteOut / d ialUnits) ) ) ;
var tonemapCoeff2 = new Vector4 ( 0.0f , 0.0f , whiteLevel , whiteClip / h alfDialUnits) ;
m_FinalPassMaterial . SetVector ( "_ToneMapCoeffs1" , tonemapCoeff1 ) ;
m_FinalPassMaterial . SetVector ( "_ToneMapCoeffs2" , tonemapCoeff2 ) ;
CommandBuffe r cmd = new CommandBuffer ( ) ;
cmd . name = "FinalPass" ;
va r cmd = new CommandBuffer { name = "FinalPass" } ;
// Resolve our HDR texture to CameraTarget.
cmd . Blit ( s_CameraColorBuffer , BuiltinRenderTextureType . CameraTarget , m_FinalPassMaterial , 0 ) ;
renderLoop . ExecuteCommandBuffer ( cmd ) ;
void UpdatePunctualLights ( VisibleLight [ ] visibleLights )
{
List < PunctualLightData > lights = new List < PunctualLightData > ( ) ;
var lights = new List < PunctualLightData > ( ) ;
VisibleLight light = visibleLights [ lightIndex ] ;
if ( light . lightType = = LightType . Spot | | light . lightType = = LightType . Point | | light . lightType = = LightType . Directional )
{
PunctualLightData l = new PunctualLightData ( ) ;
var light = visibleLights [ lightIndex ] ;
if ( light . lightType ! = LightType . Spot & & light . lightType ! = LightType . Point & & light . lightType ! = LightType . Directional )
continue ;
if ( light . lightType = = LightType . Directional )
{
l . useDistanceAttenuation = 0.0f ;
// positionWS store Light direction for directional and is opposite to the forward direction
l . positionWS = - light . light . transform . forward ;
l . invSqrAttenuationRadius = 0.0f ;
}
else
{
l . useDistanceAttenuation = 1.0f ;
l . positionWS = light . light . transform . position ;
l . invSqrAttenuationRadius = 1.0f / ( light . range * light . range ) ;
}
var l = new PunctualLightData ( ) ;
// Correct intensity calculation (Different from Unity)
float lightColorR = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . r ) ;
float lightColorG = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . g ) ;
float lightColorB = light . light . intensity * Mathf . GammaToLinearSpace ( light . light . color . b ) ;
if ( light . lightType = = LightType . Directional )
{
l . useDistanceAttenuation = 0.0f ;
// positionWS store Light direction for directional and is opposite to the forward direction
l . positionWS = - light . light . transform . forward ;
l . invSqrAttenuationRadius = 0.0f ;
}
else
{
l . useDistanceAttenuation = 1.0f ;
l . positionWS = light . light . transform . position ;
l . invSqrAttenuationRadius = 1.0f / ( light . range * light . range ) ;
}
l . color . Set ( lightColorR , lightColorG , lightColorB ) ;
// Correct intensity calculation (Different from Unity)
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 ) ;
// Light direction is opposite to the forward direction
l . forward = - light . light . transform . forward ;
// CAUTION: For IES as we inverse forward maybe this will need rotation.
l . up = light . light . transform . up ;
l . right = light . light . transform . right ;
l . color . Set ( lightColorR , lightColorG , lightColorB ) ;
l . diffuseScale = 1.0f ;
l . sp ecular Scale = 1.0f ;
l . shadowDimmer = 1.0f ;
// Light direction is opposite to the forward direction
l . forward = - light . light . transform . forward ;
// CAUTION: For IES as we inverse forward maybe this will need rotation.
l . up = light . light . transform . up ;
l . right = light . light . transform . right ;
if ( light . lightType = = LightType . Spot )
{
float spotAngle = light . light . spotAngle ;
AdditionalLightData additionalLightData = light . light . GetComponent < AdditionalLightData > ( ) ;
float innerConePercent = AdditionalLightData . GetInnerSpotPercent01 ( additionalLightData ) ;
float cosSpotOuterHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ;
float cosSpotInn erHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * innerConePercent * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ; // inner cone
l . diffu seScale = 1.0f ;
l . specularScale = 1.0f ;
l . shadowDimmer = 1.0f ;
float val = Mathf . Max ( 0.001f , ( cosSpotInnerHalfAngle - cosSpotOuterHalfAngle ) ) ;
l . angleScale = 1.0f / val ;
l . angleOffset = - cosSpotOuterHalfAngle * l . angleScale ;
}
else
{
// 1.0f, 2.0f are neutral value allowing GetAngleAnttenuation in shader code to return 1.0
l . angleScale = 1.0f ;
l . angleOffset = 2 .0f ;
}
if ( light . lightType = = LightType . Spot )
{
var spotAngle = light . light . spotAngle ;
var additionalLightData = light . light . GetComponent < AdditionalLightData > ( ) ;
var innerConePercent = AdditionalLightData . GetInnerSpotPercent01 ( additionalLightData ) ;
var cosSpotOut erHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ;
var cosSpotInnerHalfAngle = Mathf . Clamp ( Mathf . Cos ( spotAngle * 0.5f * innerConePercent * Mathf . Deg2Rad ) , 0.0f , 1.0f ) ; // inner cone
lights . Add ( l ) ;
var val = Mathf . Max ( 0.001f , ( cosSpotInnerHalfAngle - cosSpotOuterHalfAngle ) ) ;
l . angleScale = 1.0f / val ;
l . angleOffset = - cosSpotOuterHalfAngle * l . angleScale ;
else
{
// 1.0f, 2.0f are neutral value allowing GetAngleAnttenuation in shader code to return 1.0
l . angleScale = 1 .0f ;
l . angleOffset = 2.0f ;
}
lights . Add ( l ) ;
}
s_punctualLightList . SetData ( lights . ToArray ( ) ) ;
void UpdateReflectionProbes ( VisibleReflectionProbe [ ] activeReflectionProbes )
{
List < EnvLightData > lights = new List < EnvLightData > ( ) ;
var lights = new List < EnvLightData > ( ) ;
VisibleReflectionProbe probe = activeReflectionProbes [ lightIndex ] ;
var probe = activeReflectionProbes [ lightIndex ] ;
EnvLightData l = new EnvLightData ( ) ;
var l = new EnvLightData
{
positionWS = probe . localToWorld . GetColumn ( 3 ) ,
shapeType = EnvShapeType . None
} ;
l . positionWS = probe . localToWorld . GetColumn ( 3 ) ;
l . shapeType = EnvShapeType . None ;
if ( probe . boxProjection ! = 0 )
{
l . shapeType = EnvShapeType . Box ;
public override void Render ( Camera [ ] cameras , RenderLoop renderLoop )
{
if ( ! m_l itRenderLoop . isInit )
if ( ! m_L itRenderLoop . isInit )
m_l itRenderLoop . RenderInit ( renderLoop ) ;
m_L itRenderLoop . RenderInit ( renderLoop ) ;
}
// Do anything we need to do upon a new frame.
// Set camera constant buffer
// TODO...
CullResults cullResults ;
CullingParameters cullingParams ;
if ( ! CullResults . GetCullingParameters ( camera , out cullingParams ) )
continue ;
cullResults = CullResults . Cull ( ref cullingParams , renderLoop ) ;
var cullResults = CullResults . Cull ( ref cullingParams , renderLoop ) ;
//ShadowOutput shadows;
//m_ShadowPass.Render (renderLoop, cullResults, out shadows);
#if UNITY_EDITOR
public override UnityEditor . SupportedRenderingFeatures GetSupportedRenderingFeatures ( )
{
var features = new UnityEditor . SupportedRenderingFeatures ( ) ;
features . reflectionProbe = UnityEditor . SupportedRenderingFeatures . ReflectionProbe . Rotation ;
var features = new UnityEditor . SupportedRenderingFeatures
{
reflectionProbe = UnityEditor . SupportedRenderingFeatures . ReflectionProbe . Rotation
} ;
return features ;
}