2026-04-16 오브젝트 그림자

This commit is contained in:
skrwns304@gmail.com
2026-04-16 04:58:10 +09:00
parent 0fe8b18872
commit 42646a636f
303 changed files with 54374 additions and 20 deletions

View File

@@ -0,0 +1,98 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// "Charlie" Sheen Implementation
/// Source from Sony Pictures Imageworks by Estevez and Kulla, "Production Friendly Microfacet Sheen BRDF" (http://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_sheen.pdf)
/// Details: https://knarkowicz.wordpress.com/2018/01/04/cloth-shading/
/// </summary>
public struct BRDF_Charlie : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
_alpha = Mathf.Max(0.002f, _alpha);
Vector3 H = Vector3.Normalize(_tsView + _tsLight);
double NdotL = _tsLight.z;
double NdotV = _tsView.z;
double NdotH = H.z;
// D
double D = CharlieD(_alpha, NdotH);
// Ashikmin masking/shadowing
// double G = V_Ashikhmin( NdotV, NdotL );
double G = V_Charlie(NdotV, NdotL, _alpha);
// fr = F(H) * G(V, L) * D(H)
// Note that the usual 1 / (4 * (N.L) * (N.V)) part of the Cook-Torrance micro-facet model is actually contained in the G visibility term in our case (as reported by Ashkmin in "Distribution-based BRDFs" eq. 2)
double res = D * G * NdotL; // We also include the (N.L) term here
// We're using uniform distribution
_pdf = 0.5 / Math.PI;
return res;
}
// Paper recommend plain uniform sampling of upper hemisphere instead of importance sampling for Charlie
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
float phi = 2.0f * Mathf.PI * _U1;
float cosTheta = 1.0f - _U2;
float sinTheta = Mathf.Sqrt(1 - cosTheta * cosTheta);
_direction = new Vector3(sinTheta * Mathf.Cos(phi), sinTheta * Mathf.Sin(phi), cosTheta);
}
double CharlieD(float _roughness, double _NdotH)
{
double invR = 1.0 / _roughness;
double cos2h = _NdotH * _NdotH;
double sin2h = 1.0f - cos2h;
double res = (2.0 + invR) * Math.Pow(sin2h, invR * 0.5) / (2.0 * Math.PI);
return res;
}
double V_Ashikhmin(double _NdotV, double _NdotL)
{
return 1.0 / (4.0 * (_NdotL + _NdotV - _NdotL * _NdotV));
}
// Note: This version doesn't include the softening of the paper: Production Friendly Microfacet Sheen BRDF
double V_Charlie(double _NdotV, double _NdotL, double _roughness)
{
double lambdaV = _NdotV < 0.5 ? Math.Exp(CharlieL(_NdotV, _roughness)) : Math.Exp(2.0 * CharlieL(0.5, _roughness) - CharlieL(1.0 - _NdotV, _roughness));
double lambdaL = _NdotL < 0.5 ? Math.Exp(CharlieL(_NdotL, _roughness)) : Math.Exp(2.0 * CharlieL(0.5, _roughness) - CharlieL(1.0 - _NdotL, _roughness));
return 1.0 / ((1.0 + lambdaV + lambdaL) * (4.0 * _NdotV * _NdotL));
}
double CharlieL(double x, double _roughness)
{
float r = Mathf.Clamp01((float)_roughness);
r = 1.0f - r * r;
float a = Mathf.Lerp(25.3245f, 21.5473f, r);
float b = Mathf.Lerp(3.32435f, 3.82987f, r);
float c = Mathf.Lerp(0.16801f, 0.19823f, r);
float d = Mathf.Lerp(-1.27393f, -1.97760f, r);
float e = Mathf.Lerp(-4.85967f, -4.32054f, r);
double res = a / (1.0 + b * Math.Pow(Math.Max(0, x), c)) + d * x + e;
return res;
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.Charlie;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e3273a65ebf1c474397e1eb12a73cf98
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_Charlie.cs
uploadId: 884030

View File

@@ -0,0 +1,60 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// Cook-Torrance implementation of the BRDF interface
/// </summary>
public struct BRDF_CookTorrance : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
_alpha = Mathf.Max(0.002f, _alpha);
Vector3 H = (_tsView + _tsLight).normalized;
double NdotL = Math.Max(1e-8, _tsLight.z);
double NdotV = Math.Max(1e-8, _tsView.z);
double NdotH = H.z;
double LdotH = Math.Max(1e-8, Vector3.Dot(_tsLight, H));
// D
double cosb2 = NdotH * NdotH;
double m2 = _alpha * _alpha;
double D = Math.Exp((cosb2 - 1.0) / (cosb2 * m2)) // exp( -tan(a)² / m² )
/ Math.Max(1e-12, Math.PI * m2 * cosb2 * cosb2); // / (PI * m² * cos(a)^4)
// masking/shadowing
double G = Math.Min(1, 2.0 * NdotH * Math.Min(NdotV, NdotL) / LdotH);
// fr = F(H) * G(V, L) * D(H) / (4 * (N.L) * (N.V))
double res = D * G / (4.0 * NdotV); // Full specular mico-facet model is F * D * G / (4 * NdotL * NdotV) but since we're fitting with the NdotL included, it gets nicely canceled out!
// pdf = D(H) * (N.H) / (4 * (L.H))
_pdf = Math.Abs(D * NdotH / (4.0 * LdotH));
return res;
}
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
float phi = 2.0f * Mathf.PI * _U1;
float cosTheta = 1.0f / Mathf.Sqrt(1 - _alpha * _alpha * Mathf.Log(Mathf.Max(1e-6f, _U2)));
float sinTheta = Mathf.Sqrt(1 - cosTheta * cosTheta);
Vector3 H = new Vector3(sinTheta * Mathf.Cos(phi), sinTheta * Mathf.Sin(phi), cosTheta);
_direction = 2.0f * Vector3.Dot(H, _tsView) * H - _tsView; // Mirror view direction
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.CookTorrance;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 432ee4d0aec53c943894a42d0bf30444
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_CookTorrance.cs
uploadId: 884030

