浏览代码

Merge pull request #70 from EvgeniiG/master

Improve the quality of EnvMap filtering
/main
GitHub 8 年前
当前提交
f3e5d8cd
共有 17 个文件被更改,包括 762 次插入180 次删除
  1. 4
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.hlsl
  2. 1
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.cs
  3. 37
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  4. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/ShaderVariables.hlsl
  5. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/ProceduralSky/Resources/AtmosphericScattering.hlsl
  6. 54
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/GGXConvolve.shader
  7. 90
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs
  8. 19
      Assets/ScriptableRenderLoop/ShaderLibrary/API/D3D11.hlsl
  9. 25
      Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
  10. 19
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl
  11. 125
      Assets/ScriptableRenderLoop/ShaderLibrary/Fibonacci.hlsl
  12. 11
      Assets/ScriptableRenderLoop/ShaderLibrary/Hammersley.hlsl
  13. 368
      Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl
  14. 2
      ProjectSettings/ProjectVersion.txt
  15. 160
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/BuildProbabilityTables.compute
  16. 9
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/BuildProbabilityTables.compute.meta
  17. 14
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs.hlsl

4
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.hlsl


//TEXTURE2D(_ShadowAtlas);
//SAMPLER2D_SHADOW(sampler_ShadowAtlas);
//SAMPLER2D(sampler_ManualShadowAtlas); // TODO: settings sampler individually is not supported in shader yet...
TEXTURE2D(g_tShadowBuffer) // TODO: No choice, the name is hardcoded in ShadowrenderPass.cs for now. Need to change this!
TEXTURE2D(g_tShadowBuffer); // TODO: No choice, the name is hardcoded in ShadowrenderPass.cs for now. Need to change this!
SAMPLER2D_SHADOW(samplerg_tShadowBuffer);
// Use texture array for IES

