You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

79 lines
3.0 KiB

using System;
using UnityEngine.Rendering;
namespace UnityEngine.Rendering.HighDefinition.LTC
{
/// <summary>
/// Oren-Nayar Implementation
/// Source from 1994 Oren, M. Nayar, S. K. "Generalization of Lambert's Reflectance Model"
/// </summary>
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 LTCLightingModel GetLightingModel()
{
return LTCLightingModel.OrenNayar;
}
}
}