View File

@@ -0,0 +1,83 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// Disney Diffuse Implementation
/// Source from 2012 Burley, B. "Physically-Based Shading at Disney" Section 5.3
/// (https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf)
/// </summary>
public struct BRDF_Disney : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
_alpha = Mathf.Max(0.002f, _alpha);
double NdotL = Math.Max(0, _tsLight.z);
double NdotV = Math.Max(0, _tsView.z);
double LdotV = Math.Max(0, Vector3.Dot(_tsLight, _tsView));
double perceptualRoughness = Math.Sqrt(_alpha);
// (2 * LdotH * LdotH) = 1 + LdotV
// real fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
double fd90 = 0.5 + (perceptualRoughness + perceptualRoughness * LdotV);
// Two schlick fresnel term
double lightScatter = F_Schlick(1.0, fd90, NdotL);
double viewScatter = F_Schlick(1.0, fd90, NdotV);
// Normalize the BRDF for polar view angles of up to (Pi/4).
// We use the worst case of (roughness = albedo = 1), and, for each view angle,
// integrate (brdf * cos(theta_light)) over all light directions.
// The resulting value is for (theta_view = 0), which is actually a little bit larger
// than the value of the integral for (theta_view = Pi/4).
// Hopefully, the compiler folds the constant together with (1/Pi).
double res = lightScatter * viewScatter / Math.PI;
res /= 1.03571;
// Remember we must include the N.L term!
res *= NdotL;
// Cosine-weighted hemisphere sampling
_pdf = NdotL / Math.PI;
return res;
}
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
// Performs uniform sampling of the unit disk.
// Ref: PBRT v3, p. 777.
float r = Mathf.Sqrt(_U1);
float phi = 2.0f * Mathf.PI * _U2;
// Performs cosine-weighted sampling of the hemisphere.
// Ref: PBRT v3, p. 780.
_direction.x = r * Mathf.Cos(phi);
_direction.y = r * Mathf.Sin(phi);
_direction.z = Mathf.Sqrt(1 - _U1); // Project the point from the disk onto the hemisphere.
}
double F_Schlick(double _F0, double _F90, double _cosTheta)
{
double x = 1.0 - _cosTheta;
double x2 = x * x;
double x5 = x * x2 * x2;
return (_F90 - _F0) * x5 + _F0; // sub mul mul mul sub mad
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.DisneyDiffuse;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ff4aa0c2af19abb42bade44e76256186
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_Disney.cs
uploadId: 884030

View File

@@ -0,0 +1,74 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// GGX implementation of the BRDF interface
/// </summary>
public class BRDF_GGX : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
// masking
double lambdaV = Lambda(_tsView.z, _alpha);
// shadowing
double G2 = 0;
if (_tsLight.z > 0.0f)
{
double lambdaL = Lambda(_tsLight.z, _alpha);
G2 = 1.0 / (1.0 + lambdaV + lambdaL);
}
// D
Vector3 H = _tsView + _tsLight;
float lengthH = H.magnitude;
if (lengthH > 1e-8f)
H = H / lengthH;
else
H = new Vector3(0, 0, 1);
double slopex = H.x / H.z;
double slopey = H.y / H.z;
double D = 1.0 / (1.0 + (slopex * slopex + slopey * slopey) / _alpha / _alpha);
D = D * D;
D = D / (Math.PI * _alpha * _alpha * H.z * H.z * H.z * H.z);
// Full specular mico-facet model is F * D * G / (4 * NdotL * NdotV) but since we're fitting with the NdotL included, it gets nicely canceled out!
double res = D * G2 / 4.0 / _tsView.z;
// pdf = D(H) * (N.H) / (4 * (L.H))
_pdf = Math.Abs(D * H.z / 4.0 / Vector3.Dot(_tsView, H));
return res;
}
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
float phi = 2.0f * Mathf.PI * _U1;
float r = _alpha * Mathf.Sqrt(_U2 / (1.0f - _U2));
Vector3 H = new Vector3(r * Mathf.Cos(phi), r * Mathf.Sin(phi), 1.0f).normalized;
_direction = -_tsView + 2.0f * H * Vector3.Dot(H, _tsView);
}
double Lambda(float _cosTheta, float _alpha)
{
double a = 1.0f / _alpha / Math.Tan(Math.Acos(_cosTheta));
double lambda = _cosTheta < 1.0 ? 0.5 * (-1.0 + Math.Sqrt(1.0 + 1.0 / (a * a))) : 0.0;
return lambda;
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.GGX;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e67e2cd414ae81a4f8f5a76bce9f6b35
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_GGX.cs
uploadId: 884030

View File

@@ -0,0 +1,38 @@
//////////////////////////////////////////////////////////////////////////
// BRDF Interface
//////////////////////////////////////////////////////////////////////////
//
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// BRDF Interface that you must implement in order to generate a new table
/// </summary>
public interface IBRDF
{
/// <summary>
/// Evaluation of the ***cosine-weighted*** BRDF
/// </summary>
/// <param name="_tsView">The vector pointing toward the camera</param>
/// <param name="_tsLight">The vector pointing toward the light</param>
/// <param name="_alpha">Surface roughness</param>
/// <param name="_pdf">The Probability Density Function of sampling the light in that direction</param>
/// <returns></returns>
double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf);
/// <summary>
/// Gets an importance-sampled light direction given a view vector and the surface roughness
/// </summary>
/// <param name="_tsView">The vector pointing toward the camera</param>
/// <param name="_alpha">>Surface roughness</param>
/// <param name="_U1">A random value in [0,1]</param>
/// <param name="_U2">A 2nd random value in [0,1]</param>
/// <param name="_direction">The generated direction</param>
void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction);
BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel();
};
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8e6541bb3b842494ab1ec4bf036a37e9
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_Interface.cs
uploadId: 884030