// EnvIndex can also be use to fetch in another array of struct (to atlas information etc...).
float4 SampleEnv(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod)
{
lod = min(lod, UNITY_SPECCUBE_LOD_STEPS);
// This code will be inlined as lightLoopContext is hardcoded in the light loop
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
{

1
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.cs


m_LtcGGXMatrix = LoadLUT(TextureFormat.RGBAHalf, s_LtcGGXMatrixData);
m_LtcDisneyDiffuseMatrix = LoadLUT(TextureFormat.RGBAHalf, s_LtcDisneyDiffuseMatrixData);
// TODO: switch to RGBA64 when it becomes available.
m_LtcMultiGGXFresnelDisneyDiffuse = LoadLUT(TextureFormat.RGBAHalf, s_LtcGGXMagnitudeData,
s_LtcGGXFresnelData,
s_LtcDisneyDiffuseMagnitudeData);

37
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float3 acc = float3(0.0, 0.0, 0.0);
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);

float3 L;
float NdotL;
float weightOverPdf;
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
ImportanceSampleLambert(u, localToWorld, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{

float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(N.xy * 0.5 + 0.5);

float NdotL;
float weightOverPdf;
// for Disney we still use a Cosine importance sampling, true Disney importance sampling imply a look up table
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
ImportanceSampleLambert(u, localToWorld, L, NdotL, weightOverPdf);
{
{
float3 H = normalize(L + V);
float LdotH = dot(L, H);
// Note: we call DisneyDiffuse that require to multiply by Albedo / PI. Divide by PI is already taken into account

float3 V, EnvLightData lightData, BSDFData bsdfData,
uint sampleCount = 2048)
{
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
float3 N = bsdfData.normalWS;
float3 tangentX = bsdfData.tangentWS;
float3 tangentY = bsdfData.bitangentWS;
float3x3 localToWorld = GetLocalFrame(N, tangentX);
float NdotV = GetShiftedNdotV(N, V, false);
float3 acc = float3(0.0, 0.0, 0.0);
// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);

}
else
{
ImportanceSampleGGX(u, V, N, tangentX, tangentY, bsdfData.roughness, NdotV, L, VdotH, NdotL, weightOverPdf);
ImportanceSampleGGX(u, V, localToWorld, bsdfData.roughness, NdotV, L, VdotH, NdotL, weightOverPdf);
}

2
Assets/ScriptableRenderLoop/HDRenderLoop/ShaderVariables.hlsl


// TODO: Change code here so probe volume use only one transform instead of all this parameters!
TEXTURE3D(unity_ProbeVolumeSH);
SAMPLER3D(samplerunity_ProbeVolumeSH)
SAMPLER3D(samplerunity_ProbeVolumeSH);
CBUFFER_START(UnityProbeVolume)
// x = Disabled(0)/Enabled(1)

2
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/ProceduralSky/Resources/AtmosphericScattering.hlsl


uniform float _MiePhaseAnisotropy;
uniform float _MieExtinctionFactor;
SAMPLER2D(sampler_CameraDepthTexture)
SAMPLER2D(sampler_CameraDepthTexture);
#define SRL_BilinearSampler sampler_CameraDepthTexture // Used for all textures
TEXTURE2D(_CameraDepthTexture);

54
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/GGXConvolve.shader


#pragma target 5.0
#pragma only_renderers d3d11 // TEMP: unitl we go futher in dev
#pragma multi_compile _ USE_MIS
#include "../SkyManager.cs.hlsl"
struct Attributes
{

TEXTURECUBE(_MainTex);
SAMPLERCUBE(sampler_MainTex);
#ifdef USE_MIS
TEXTURE2D(_MarginalRowDensities);
TEXTURE2D(_ConditionalDensities);
#endif
float _MipMapCount;
float _MaxLevel;
float _InvOmegaP;
half4 Frag(Varyings input) : SV_Target

// Remove view-dependency from GGX, effectively making the BSDF isotropic.
// We approximate the pre-integration with V == N
float4 val = IntegrateLD( TEXTURECUBE_PARAM(_MainTex, sampler_MainTex),
V,
N,
PerceptualRoughnessToRoughness(perceptualRoughness),
_MipMapCount,
_InvOmegaP,
55, // Matches the size of the precomputed Fibonacci point set
true);
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
#ifdef USE_MIS
float4 val = IntegrateLD_MIS(TEXTURECUBE_PARAM(_MainTex, sampler_MainTex),
_MarginalRowDensities, _ConditionalDensities,
V, N,
roughness,
_InvOmegaP,
LIGHTSAMPLINGPARAMETERS_TEXTURE_WIDTH,
LIGHTSAMPLINGPARAMETERS_TEXTURE_HEIGHT,
1024,
false);
#else
uint sampleCount = 0;
switch (_Level)
{
case 1: sampleCount = 21; break;
case 2: sampleCount = 34; break;
case 3: sampleCount = 55; break;
case 4: sampleCount = 89; break;
case 5: sampleCount = 89; break;
case 6: sampleCount = 89; break; // UNITY_SPECCUBE_LOD_STEPS
}
float4 val = IntegrateLD(TEXTURECUBE_PARAM(_MainTex, sampler_MainTex),
V, N,
roughness,
_MaxLevel,
_InvOmegaP,
sampleCount, // Must be a Fibonacci number
true);
#endif
return val;
}

90
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs


using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using System.Collections.Generic;
namespace UnityEngine.Experimental.ScriptableRenderLoop
{

//SkyResolution4096 = 4096
}
[GenerateHLSL(PackingRules.Exact)]
public enum LightSamplingParameters
{
TextureHeight = 256,
TextureWidth = 512
}
public enum EnvironementUpdateMode
{
OnChanged = 0,

public Vector3 cameraPosWS;
public Vector4 screenSize;
public Mesh skyMesh;
public ScriptableRenderContext renderLoop;
public ScriptableRenderContext renderLoop;
public Light sunLight;
public RenderTargetIdentifier colorBuffer;
public RenderTargetIdentifier depthBuffer;

{
RenderTexture m_SkyboxCubemapRT = null;
RenderTexture m_SkyboxGGXCubemapRT = null;
RenderTexture m_SkyboxMarginalRowCdfRT = null;
RenderTexture m_SkyboxConditionalCdfRT = null;
ComputeShader m_BuildProbabilityTablesCS = null;
int m_ConditionalDensitiesKernel = -1;
int m_MarginalRowDensitiesKernel = -1;
Vector4 m_CubemapScreenSize;
Matrix4x4[] m_faceCameraViewProjectionMatrix = new Matrix4x4[6];
Matrix4x4[] m_faceCameraInvViewProjectionMatrix = new Matrix4x4[6];

bool m_NeedLowLevelUpdateEnvironment = false;
bool m_UpdateRequired = true;
float m_CurrentUpdateTime = 0.0f;
const bool m_useMIS = false;
SkyParameters m_SkyParameters = null;

{
Utilities.Destroy(m_SkyboxCubemapRT);
Utilities.Destroy(m_SkyboxGGXCubemapRT);
Utilities.Destroy(m_SkyboxMarginalRowCdfRT);
Utilities.Destroy(m_SkyboxConditionalCdfRT);
m_UpdateRequired = true; // Special case. Even if update mode is set to OnDemand, we need to regenerate the environment after destroying the texture.
}

m_SkyboxGGXCubemapRT.autoGenerateMips = false;
m_SkyboxGGXCubemapRT.filterMode = FilterMode.Trilinear;
m_SkyboxGGXCubemapRT.Create();
if (m_useMIS)
{
int width = (int)LightSamplingParameters.TextureWidth;
int height = (int)LightSamplingParameters.TextureHeight;
// + 1 because we store the value of the integral of the cubemap at the end of the texture.
m_SkyboxMarginalRowCdfRT = new RenderTexture(height + 1, 1, 1, RenderTextureFormat.RFloat);
m_SkyboxMarginalRowCdfRT.dimension = TextureDimension.Tex2D;
m_SkyboxMarginalRowCdfRT.useMipMap = false;
m_SkyboxMarginalRowCdfRT.autoGenerateMips = false;
m_SkyboxMarginalRowCdfRT.enableRandomWrite = true;
m_SkyboxMarginalRowCdfRT.filterMode = FilterMode.Point;
m_SkyboxMarginalRowCdfRT.Create();
// TODO: switch the format to R16 (once it's available) to save some bandwidth.
m_SkyboxConditionalCdfRT = new RenderTexture(width, height, 1, RenderTextureFormat.RFloat);
m_SkyboxConditionalCdfRT.dimension = TextureDimension.Tex2D;
m_SkyboxConditionalCdfRT.useMipMap = false;
m_SkyboxConditionalCdfRT.autoGenerateMips = false;
m_SkyboxConditionalCdfRT.enableRandomWrite = true;
m_SkyboxConditionalCdfRT.filterMode = FilterMode.Point;
m_SkyboxConditionalCdfRT.Create();
}
}
m_CubemapScreenSize = new Vector4((float)resolution, (float)resolution, 1.0f / (float)resolution, 1.0f / (float)resolution);

m_Renderer.Build();
// TODO: We need to have an API to send our sky information to Enlighten. For now use a workaround through skybox/cubemap material...
m_StandardSkyboxMaterial = Utilities.CreateEngineMaterial("Skybox/Cubemap");
m_GGXConvolveMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderLoop/GGXConvolve");
m_StandardSkyboxMaterial = Utilities.CreateEngineMaterial("Skybox/Cubemap");
m_GGXConvolveMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderLoop/GGXConvolve");
m_BuildProbabilityTablesCS = Resources.Load<ComputeShader>("BuildProbabilityTables");
m_ConditionalDensitiesKernel = m_BuildProbabilityTablesCS.FindKernel("ComputeConditionalDensities");
m_MarginalRowDensitiesKernel = m_BuildProbabilityTablesCS.FindKernel("ComputeMarginalRowDensities");
m_CurrentUpdateTime = 0.0f;
}

Utilities.Destroy(m_GGXConvolveMaterial);
Utilities.Destroy(m_SkyboxCubemapRT);
Utilities.Destroy(m_SkyboxGGXCubemapRT);
Utilities.Destroy(m_SkyboxMarginalRowCdfRT);
Utilities.Destroy(m_SkyboxConditionalCdfRT);
if(m_Renderer != null)
m_Renderer.Cleanup();

}
}
private void BuildProbabilityTables(ScriptableRenderContext renderLoop)
{
// Bind the input cubemap.
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "envMap", m_SkyboxCubemapRT);
// Bind the outputs.
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "marginalRowDensities", m_SkyboxMarginalRowCdfRT);
m_BuildProbabilityTablesCS.SetTexture(m_ConditionalDensitiesKernel, "conditionalDensities", m_SkyboxConditionalCdfRT);
m_BuildProbabilityTablesCS.SetTexture(m_MarginalRowDensitiesKernel, "marginalRowDensities", m_SkyboxMarginalRowCdfRT);
var cmd = new CommandBuffer() { name = "" };
cmd.DispatchCompute(m_BuildProbabilityTablesCS, m_ConditionalDensitiesKernel, (int)LightSamplingParameters.TextureHeight, 1, 1);
cmd.DispatchCompute(m_BuildProbabilityTablesCS, m_MarginalRowDensitiesKernel, 1, 1, 1);
renderLoop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
private void RenderCubemapGGXConvolution(ScriptableRenderContext renderLoop, BuiltinSkyParameters builtinParams, SkyParameters skyParams, Texture input, RenderTexture target)
{
using (new Utilities.ProfilingSample("Sky Pass: GGX Convolution", renderLoop))

{
Debug.LogWarning("RenderCubemapGGXConvolution: Cubemap size is too small for GGX convolution, needs at least " + ((int)EnvConstants.SpecCubeLodStep + 1) + " mip levels");
return;
}
if (m_useMIS)
{
BuildProbabilityTables(renderLoop);
}
// Copy the first mip.

//for (int f = 0; f < 6; f++)
// Graphics.CopyTexture(input, f, 0, target, f, 0);
if (m_useMIS)
{
m_GGXConvolveMaterial.EnableKeyword("USE_MIS");
m_GGXConvolveMaterial.SetTexture("_MarginalRowDensities", m_SkyboxMarginalRowCdfRT);
m_GGXConvolveMaterial.SetTexture("_ConditionalDensities", m_SkyboxConditionalCdfRT);
}
else
{
m_GGXConvolveMaterial.DisableKeyword("USE_MIS");
}
m_GGXConvolveMaterial.SetFloat("_MipMapCount", mipCount);
m_GGXConvolveMaterial.SetFloat("_MaxLevel", mipCount - 1);
m_GGXConvolveMaterial.SetFloat("_InvOmegaP", invOmegaP);
for (int mip = 1; mip < ((int)EnvConstants.SpecCubeLodStep + 1); ++mip)

19
Assets/ScriptableRenderLoop/ShaderLibrary/API/D3D11.hlsl


// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName;
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName;
#define TEXTURECUBE(textureName) TextureCube textureName;
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName;
#define TEXTURE3D(textureName) Texture3D textureName;
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define SAMPLER2D(samplerName) SamplerState samplerName;
#define SAMPLERCUBE(samplerName) SamplerState samplerName;
#define SAMPLER3D(samplerName) SamplerState samplerName;
#define SAMPLER2D(samplerName) SamplerState samplerName
#define SAMPLERCUBE(samplerName) SamplerState samplerName
#define SAMPLER3D(samplerName) SamplerState samplerName
#define SAMPLER2D_SHADOW(samplerName) SamplerComparisonState samplerName
#define SAMPLERCUBE_SHADOW(samplerName) SamplerComparisonState samplerName

#define SAMPLER2D_FLOAT SAMPLER2D
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))

