// TODO: Find a way to automatically create/iterate through deferred material
// TODO TO CHECK: SebL I move allocation from Build() to here, but there was a comment "// Our object can be garbage collected, so need to be allocate here", it is still true ?
// Keep these settings safe to recover when leaving the render pipeline
boolpreviousLightsUseLinearIntensity;
boolpreviousLightsUseCCT;
ShadowRenderPassm_ShadowPass;
ShadowOutputm_ShadowsResult=newShadowOutput();
// This must be allocate outside of Build() 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)
// TODO: Find a way to automatically create/iterate through deferred material
// TODO TO CHECK: SebL I move allocation from Build() to here, but there was a comment "// Our object can be garbage collected, so need to be allocate here", it is still true ?
// TODO: Detect if renderdoc just load and force a resize in this case, as often renderdoc require to realloc resource.
// TODO: This is the wrong way to handle resize/allocation. We can have several different camera here, mean that the loop on camera will allocate and deallocate
// the below buffer which is bad. Best is to have a set of buffer for each camera that is persistent and reallocate resource if need
// For now consider we have only one camera that go to this code, the main one.
m_SkyManager.Resize(camera.nearClipPlane,camera.farClipPlane);// TODO: Also a bad naming, here we just want to realloc texture if skyparameters change (usefull for lookdev)
// 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.
// Forward opaque with deferred/cluster 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.
m_LightLoop.BuildGPULightLists(camera,renderContext,m_CameraDepthStencilBufferRT);// TODO: Use async compute here to run light culling during shadow
// END TEMP
PushGlobalParams(hdCamera,renderContext);
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera,renderContext);
RenderDeferredLighting(hdCamera,renderContext);
// We compute subsurface scattering here. Therefore, no objects rendered afterwards will exhibit SSS.
// Currently, there is no efficient way to switch between SRT and MRT for the forward pass;
// therefore, forward-rendered objects do not output split lighting required for the SSS pass.
// For opaque forward we have split rendering in two categories
// Material that are always forward and material that can be deferred or forward depends on render pipeline options (like switch to rendering forward only mode)
// Material that are always forward are unlit and complex (Like Hair) and don't require sorting, so it is ok to split them.
RenderForward(cullResults,camera,renderContext,true);// Render deferred or forward opaque
RenderVelocity(cullResults,camera,renderContext);// 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 ?
// TODO: Check with VFX team.
// Rendering distortion here have off course lot of artifact.
// But resolving at each objects that write in distortion is not possible (need to sort transparent, render those that do not distort, then resolve, then etc...)
// Instead we chose to apply distortion at the end after we cumulate distortion vector and desired blurriness. This
// TODO: Detect if renderdoc just load and force a resize in this case, as often renderdoc require to realloc resource.
// TODO: This is the wrong way to handle resize/allocation. We can have several different camera here, mean that the loop on camera will allocate and deallocate
// the below buffer which is bad. Best is to have a set of buffer for each camera that is persistent and reallocate resource if need
// For now consider we have only one camera that go to this code, the main one.
m_SkyManager.Resize(camera.nearClipPlane,camera.farClipPlane);// TODO: Also a bad naming, here we just want to realloc texture if skyparameters change (usefull for lookdev)
m_lightLoop.BuildGPULightLists(camera,renderContext,m_CameraDepthBufferRT);// TODO: Use async compute here to run light culling during shadow
m_gbufferManager.InitGBuffers(w,h,cmd);
PushGlobalParams(hdCamera,renderContext);
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera,renderContext);
RenderDeferredLighting(hdCamera,renderContext);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
// For opaque forward we have split rendering in two categories
// Material that are always forward and material that can be deferred or forward depends on render pipeline options (like switch to rendering forward only mode)
// Material that are always forward are unlit and complex (Like Hair) and don't require sorting, so it is ok to split them.
RenderForward(cullResults,camera,renderContext,true);// Render deferred or forward opaque
RenderVelocity(cullResults,camera,renderContext);// 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 ?
// 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.
// TODO: Check with VFX team.
// Rendering distortion here have off course lot of artifact.
// But resolving at each objects that write in distortion is not possible (need to sort transparent, render those that do not distort, then resolve, then etc...)
// Instead we chose to apply distortion at the end after we cumulate distortion vector and desired blurriness. This
publicreadonlyGUIContentlayerMapMaskText=newGUIContent("Layer Mask","Layer mask (multiplied by vertex color if enabled)");
publicreadonlyGUIContentlayerMapVertexColorText=newGUIContent("Use Vertex Color","If no layer mask is set, vertex color values between 0 and 1.0 are used as final mask.\nIf a layer mask is set, vertex color values are remapped between -1 and 1 and added to the mask (neutral at 0.5 vertex color).");
publicreadonlyGUIContentvertexColorHeightMultiplierText=newGUIContent("Vertex Height Scale","Scale applied to the vertex color height.");
publicreadonlyGUIContentvertexColorModeText=newGUIContent("Vertex Color Mode","Mode multiply: vertex color is multiply with the mask. Mode additive: vertex color values are remapped between -1 and 1 and added to the mask (neutral at 0.5 vertex color).");
publicreadonlyGUIContentlayerTilingText=newGUIContent("Tiling","Tiling factor applied to UVSet");
publicreadonlyGUIContentuseHeightBasedBlendV2Text=newGUIContent("Use Height Based Blend V2","Layer will be blended with the underlying layer based on the height.");
publicreadonlyGUIContentinheritBaseNormalText=newGUIContent("Inherit Base Layer Normal","Inherit the normal from the base layer.");
publicreadonlyGUIContentinheritBaseHeightText=newGUIContent("Inherit Base Layer Height","Inherit the height from the base layer.");
publicreadonlyGUIContentinheritBaseColorText=newGUIContent("Inherit Base Layer Color","Inherit the base color from the base layer.");
publicreadonlyGUIContentinheritBaseNormalText=newGUIContent("Normal influence","Inherit the normal from the base layer.");
publicreadonlyGUIContentinheritBaseHeightText=newGUIContent("Heightmap influence","Inherit the height from the base layer.");
publicreadonlyGUIContentinheritBaseColorText=newGUIContent("BaseColor influence","Inherit the base color from the base layer.");
publicstaticGUIContentdetailMapModeText=newGUIContent("Detail Map with Normal","Detail Map with AO / Height");
publicstaticGUIContentUVDetailMappingText=newGUIContent("UV set for Detail","");
publicstaticGUIContentmaterialIDText=newGUIContent("Material Class","Subsurface Scattering: enable for translucent materials such as skin, vegetation, fruit, marble, wax and milk.");
publicstaticGUIContentemissiveColorModeText=newGUIContent("Emissive Color Usage","Use emissive color or emissive mask");
publicstaticstringInputsText="Inputs";
publicstaticGUIContenttangentMapText=newGUIContent("Tangent Map","Tangent Map (BC5) - DXT5 for test");
else if (surfaceData.materialId == MATERIALID_LIT_SSS)
{
outGBuffer2 = float4(surfaceData.subSurfaceRadius, surfaceData.thickness, 0.0, surfaceData.subSurfaceProfile / 8.0f); // Number of profile not define yet
outGBuffer2 = float4(surfaceData.subSurfaceRadius, surfaceData.thickness, 0.0, surfaceData.subSurfaceProfile / 8.0); // Number of profile not define yet
}
else if (surfaceData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
bsdfData.fresnel0 = 0.028; // TODO take from subSurfaceProfile
bsdfData.subSurfaceRadius = inGBuffer2.r;
bsdfData.thickness = inGBuffer2.g;
bsdfData.subSurfaceProfile = inGBuffer2.a * 8.0f;
bsdfData.subSurfaceProfile = inGBuffer2.a * 8.0;
}
else if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{
specularLighting = float3(0.0, 0.0, 0.0);
float3 cookieColor = float3(1.0, 1.0, 1.0);
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0f)
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0)
// // The idea here is to lerp toward vertex normal. This way when we don't want to inherit, we will combine layer 1/2/3 normal with a vertex normal which is neutral.
// // Blend layer 1/2/3 normals before combining to the base layer. Again we need to have a neutral value for base layer (vertex normal) in case all weights are zero.
// Compute how much we want to inherit from base layer normal base on the mask. Base layer always fully inherit from "itself" if it's the visible layer.
// Based on this inheritance parameters, fetch a lower level of the base layer normal map so that the less we inherit the more this tends to be "vertex normal"
float maxMipBias = 12.0f; // We arbitrarly choose the max bias for a 2048 texture. Smaller texture will bias toward vertex normal faster.
// Blend all layers but the base one. This will then be added to the "inherited" normal of base layer (that's why base layer here is tangent space vertex normal so that if it's the visible layer we add nothing in term of normal map).
// We will add smoothly the contribution of the normal map by using lower mips with help of bias sampling. InfluenceFactor must be [0..numMips] // Caution it cause banding...
// Note: that we don't take details map into account here.
float maxMipBias = log2(max(_NormalMap0_TexelSize.z, _NormalMap0_TexelSize.w)); // don't do + 1 as it is for bias, not lod
#if defined(_LAYER_MASK_VERTEX_COLOR_MUL) // Used when no layer mask is set
inputMaskValues *= input.color.rgb;
#elif defined(_LAYER_MASK_VERTEX_COLOR_ADD) || defined(_HEIGHT_BASED_BLEND_V2) // When layer mask is set, color is additive to enable user to override it.
// TODO : Test if GetOddNegativeScale() is necessary here in case of normal map, as GetOddNegativeScale is take into account in CreateTangentToWorld();
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// This function convert the tangent space normal/tangent to world space and orthonormalize it + apply a correction of the normal if it is not pointing towards the near plane
publicstaticGUIContentemissiveWarning=newGUIContent("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
publicstaticGUIContentemissiveColorWarning=newGUIContent("Ensure emissive color is non-black for emission to have effect.");
FindCommonOptionProperties(props);// MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
FindCommonOptionProperties(props);// MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
// Disable all incompatible sky parameters and enable the compatible one
boolfound=false;
foreach(SkyParametersparaminresult)
{
if(param.GetType()==skyParamType)
{
// This is a workaround the fact that we can't control the order in which components are initialized.
// So it can happen that a given SkyParameter is OnEnabled before the CommonSettings and so fail the setup because the SkyRenderer is not yet initialized.
// So we disable it to for OnEnable to be called again.
publicreadonlyGUIContentsssProfileStdDev1=newGUIContent("SSS profile standard deviation #1","Determines the shape of the 1st Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel.");
publicreadonlyGUIContentsssProfileStdDev2=newGUIContent("SSS profile standard deviation #2","Determines the shape of the 2nd Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel.");
publicreadonlyGUIContentsssProfileLerpWeight=newGUIContent("SSS profile filter interpolation","Controls linear interpolation between the two Gaussian filters.");
publicreadonlyGUIContentsssBilateralScale=newGUIContent("SSS bilateral filtering scale","Larger values make the filter more tolerant to depth differences.");
// We need one frame delay for this update to work since DynamicGI.UpdateEnvironment is executed direclty but the renderloop is not (so we need to wait for the sky texture to be rendered first)
if(m_NeedLowLevelUpdateEnvironment)
{
// TODO: Properly send the cubemap to Enlighten. Currently workaround is to set the cubemap in a Skybox/cubemap material
RenderSettings.skybox=m_StandardSkyboxMaterial;// Setup this material as the default to be use in RenderSettings
RenderSettings.ambientIntensity=1.0f;// fix this to 1, this parameter should not exist!
RenderSettings.ambientMode=UnityEngine.Rendering.AmbientMode.Skybox;// Force skybox for our HDRI
RenderSettings.reflectionIntensity=1.0f;
RenderSettings.customReflection=null;
DynamicGI.UpdateEnvironment();
// We need one frame delay for this update to work since DynamicGI.UpdateEnvironment is executed direclty but the renderloop is not (so we need to wait for the sky texture to be rendered first)
if(m_NeedLowLevelUpdateEnvironment)
{
// TODO: Properly send the cubemap to Enlighten. Currently workaround is to set the cubemap in a Skybox/cubemap material
// Note that m_SkyboxCubemapRT is created with auto-generate mipmap, it mean that here we have also our mipmap correctly box filtered for importance sampling.
// Note that m_SkyboxCubemapRT is created with auto-generate mipmap, it mean that here we have also our mipmap correctly box filtered for importance sampling.
if(renderPipeline.skyManager.skyParameters==null||renderPipeline.skyManager.skyParameters.GetType()!=this.GetType())// We allow override of parameters only if the type is different. It means that we changed the Sky Renderer and might need a new set of parameters.