View File

@@ -0,0 +1,112 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// Disney Diffuse Implementation
/// Source from 2012 Burley, B. "Physically-Based Shading at Disney" Section 5.3
/// (https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf)
/// </summary>
public struct BRDF_KajiyaKaySpecular : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
_alpha = Mathf.Max(0.002f, _alpha);
double perceptualRoughness = Math.Sqrt(_alpha);
Vector3 T = Vector3.right;
Vector3 N = Vector3.forward;
double NdotV = Math.Max(0, _tsView.z);
double NdotL = Math.Max(0, _tsLight.z);
double LdotV = Math.Max(0, Vector3.Dot(_tsLight, _tsView));
Vector3 H = Vector3.Normalize(_tsLight + _tsView);
double LdotH = Math.Max(0, Vector3.Dot(_tsLight, H));
Vector3 t1 = ShiftTangent(T, N, 0.0f);
Vector3 t2 = ShiftTangent(T, N, 0.0f);
double specularExponent = RoughnessToBlinnPhongSpecularExponent(_alpha);
// Balancing energy between lobes, as well as between diffuse and specular is left to artists.
double hairSpec1 = D_KajiyaKay(t1, H, specularExponent);
double hairSpec2 = D_KajiyaKay(t2, H, specularExponent);
double fd90 = 0.5 + (perceptualRoughness + perceptualRoughness * LdotV);
double F = F_Schlick(1.0, fd90, LdotH);
// G = NdotL * NdotV.
double res = 0.25 * F * (hairSpec1 + hairSpec2) * NdotL * Math.Min(Math.Max(NdotV * double.MaxValue, 0.0), 1.0);
// Uniform Sampling
_pdf = 0.5 / Math.PI;
return res;
}
// Uniform Sampling
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
float phi = 2.0f * Mathf.PI * _U1;
float cosTheta = 1.0f - _U2;
float sinTheta = Mathf.Sqrt(1 - cosTheta * cosTheta);
_direction = new Vector3(sinTheta * Mathf.Cos(phi), sinTheta * Mathf.Sin(phi), cosTheta);
}
double RoughnessToBlinnPhongSpecularExponent(double roughness)
{
// 1e-4 and 3e3 are the lowest/highest values that do not cause numerical instabilities with the fitting tool
return Math.Min(Math.Max(2.0 / (roughness * roughness) - 2.0, 1e-4), 3e3);
}
double F_Schlick(double _F0, double _F90, double _cosTheta)
{
double x = 1.0f - _cosTheta;
double x2 = x * x;
double x5 = x * x2 * x2;
return (_F90 - _F0) * x5 + _F0; // sub mul mul mul sub mad
}
//http://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf
Vector3 ShiftTangent(Vector3 T, Vector3 N, float shift)
{
return Vector3.Normalize(T + N * shift);
}
double PositivePow(double value, double power)
{
return Math.Pow(Math.Max(Math.Abs(value), 1.192092896e-07), power);
}
double D_KajiyaKay(Vector3 T, Vector3 H, double specularExponent)
{
float TdotH = Vector3.Dot(T, H);
float sinTHSq = Mathf.Clamp(1.0f - TdotH * TdotH, 0.0f, 1.0f);
float dirAttn = Mathf.Clamp(TdotH + 1.0f, 0.0f, 1.0f); // Evgenii: this seems like a hack? Do we really need this?
// Note: Kajiya-Kay is not energy conserving.
// We attempt at least some energy conservation by approximately normalizing Blinn-Phong NDF.
// We use the formulation with the NdotL.
// See http://www.thetenthplanet.de/archives/255.
double n = specularExponent;
double norm = (n + 2) / (2.0 * Math.PI);
return dirAttn * norm * PositivePow(sinTHSq, 0.5 * n);
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.KajiyaKaySpecular;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4288b6ce37f7e2f40b421a4053ff7b73
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_KajiyaKaySpecular.cs
uploadId: 884030

View File

@@ -0,0 +1,27 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
public struct BRDF_Marschner : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
// Uniform sampled over a sphere.
_pdf = 1f / (4f * Math.PI);
return 0f;
}
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
_direction = Vector3.up;
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.Marschner;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4986784e6e6a4a048aa882f5bcd44d55
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_Marschner.cs
uploadId: 884030