25
Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl


#define Clamp clamp
#endif // INTRINSIC_CLAMP
#ifndef INTRINSIC_MUL24
int Mul24(int a, int b)
{
return a * b;
}
uint Mul24(uint a, uint b)
{
return a * b;
}
#endif // INTRINSIC_MUL24
#ifndef INTRINSIC_MAD24
int Mad24(int a, int b, int c)
{
return a * b + c;
}
uint Mad24(uint a, uint b, uint c)
{
return a * b + c;
}
#endif // INTRINSIC_MAD24
#ifndef INTRINSIC_MED3
float Med3(float a, float b, float c)
{

#define INV_HALF_PI 0.636619772367
#define FLT_EPSILON 1.192092896e-07 // Smallest positive number, such that 1.0 + FLT_EPSILON != 1.0
#define FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number
#define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
#define MERGE_NAME(X, Y) X##Y

19
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


// Get local frame
//-----------------------------------------------------------------------------
// generate an orthonormalBasis from 3d unit vector.
void GetLocalFrame(float3 N, out float3 tangentX, out float3 tangentY)
// Generates an orthonormal basis from two orthogonal unit vectors.
float3x3 GetLocalFrame(float3 localZ, float3 localX)
{
float3 localY = cross(localZ, localX);
return float3x3(localX, localY, localZ);
}
// Generates an orthonormal basis from a unit vector.
float3x3 GetLocalFrame(float3 localZ)
float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
tangentX = normalize(cross(upVector, N));
tangentY = cross(N, tangentX);
float3 upVector = abs(localZ.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
float3 localX = normalize(cross(upVector, localZ));
return GetLocalFrame(localZ, localX);
}
// TODO: test

125
Assets/ScriptableRenderLoop/ShaderLibrary/Fibonacci.hlsl


}
static const int k_FibonacciSeq[] = {
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610
};
static const float2 k_Fibonacci2dSeq21[] = {

float2(0.98181820, 0.38181686)
};
// Loads elements from one of the precomputed tables for sequence lengths of 9, 10, 11.
// Computes the values at runtime otherwise.
// For sampling, the size of the point set is given by { k_FibonacciSeq[sequenceLength - 1] }.
float2 Fibonacci2d(uint i, uint sequenceLength)
static const float2 k_Fibonacci2dSeq89[] = {
float2(0.00000000, 0.00000000),
float2(0.01123596, 0.61797750),
float2(0.02247191, 0.23595500),
float2(0.03370786, 0.85393250),
float2(0.04494382, 0.47191000),
float2(0.05617978, 0.08988762),
float2(0.06741573, 0.70786500),
float2(0.07865169, 0.32584238),
float2(0.08988764, 0.94382000),
float2(0.10112359, 0.56179762),
float2(0.11235955, 0.17977524),
float2(0.12359551, 0.79775238),
float2(0.13483146, 0.41573000),
float2(0.14606741, 0.03370762),
float2(0.15730338, 0.65168476),
float2(0.16853933, 0.26966286),
float2(0.17977528, 0.88764000),
float2(0.19101124, 0.50561714),
float2(0.20224719, 0.12359524),
float2(0.21348314, 0.74157238),
float2(0.22471911, 0.35955048),
float2(0.23595506, 0.97752762),
float2(0.24719101, 0.59550476),
float2(0.25842696, 0.21348286),
float2(0.26966292, 0.83146000),
float2(0.28089887, 0.44943714),
float2(0.29213482, 0.06741524),
float2(0.30337077, 0.68539238),
float2(0.31460676, 0.30336952),
float2(0.32584271, 0.92134666),
float2(0.33707866, 0.53932571),
float2(0.34831461, 0.15730286),
float2(0.35955057, 0.77528000),
float2(0.37078652, 0.39325714),
float2(0.38202247, 0.01123428),
float2(0.39325842, 0.62921333),
float2(0.40449437, 0.24719048),
float2(0.41573033, 0.86516762),
float2(0.42696628, 0.48314476),
float2(0.43820226, 0.10112190),
float2(0.44943821, 0.71910095),
float2(0.46067417, 0.33707809),
float2(0.47191012, 0.95505524),
float2(0.48314607, 0.57303238),
float2(0.49438202, 0.19100952),
float2(0.50561798, 0.80898666),
float2(0.51685393, 0.42696571),
float2(0.52808988, 0.04494286),
float2(0.53932583, 0.66292000),
float2(0.55056179, 0.28089714),
float2(0.56179774, 0.89887428),
float2(0.57303369, 0.51685333),
float2(0.58426964, 0.13483047),
float2(0.59550560, 0.75280762),
float2(0.60674155, 0.37078476),
float2(0.61797750, 0.98876190),
float2(0.62921351, 0.60673904),
float2(0.64044946, 0.22471619),
float2(0.65168542, 0.84269333),
float2(0.66292137, 0.46067429),
float2(0.67415732, 0.07865143),
float2(0.68539327, 0.69662857),
float2(0.69662923, 0.31460571),
float2(0.70786518, 0.93258286),
float2(0.71910113, 0.55056000),
float2(0.73033708, 0.16853714),
float2(0.74157304, 0.78651428),
float2(0.75280899, 0.40449142),
float2(0.76404494, 0.02246857),
float2(0.77528089, 0.64044571),
float2(0.78651685, 0.25842667),
float2(0.79775280, 0.87640381),
float2(0.80898875, 0.49438095),
float2(0.82022470, 0.11235809),
float2(0.83146065, 0.73033524),
float2(0.84269661, 0.34831238),
float2(0.85393256, 0.96628952),
float2(0.86516851, 0.58426666),
float2(0.87640452, 0.20224380),
float2(0.88764048, 0.82022095),
float2(0.89887643, 0.43820190),
float2(0.91011238, 0.05617905),
float2(0.92134833, 0.67415619),
float2(0.93258429, 0.29213333),
float2(0.94382024, 0.91011047),
float2(0.95505619, 0.52808762),
float2(0.96629214, 0.14606476),
float2(0.97752810, 0.76404190),
float2(0.98876405, 0.38201904)
};
// Loads elements from one of the precomputed tables for sample counts of 21, 34, 55.
// Computes sample positions at runtime otherwise.
// Sample count must be a Fibonacci number (see 'k_FibonacciSeq').
float2 Fibonacci2d(uint i, uint sampleCount)
int fibN1 = k_FibonacciSeq[sequenceLength - 1];
int fibN2 = k_FibonacciSeq[sequenceLength - 2];
switch (fibN1)
switch (sampleCount)
default: Fibonacci2dSeq(fibN1, fibN2, i);
case 89: return k_Fibonacci2dSeq89[i];
default:
{
int fibN1 = sampleCount;
int fibN2 = sampleCount;
// These are all constants, so this loop will be optimized away.
for (int j = 1; j < 16; j++)
{
if (k_FibonacciSeq[j] == fibN1)
{
fibN2 = k_FibonacciSeq[j - 1];
}
}
return Fibonacci2dSeq(fibN1, fibN2, i);
}
}
}

