1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "MicrofacetDistribution.ih"
#include "math/sampling.ih"
OSPRAY_BEGIN_ISPC_NAMESPACE
// Cylindrical microfiber distribution for sheen
// [Conty and Kulla, 2017, "Production Friendly Microfacet Sheen BRDF"]
// [Kulla and Conty, 2017, "Revisiting Physically Based Shading at Imageworks"]
struct SheenDistribution
{
float r; // in (0, 1]
};
inline SheenDistribution make_SheenDistribution(float r)
{
SheenDistribution self;
self.r = r;
return self;
}
inline float eval(const SheenDistribution &self, float cosTheta)
{
float sinTheta = cos2sin(cosTheta);
float invr = rcp(self.r);
return (2.f + invr) * pow(sinTheta, invr) * (float)one_over_two_pi;
}
// Helper function for computing Lambda
inline float evalL(const SheenDistribution &self, float x)
{
const float a0 = 25.3245f;
const float a1 = 21.5473f;
const float b0 = 3.32435f;
const float b1 = 3.82987f;
const float c0 = 0.16801f;
const float c1 = 0.19823f;
const float d0 = -1.27393f;
const float d1 = -1.97760f;
const float e0 = -4.85967f;
const float e1 = -4.32054f;
float r = self.r;
float w0 = sqr(1.f - r);
float w1 = 1.f - w0;
float a = w0 * a0 + w1 * a1;
float b = w0 * b0 + w1 * b1;
float c = w0 * c0 + w1 * c1;
float d = w0 * d0 + w1 * d1;
float e = w0 * e0 + w1 * e1;
return a / (1.f + b * pow(x, c)) + d * x + e;
}
inline float evalLambda(const SheenDistribution &self, float cosTheta)
{
if (cosTheta < 0.5f)
return exp(evalL(self, cosTheta));
else
return exp(2.f * evalL(self, 0.5f) - evalL(self, 1.f - cosTheta));
}
// Non-physical artistic adjustment for a softer light terminator
inline float evalLambdaI(const SheenDistribution &self, float cosTheta)
{
float x = 1.f + 2.f * sqr(sqr(sqr(1.f - cosTheta)));
return pow(evalLambda(self, cosTheta), x);
}
// Smith's height-correlated masking-shadowing function
// [Heitz, 2014, "Understanding the Masking-Shadowing Function in
// Microfacet-Based BRDFs"]
inline float evalG2(const SheenDistribution &self,
float cosThetaO,
float cosThetaI,
float cosThetaOH,
float cosThetaIH)
{
if (cosThetaO * cosThetaOH <= 0.f || cosThetaI * cosThetaIH <= 0.f)
return 0.f;
// return rcp(1.f + evalLambda(self, cosThetaO) + evalLambda(self,
// cosThetaI));
return rcp(1.f + evalLambda(self, cosThetaO) + evalLambdaI(self, cosThetaI));
}
OSPRAY_END_ISPC_NAMESPACE
|