View File

@@ -0,0 +1,80 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// Oren-Nayar Implementation
/// Source from 1994 Oren, M. Nayar, S. K. "Generalization of Lambert's Reflectance Model"
/// </summary>
public struct BRDF_OrenNayar : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
float sigma = Mathf.Max(0.002f, 0.5f * Mathf.PI * _alpha); // Standard deviation is a [0,PI/2] angle
double NdotL = Math.Max(0, _tsLight.z);
double NdotV = Math.Max(0, _tsView.z);
double gamma = (_tsView.x * _tsLight.x + _tsView.y * _tsLight.y)
/ Math.Max(1e-20, Math.Sqrt(1.0 - NdotV * NdotV) * Math.Sqrt(1.0 - NdotL * NdotL));
double rough_sq = sigma * sigma;
double A = 1.0 - 0.5 * (rough_sq / (rough_sq + 0.57)); // You can replace 0.33 by 0.57 to simulate the missing inter-reflection term, as specified in footnote of page 22 of the 1992 paper
double B = 0.45 * (rough_sq / (rough_sq + 0.09));
// Original formulation
// float angle_vn = acos( NdotV );
// float angle_ln = acos( NdotL );
// float alpha = max( angle_vn, angle_ln );
// float beta = min( angle_vn, angle_ln );
// float C = sin(alpha) * tan(beta);
// Optimized formulation (without tangents, arccos or sines)
double cos_alpha = NdotV < NdotL ? NdotV : NdotL;
double cos_beta = NdotV < NdotL ? NdotL : NdotV;
double sin_alpha = Math.Sqrt(1.0 - cos_alpha * cos_alpha);
double sin_beta = Math.Sqrt(1.0 - cos_beta * cos_beta);
double C = sin_alpha * sin_beta / Math.Max(1e-20, cos_beta);
double res = A + B * Math.Max(0.0, gamma) * C;
res /= Math.PI;
// Remember we must include the N.L term!
res *= NdotL;
// Cosine-weighted hemisphere sampling
_pdf = NdotL / Math.PI;
return res;
}
// Here we use a simple cosine-weighted hemisphere sampling
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
// Performs uniform sampling of the unit disk.
// Ref: PBRT v3, p. 777.
float r = Mathf.Sqrt(_U1);
float phi = 2.0f * Mathf.PI * _U2;
// Performs cosine-weighted sampling of the hemisphere.
// Ref: PBRT v3, p. 780.
_direction.x = r * Mathf.Cos(phi);
_direction.y = r * Mathf.Sin(phi);
_direction.z = Mathf.Sqrt(1 - _U1); // Project the point from the disk onto the hemisphere.
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.OrenNayar;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: cdf80bc060c4e8d4a8665c2b4a01044b
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_OrenNayar.cs
uploadId: 884030