11
Assets/ScriptableRenderLoop/ShaderLibrary/Hammersley.hlsl


float2(0.99609375, 0.99609375)
};
// Loads elements from one of the precomputed tables for sequence lengths of 16, 32, 64, 256.
// Computes the values at runtime otherwise.
// For sampling, the size of the point set is the same as the sequence length.
float2 Hammersley2d(uint i, uint sequenceLength)
// Loads elements from one of the precomputed tables for sample counts of 16, 32, 64, 256.
// Computes sample positions at runtime otherwise.
float2 Hammersley2d(uint i, uint sampleCount)
switch (sequenceLength)
switch (sampleCount)
default: return Hammersley2dSeq(i, sequenceLength);
default: return Hammersley2dSeq(i, sampleCount);
}
}

368
Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl


#include "BSDF.hlsl"
#include "Sampling.hlsl"
// TODO: We need to change this hard limit!
#ifndef UNITY_SPECCUBE_LOD_STEPS
#define UNITY_SPECCUBE_LOD_STEPS 6
#endif
// TODO: We need to change this hard limit!
#define UNITY_SPECCUBE_LOD_STEPS (6)
float perceptualRoughnessToMipmapLevel(float perceptualRoughness)
{

float mipmapLevelToPerceptualRoughness(float mipmapLevel)
{
return mipmapLevel / UNITY_SPECCUBE_LOD_STEPS;
return saturate(mipmapLevel / UNITY_SPECCUBE_LOD_STEPS);
}
//-----------------------------------------------------------------------------
// Coordinate system conversion
//-----------------------------------------------------------------------------
// Transforms the unit vector from the spherical to the Cartesian (right-handed, Z up) coordinate.
float3 SphericalToCartesian(float phi, float sinTheta, float cosTheta)
{
float sinPhi, cosPhi;
sincos(phi, sinPhi, cosPhi);
return float3(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta);
}
// Converts Cartesian coordinates given in the right-handed coordinate system
// with Z pointing upwards (OpenGL style) to the coordinates in the left-handed
// coordinate system with Y pointing up and Z facing forward (DirectX style).
float3 TransformGLtoDX(float x, float y, float z)
{
return float3(x, z, y);
}
float3 TransformGLtoDX(float3 v)
{
return v.xzy;
}
// Performs conversion from equiareal map coordinates to Cartesian (DirectX cubemap) ones.
float3 ConvertEquiarealToCubemap(float u, float v)
{
// The equiareal mapping is defined as follows:
// phi = TWO_PI * (1.0 - u)
// cos(theta) = 1.0 - 2.0 * v
// sin(theta) = sqrt(1.0 - cos^2(theta)) = 2.0 * sqrt(v - v * v)
float phi = TWO_PI - TWO_PI * u;
float cosTheta = 1.0 - 2.0 * v;
float sinTheta = 2.0 * sqrt(v - v * v);
return TransformGLtoDX(SphericalToCartesian(phi, sinTheta, cosTheta));
}
// Ref: See "Moving Frostbite to PBR" Listing 22

// Importance sampling BSDF functions
// ----------------------------------------------------------------------------
void ImportanceSampleCosDir(float2 u,
float3 N,
float3 tangentX,
float3 tangentY,
out float3 L)
void ImportanceSampleCosDir(float2 u,
float3x3 localToWorld,
out float3 L)
float phi = TWO_PI * u.y;
float phi = TWO_PI * u.y;
// Transform from spherical into cartesian
L = float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
// Local to world
L = tangentX * L.x + tangentY * L.y + N * L.z;
L = SphericalToCartesian(phi, sinTheta, cosTheta);
L = mul(L, localToWorld);
void ImportanceSampleGGXDir(float2 u,
float3 V,
float3 N,
float3 tangentX,
float3 tangentY,
float roughness,
out float3 H,
out float3 L)
void ImportanceSampleGGXDir(float2 u,
float3 V,
float3x3 localToWorld,
float roughness,
out float3 L,
out float NdotH,
out float VdotH,
bool VeqN = false)
float cosThetaH = sqrt((1.0 - u.x) / (1.0 + (roughness * roughness - 1.0) * u.x));
float sinThetaH = sqrt(saturate(1.0 - cosThetaH * cosThetaH));
float phiH = TWO_PI * u.y;
// Transform from spherical into cartesian
H = float3(sinThetaH * cos(phiH), sinThetaH * sin(phiH), cosThetaH);
// Local to world
H = tangentX * H.x + tangentY * H.y + N * H.z;
// Convert sample from half angle to incident angle
L = 2.0 * dot(V, H) * H - V;
}
float cosTheta = sqrt((1.0 - u.x) / (1.0 + (roughness * roughness - 1.0) * u.x));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
float phi = TWO_PI * u.y;
float3 localH = SphericalToCartesian(phi, sinTheta, cosTheta);
// Special case of ImportanceSampleGGXDir() where N == V.
// Approximates GGX with a BRDF which is isotropic for all viewing angles.
void ImportanceSampleGGXViewIndDir(float2 u,
float3 N,
float3 tangentX,
float3 tangentY,
float roughness,
out float3 L,
out float NdotH)
{
// GGX NDF sampling
float cosThetaH = sqrt((1.0 - u.x) / (1.0 + (roughness * roughness - 1.0) * u.x));
float sinThetaH = sqrt(saturate(1.0 - cosThetaH * cosThetaH));
float phiH = TWO_PI * u.y;
NdotH = cosTheta;
// Transform from spherical into Cartesian.
float3 localH = float3(sinThetaH * cos(phiH), sinThetaH * sin(phiH), cosThetaH);
float3 localV;
// localN == localV == float3(0.0, 0.0, 1.0).
NdotH = localH.z;
if (VeqN)
{
// localV == localN
localV = float3(0.0, 0.0, 1.0);
VdotH = NdotH;
}
else
{
localV = mul(V, transpose(localToWorld));
VdotH = saturate(dot(localV, localH));
}
// Compute { L = reflect(-localV, localH) }.
float VdotH = NdotH;
L = float3(0.0, 0.0, -1.0) + 2.0 * VdotH * localH;
// Compute { L = reflect(-localV, localH) }
L = -localV + 2.0 * VdotH * localH;
// Local to world
L = tangentX * L.x + tangentY * L.y + N * L.z;
L = mul(L, localToWorld);
}
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26

// H = tangentX * H.x + tangentY * H.y + N * H.z;
// Convert sample from half angle to incident angle
L = 2.0 * dot(V, H) * H - V;
L = 2.0 * saturate(dot(V, H)) * H - V;
void ImportanceSampleLambert(
float2 u,
float3 N,
float3 tangentX,
float3 tangentY,
out float3 L,
out float NdotL,
out float weightOverPdf)
void ImportanceSampleLambert(float2 u,
float3x3 localToWorld,
out float3 L,
out float NdotL,
out float weightOverPdf)
ImportanceSampleCosDir(u, N, tangentX, tangentY, L);
ImportanceSampleCosDir(u, localToWorld, L);
NdotL = saturate(dot(N, L));
NdotL = saturate(dot(localToWorld[2], L));
// Importance sampling weight for each sample
// pdf = N.L / PI

}
// weightOverPdf return the weight (without the Fresnel term) over pdf. Fresnel term must be apply by the caller.
void ImportanceSampleGGX(
float2 u,
float3 V,
float3 N,
float3 tangentX,
float3 tangentY,
float roughness,
float NdotV,
out float3 L,
out float VdotH,
out float NdotL,
out float weightOverPdf)
void ImportanceSampleGGX(float2 u,
float3 V,
float3x3 localToWorld,
float roughness,
float NdotV,
out float3 L,
out float VdotH,
out float NdotL,
out float weightOverPdf)
ImportanceSampleGGXDir(u, V, N, tangentX, tangentY, roughness, H, L);
float NdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH);
float NdotH = saturate(dot(N, H));
// Note: since L and V are symmetric around H, LdotH == VdotH
VdotH = saturate(dot(V, H));
NdotL = saturate(dot(N, L));
NdotL = saturate(dot(localToWorld[2], L));
// Importance sampling weight for each sample
// pdf = D(H) * (N.H) / (4 * (L.H))