View File

@@ -0,0 +1,65 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace BadDog.Rendering.AreaLight.LTC
{
/// <summary>
/// Ward implementation of the BRDF interface
// Formulas come from -> Walter, B. 2005 "Notes on the Ward BRDF" (https://pdfs.semanticscholar.org/330e/59117d7da6c794750730a15f9a178391b9fe.pdf)
// The BRDF though, is the one most proeminently used by the AxF materials and is based on the Geisler-Moroder variation of Ward (http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.169.9908&rep=rep1&type=pdf)
/// </summary>
public struct BRDF_Ward : IBRDF
{
public double Eval(ref Vector3 _tsView, ref Vector3 _tsLight, float _alpha, out double _pdf)
{
if (_tsView.z <= 0)
{
_pdf = 0;
return 0;
}
_alpha = Mathf.Max(0.002f, _alpha);
Vector3 H = (_tsView + _tsLight).normalized;
double NdotL = Math.Max(1e-8, _tsLight.z);
double NdotH = Math.Max(1e-8, H.z);
double LdotH = Math.Max(1e-8, Vector3.Dot(_tsLight, H));
// D (basically a Beckmann distribution + an additional divider for albedo bounding)
double m2 = _alpha * _alpha;
double cosb2 = NdotH * NdotH;
double D = Math.Exp(-(1 - cosb2) / (m2 * cosb2)) // exp( -tan(a)² / m² )
/ (Math.PI * m2 * cosb2 * cosb2); // / (PI * m² * cos(a)^4)
D /= 4.0 * LdotH * LdotH; // Moroder
// fr = F(H) * D(H)
double res = D;
// Remember we must include the N.L term!
res *= NdotL;
// From Walter, eq. 24 we know that pdf(H) = D(H) * (N.H)
_pdf = Math.Abs(D * NdotH);
return res;
}
public void GetSamplingDirection(ref Vector3 _tsView, float _alpha, float _U1, float _U2, ref Vector3 _direction)
{
// Ward NDF sampling (eqs. 6 & 7 from above paper)
float tanTheta = _alpha * Mathf.Sqrt(-Mathf.Log(Mathf.Max(1e-6f, _U1)));
float phi = _U2 * 2.0f * Mathf.PI;
float cosTheta = 1.0f / Mathf.Sqrt(1 + tanTheta * tanTheta);
float sinTheta = Mathf.Sqrt(1 - cosTheta * cosTheta);
Vector3 H = new Vector3(sinTheta * Mathf.Cos(phi), sinTheta * Mathf.Sin(phi), cosTheta);
_direction = 2.0f * Vector3.Dot(H, _tsView) * H - _tsView; // Mirror view direction
}
public BadDog.Rendering.AreaLight.LTCLightingModel GetLightingModel()
{
return BadDog.Rendering.AreaLight.LTCLightingModel.Ward;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 70fe8e92f23e84f49aabe7648f8e96f3
AssetOrigin:
serializedVersion: 1
productId: 346790
packageName: Realtime Area Light for URP
packageVersion: 1.3.0
assetPath: Packages/com.baddog.rendering.arealight/Runtime/Material/LTCAreaLight/BRDF/BRDF_Ward.cs
uploadId: 884030