// Add some jittering on Hammersley2d
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
float3x3 localToWorld = GetLocalFrame(N);
float2 u = Hammersley2d(i, sampleCount);
u = frac(u + randNum + 0.5);
float2 u = frac(randNum + Hammersley2d(i, sampleCount));
float VdotH;
float NdotL;

ImportanceSampleGGX(u, V, N, tangentX, tangentY, roughness, NdotV,
ImportanceSampleGGX(u, V, localToWorld, roughness, NdotV,
L, VdotH, NdotL, weightOverPdf);
if (NdotL > 0.0)

}
// for Disney we still use a Cosine importance sampling, true Disney importance sampling imply a look up table
ImportanceSampleLambert(u, N, tangentX, tangentY, L, NdotL, weightOverPdf);
ImportanceSampleLambert(u, localToWorld, L, NdotL, weightOverPdf);
if (NdotL > 0.0)
{

float3 V,
float3 N,
float roughness,
float mipmapcount,
float maxMipLevel,
uint sampleCount, // Matches the size of the precomputed Fibonacci point set
bool prefilter = true) // static bool
uint sampleCount, // Must be a Fibonacci number
bool prefilter)
float3 acc = float3(0.0, 0.0, 0.0);
float accWeight = 0;
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
float3x3 localToWorld = GetLocalFrame(N);
float3 tangentX, tangentY;
GetLocalFrame(N, tangentX, tangentY);
float3 lightInt = float3(0.0, 0.0, 0.0);
float cbsdfInt = 0.0;
float2 u = k_Fibonacci2dSeq55[i];
u = frac(u + randNum);
float2 u = Fibonacci2d(i, sampleCount);
// Bias samples towards the mirror direction to reduce variance.
// This will have a side effect of making the reflection sharper.
// Ref: Stochastic Screen-Space Reflections, p. 67.
const float bias = 0.2;
u.x = lerp(u.x, 0.0, bias);
float NdotH;
ImportanceSampleGGXViewIndDir(u, N, tangentX, tangentY, roughness, L, NdotH);
float NdotH, VdotH;
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH, true);
float NdotL = saturate(dot(N, L));

{
mipLevel = 0.0;
mipLevel = 0;
}
else // Prefiltered BRDF importance sampling
{

// - OmegaP : Solid angle associated to a pixel of the cubemap
float invPdf = D_GGX_Inverse(NdotH, roughness) * 4.0;
float omegaS = rcp(sampleCount) * invPdf; // Solid angle associated with the sample
// TODO: check the accuracy of the sample's solid angle fit for GGX.
float omegaS = rcp(sampleCount) * invPdf;
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated with the pixel of the cubemap
mipLevel = 0.5 * log2(omegaS * invOmegaP) + 1.0; // Clamp is not necessary as the hardware will do it
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth);
mipLevel = 0.5 * log2(omegaS * invOmegaP);
// Bias the MIP map level to compensate for the importance sampling bias.
// This will blur the reflection.
// TODO: find a more accurate MIP bias function.
mipLevel = lerp(mipLevel, maxMipLevel, bias);
if (NdotL > 0.0f)
if (NdotL > 0.0)
// TODO: use a Gaussian-like filter to generate the MIP pyramid.
// See p63 equation (53) of moving Frostbite to PBR v2 for the extra NdotL here (both in weight and value)
acc += val * NdotL;
accWeight += NdotL;
// *********************************************************************************
// Our goal is to use Monte-Carlo integration with importance sampling to evaluate
// X(V) = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// PDF = D * NdotH / (4 * LdotH).
// Weight = CBSDF / PDF = F * G * LdotH / (NdotV * NdotH).
// Since we perform filtering with the assumption that (V == N),
// (LdotH == NdotH) && (NdotV == 1) && (Weight == F * G).
// We use the approximation of Brian Karis from "Real Shading in Unreal Engine 4":
// Weight ≈ NdotL, which produces nearly identical results in practice.
// *********************************************************************************
lightInt += NdotL * val;
cbsdfInt += NdotL;
return float4(acc * (1.0 / accWeight), 1.0);
return float4(lightInt / cbsdfInt, 1.0);
}
// Searches the row 'j' containing 'n' elements of 'haystack' and
// returns the index of the first element greater or equal to 'needle'.
uint BinarySearchRow(uint j, float needle, TEXTURE2D(haystack), uint n)
{
uint i = n - 1;
float v = LOAD_TEXTURE2D(haystack, uint2(i, j)).r;
if (needle < v)
{
i = 0;
for (uint b = 1 << firstbithigh(n - 1); b != 0; b >>= 1)
{
uint p = i | b;
v = LOAD_TEXTURE2D(haystack, uint2(p, j)).r;
if (v <= needle) { i = p; } // Move to the right.
}
}
return i;
}
float4 IntegrateLD_MIS(TEXTURECUBE_ARGS(envMap, sampler_envMap),
TEXTURE2D(marginalRowDensities),
TEXTURE2D(conditionalDensities),
float3 V,
float3 N,
float roughness,
float invOmegaP,
uint width,
uint height,
uint sampleCount,
bool prefilter)
{
float3x3 localToWorld = GetLocalFrame(N);
float2 randNum = InitRandom(V.xy * 0.5 + 0.5);
float3 lightInt = float3(0.0, 0.0, 0.0);
float cbsdfInt = 0.0;
/*
// Dedicate 50% of samples to light sampling at 1.0 roughness.
// Only perform BSDF sampling when roughness is below 0.5.
const int lightSampleCount = lerp(0, sampleCount / 2, saturate(2.0 * roughness - 1.0));
const int bsdfSampleCount = sampleCount - lightSampleCount;
*/
// The value of the integral of intensity values of the environment map (as a 2D step function).
float envMapInt2dStep = LOAD_TEXTURE2D(marginalRowDensities, uint2(height, 0)).r;
// Since we are using equiareal mapping, we need to divide by the area of the sphere.
float envMapIntSphere = envMapInt2dStep * INV_FOUR_PI;
// Perform light importance sampling.
for (uint i = 0; i < sampleCount; i++)
{
float2 s = frac(randNum + Hammersley2d(i, sampleCount));
// Sample a row from the marginal distribution.
uint y = BinarySearchRow(0, s.x, marginalRowDensities, height - 1);
// Sample a column from the conditional distribution.
uint x = BinarySearchRow(y, s.y, conditionalDensities, width - 1);
// Compute the coordinates of the sample.
// Note: we take the sample in between two texels, and also apply the half-texel offset.
// We could compute fractional coordinates at the cost of 4 extra texel samples.
float u = saturate((float)x / width + 1.0 / width);
float v = saturate((float)y / height + 1.0 / height);
float3 L = ConvertEquiarealToCubemap(u, v);
float NdotL = saturate(dot(N, L));
if (NdotL > 0.0)
{
float3 val = SAMPLE_TEXTURECUBE_LOD(envMap, sampler_envMap, L, 0).rgb;
float pdf = (val.r + val.g + val.b) / envMapIntSphere;
if (pdf > 0.0)
{
// (N == V) && (acos(VdotL) == 2 * acos(NdotH)).
float NdotH = sqrt(NdotL * 0.5 + 0.5);
// *********************************************************************************
// Our goal is to use Monte-Carlo integration with importance sampling to evaluate
// X(V) = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}.
// CBSDF = F * D * G * NdotL / (4 * NdotL * NdotV) = F * D * G / (4 * NdotV).
// Weight = CBSDF / PDF.
// We use two approximations of Brian Karis from "Real Shading in Unreal Engine 4":
// (F * G ≈ NdotL) && (NdotV == 1).
// Weight = D * NdotL / (4 * PDF).
// *********************************************************************************
float weight = D_GGX(NdotH, roughness) * NdotL / (4.0 * pdf);
lightInt += weight * val;
cbsdfInt += weight;
}
}
}
// Prevent NaNs arising from the division of 0 by 0.
cbsdfInt = max(cbsdfInt, FLT_MIN);
return float4(lightInt / cbsdfInt, 1.0);
}
#endif // UNITY_IMAGE_BASED_LIGHTING_INCLUDED

2
ProjectSettings/ProjectVersion.txt


m_EditorVersion: 5.6.0b1
m_EditorVersion: 5.6.0b3

160
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/BuildProbabilityTables.compute


// Given a cube map (passed as a 2D array), builds CDFs of two distributions:
// 1. 1D texture with marginal densities, telling us the likelihood of selecting a particular row,
// 2. 2D texture with conditional densities, which correspond to the PDF of the texel given its row.
// Ref: PBRT v3, 13.6.7 "Piecewise-Constant 2D Distributions".
// Note that we use the equiareal sphere-to-square mapping instead of the latitude-longitude one.
#include "Common.hlsl"
#include "ImageBasedLighting.hlsl"
/* --- Input --- */
#define TEXTURE_HEIGHT 256 // Equiareal texture map: cos(theta) = 1.0 - 2.0 * v
#define TEXTURE_WIDTH 2 * TEXTURE_HEIGHT // Equiareal texture map: phi = TWO_PI * (1.0 - u)
TEXTURECUBE(envMap); // Input cubemap
SAMPLERCUBE(sampler_envMap);
/* --- Output --- */
RWTexture2D<float> marginalRowDensities; // [(TEXTURE_HEIGHT + 1) x 1] (+ 1 for the image integral)
RWTexture2D<float> conditionalDensities; // [TEXTURE_WIDTH x TEXTURE_HEIGHT]
/* --- Implementation --- */
// Creates an access pattern which avoids shared memory bank conflicts.
#define NUM_BANKS 32
#define SHARED_MEM(x) ((x) + (x) / NUM_BANKS)
// Performs a block-level parallel scan.
// Ref: GPU Gems 3, Chapter 39: "Parallel Prefix Sum (Scan) with CUDA".
#define PARALLEL_SCAN(i, n, temp, sum) \
{ \
uint offset; \
\
/* Execute the up-sweep phase. */ \
for (offset = 1; offset <= n / 2; offset *= 2) \
{ \
GroupMemoryBarrierWithGroupSync(); \
\
/*** a1 = (2 * i + 1) * offset - 1 */ \
uint a1 = Mad24(Mad24(2, i, 1), offset, -1); \
uint a2 = a1 + offset; \
\
if (a2 < n) \
{ \
temp[SHARED_MEM(a2)] += temp[SHARED_MEM(a1)]; \
} \
} \
\
GroupMemoryBarrierWithGroupSync(); \
\
/* Prevent NaNs arising from the division of 0 by 0. */ \
sum = max(temp[SHARED_MEM(n - 1)], FLT_MIN); \
\
GroupMemoryBarrierWithGroupSync(); \
\
/* The exclusive scan requires the last element to be 0. */ \
if (i == 0) \
{ \
temp[SHARED_MEM(n - 1)] = 0.0; \
} \
\
/* Execute the down-sweep phase. */ \
for (offset = n / 2; offset > 0; offset /= 2) \
{ \
GroupMemoryBarrierWithGroupSync(); \
\
/*** a1 = (2 * i + 1) * offset - 1 */ \
uint a1 = Mad24(Mad24(2, i, 1), offset, -1); \
uint a2 = a1 + offset; \
\
if (a2 < n) \
{ \
float t1 = temp[SHARED_MEM(a1)]; \
temp[SHARED_MEM(a1)] = temp[SHARED_MEM(a2)]; \
temp[SHARED_MEM(a2)] += t1; \
} \
} \
\
GroupMemoryBarrierWithGroupSync(); \
}
#pragma kernel ComputeConditionalDensities
groupshared float rowVals[SHARED_MEM(TEXTURE_WIDTH)];
[numthreads(TEXTURE_WIDTH / 2, 1, 1)]
void ComputeConditionalDensities(uint3 groupId : SV_GroupID,
uint3 groupThreadId : SV_GroupThreadID)
{
// There are TEXTURE_HEIGHT thread groups processing 2 texels per thread.
const uint n = TEXTURE_WIDTH;
const uint i = groupThreadId.x;
const uint j = groupId.x;
const uint i1 = i;
const uint i2 = i + n / 2;
float w = TEXTURE_WIDTH;
float h = TEXTURE_HEIGHT;
float u1 = i1 / w + 0.5 / w;
float u2 = i2 / w + 0.5 / w;
float v = j / h + 0.5 / h;
float3 L1 = ConvertEquiarealToCubemap(u1, v);
float3 L2 = ConvertEquiarealToCubemap(u2, v);
float3 c1 = SAMPLE_TEXTURECUBE_LOD(envMap, sampler_envMap, L1, 0).rgb;
float3 c2 = SAMPLE_TEXTURECUBE_LOD(envMap, sampler_envMap, L2, 0).rgb;
// Compute the integral of the step function (row values).
// TODO: process 4 texels per thread, and manually unroll.
rowVals[SHARED_MEM(i1)] = c1.r + c1.g + c1.b;
rowVals[SHARED_MEM(i2)] = c2.r + c2.g + c2.b;
float rowValSum;
PARALLEL_SCAN(i, n, rowVals, rowValSum)
// Compute the CDF. Note: the value at (i = n) is implicitly 1.
conditionalDensities[uint2(i1, j)] = rowVals[SHARED_MEM(i1)] / rowValSum;
conditionalDensities[uint2(i2, j)] = rowVals[SHARED_MEM(i2)] / rowValSum;
if (i == 0)
{
float rowIntegralValue = rowValSum / n;
marginalRowDensities[uint2(j, 0)] = rowIntegralValue;
}
}
#pragma kernel ComputeMarginalRowDensities
groupshared float rowInts[SHARED_MEM(TEXTURE_HEIGHT)];
[numthreads(TEXTURE_HEIGHT / 2, 1, 1)]
void ComputeMarginalRowDensities(uint3 groupThreadId : SV_GroupThreadID)
{
// There is only one thread group processing 2 texels per thread.
const uint n = TEXTURE_HEIGHT;
const uint i = groupThreadId.x;
const uint i1 = i;
const uint i2 = i + n / 2;
// Compute the integral of the step function (row integrals).
// TODO: process 4 texels per thread, and manually unroll.
rowInts[SHARED_MEM(i1)] = marginalRowDensities[uint2(i1, 0)];
rowInts[SHARED_MEM(i2)] = marginalRowDensities[uint2(i2, 0)];
float rowIntSum;
PARALLEL_SCAN(i, n, rowInts, rowIntSum)
// Compute the CDF. Note: the value at (i = n) is implicitly 1.
marginalRowDensities[uint2(i1, 0)] = rowInts[SHARED_MEM(i1)] / rowIntSum;
marginalRowDensities[uint2(i2, 0)] = rowInts[SHARED_MEM(i2)] / rowIntSum;
if (i == 0)
{
float imgIntegralValue = rowIntSum / n;
marginalRowDensities[uint2(n, 0)] = imgIntegralValue;
}
}

9
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/BuildProbabilityTables.compute.meta


fileFormatVersion: 2
guid: b9f26cf340afe9145a699753531b2a4c
timeCreated: 1482419936
licenseType: Pro
ComputeShaderImporter:
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:

14
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs.hlsl


//
// This file was automatically generated from Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyManager.cs. Please don't edit by hand.
//
#ifndef SKYMANAGER_CS_HLSL
#define SKYMANAGER_CS_HLSL
//
// UnityEngine.Experimental.ScriptableRenderLoop.LightSamplingParameters: static fields
//
#define LIGHTSAMPLINGPARAMETERS_TEXTURE_HEIGHT (256)
#define LIGHTSAMPLINGPARAMETERS_TEXTURE_WIDTH (512)
#endif
正在加载...
取消
保存