Skip to content

Commit 5c3f887

Browse files
authored
Merge pull request #1215 from est77/est-GTR1-microfacet-G
GTR1 microfacet G1
2 parents bf1b11c + afb1158 commit 5c3f887

File tree

6 files changed

+72
-117
lines changed

6 files changed

+72
-117
lines changed
-96 Bytes
Loading
-1.07 KB
Loading

src/appleseed/foundation/math/microfacet.h

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -829,16 +829,23 @@ class WardMDF
829829

830830

831831
//
832-
// Berry Microfacet Distribution Function.
833-
// Used in the Disney BRDF clearcoat layer.
832+
// GTR1 Microfacet Distribution Function.
833+
//
834+
// References:
835+
//
836+
// [1] Physically-Based Shading at Disney
837+
// https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf
838+
//
839+
// [2] Deriving the Smith shadowing function G1 for gamma (0, 4]
840+
// https://docs.chaosgroup.com/download/attachments/7147732/gtr_shadowing.pdf?version=2&modificationDate=1434539612000&api=v2
834841
//
835842

836843
template <typename T>
837-
class BerryMDF
844+
class GTR1MDF
838845
: public MDF<T>
839846
{
840847
public:
841-
BerryMDF() {}
848+
GTR1MDF() {}
842849

843850
virtual T D(
844851
const Vector<T, 3>& h,
@@ -859,9 +866,7 @@ class BerryMDF
859866
const T alpha_x,
860867
const T alpha_y) const APPLESEED_OVERRIDE
861868
{
862-
return
863-
G1(outgoing, h, alpha_x, alpha_y) *
864-
G1(incoming, h, alpha_x, alpha_y);
869+
return T(1.0) / (T(1.0) + lambda(outgoing, alpha_x, alpha_y) + lambda(incoming, alpha_x, alpha_y));
865870
}
866871

867872
virtual T G1(
@@ -870,20 +875,35 @@ class BerryMDF
870875
const T alpha_x,
871876
const T alpha_y) const APPLESEED_OVERRIDE
872877
{
873-
if (dot(v, m) * v.y <= T(0.0))
874-
return T(0.0);
878+
return T(1.0) / (T(1.0) + lambda(v, alpha_x, alpha_y));
879+
}
875880

881+
T lambda(
882+
const Vector<T, 3>& v,
883+
const T alpha_x,
884+
const T alpha_y) const
885+
{
876886
const T cos_theta = std::abs(v.y);
887+
888+
if (cos_theta == T(0.0))
889+
return T(0.0);
890+
891+
if (cos_theta == T(1.0))
892+
return T(1.0);
893+
894+
// [2] section 3.2.
877895
const T cos_theta_2 = square(cos_theta);
878896
const T sin_theta = MDF<T>::sin_theta(v);
879-
const T tan_theta_2 = square(sin_theta) / cos_theta_2;
897+
const T cot_theta_2 = cos_theta_2 / square(sin_theta);
898+
const T cot_theta = std::sqrt(cot_theta_2);
899+
const T alpha_2 = square(alpha_x);
880900

881-
if (tan_theta_2 == T(0.0))
882-
return T(1.0);
901+
const T a = std::sqrt(cot_theta_2 + alpha_2);
902+
const T b = std::sqrt(cot_theta_2 + T(1.0));
903+
const T c = std::log(cot_theta + b);
904+
const T d = std::log(cot_theta + a);
883905

884-
const T a2_rcp = square(alpha_x) * tan_theta_2;
885-
const T lambda = (T(-1.0) + std::sqrt(T(1.0) + a2_rcp)) * T(0.5);
886-
return T(1.0) / (T(1.0) + lambda);
906+
return (a - b + cot_theta * (c - d)) / (cot_theta * std::log(alpha_2));
887907
}
888908

889909
virtual Vector<T, 3> sample(
@@ -892,9 +912,9 @@ class BerryMDF
892912
const T alpha_x,
893913
const T alpha_y) const APPLESEED_OVERRIDE
894914
{
895-
const T alpha_x_2 = square(alpha_x);
896-
const T a = T(1.0) - std::pow(alpha_x_2, T(1.0) - s[0]);
897-
const T cos_theta = std::sqrt(a / (T(1.0) - alpha_x_2));
915+
const T alpha2 = square(alpha_x);
916+
const T a = T(1.0) - std::pow(alpha2, T(1.0) - s[0]);
917+
const T cos_theta = std::sqrt(a / (T(1.0) - alpha2));
898918
const T sin_theta = std::sqrt(T(1.0) - square(cos_theta));
899919

900920
T cos_phi, sin_phi;

src/appleseed/foundation/meta/tests/test_microfacet.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,19 +353,19 @@ TEST_SUITE(Foundation_Math_Microfacet)
353353

354354

355355
//
356-
// Berry MDF.
356+
// GTR1 MDF.
357357
//
358358

359-
TEST_CASE(BerryMDF_Evaluate_ReturnsNonNegativeValues)
359+
TEST_CASE(GTR1MDF_Evaluate_ReturnsNonNegativeValues)
360360
{
361-
const BerryMDF<double> mdf;
361+
const GTR1MDF<double> mdf;
362362

363363
EXPECT_TRUE(is_positive(mdf, 10.0, 10.0, PositivityTestSampleCount));
364364
}
365365

366-
TEST_CASE(BerryMDF_Integral_EqualsOne)
366+
TEST_CASE(GTR1MDF_Integral_EqualsOne)
367367
{
368-
const BerryMDF<double> mdf;
368+
const GTR1MDF<double> mdf;
369369

370370
const double integral = integrate(mdf, 10.0, IntegrationSampleCount);
371371

src/appleseed/renderer/modeling/bsdf/disneybrdf.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -450,14 +450,12 @@ namespace
450450
else
451451
{
452452
const float alpha = clearcoat_roughness(values);
453-
const BerryMDF<float> berry_mdf;
453+
const GTR1MDF<float> gtr1_mdf;
454454
MicrofacetBRDFHelper::sample(
455455
sampling_context,
456-
berry_mdf,
456+
gtr1_mdf,
457457
alpha,
458458
alpha,
459-
0.25f,
460-
0.25f,
461459
DisneyClearcoatFresnelFun(*values),
462460
cos_on,
463461
sample);
@@ -548,13 +546,11 @@ namespace
548546
{
549547
Spectrum clear;
550548
const float alpha = clearcoat_roughness(values);
551-
const BerryMDF<float> berry_mdf;
549+
const GTR1MDF<float> gtr1_mdf;
552550
pdf += MicrofacetBRDFHelper::evaluate(
553-
berry_mdf,
551+
gtr1_mdf,
554552
alpha,
555553
alpha,
556-
0.25f,
557-
0.25f,
558554
shading_basis,
559555
outgoing,
560556
incoming,
@@ -633,9 +629,9 @@ namespace
633629
if (weights[CleatcoatComponent] != 0.0f)
634630
{
635631
const float alpha = clearcoat_roughness(values);
636-
const BerryMDF<float> berry_mdf;
632+
const GTR1MDF<float> gtr1_mdf;
637633
pdf += MicrofacetBRDFHelper::pdf(
638-
berry_mdf,
634+
gtr1_mdf,
639635
alpha,
640636
alpha,
641637
shading_basis,

src/appleseed/renderer/modeling/bsdf/microfacethelper.h

Lines changed: 23 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -90,84 +90,6 @@ class MicrofacetBRDFHelper
9090
FresnelFun f,
9191
const float cos_on,
9292
BSDFSample& sample)
93-
{
94-
// gcc needs the qualifier, otherwise
95-
// it complains about missing operator() for BSDFSample.
96-
MicrofacetBRDFHelper::sample(
97-
sampling_context,
98-
mdf,
99-
alpha_x,
100-
alpha_y,
101-
alpha_x,
102-
alpha_y,
103-
f,
104-
cos_on,
105-
sample);
106-
}
107-
108-
template <typename MDF, typename FresnelFun>
109-
static float evaluate(
110-
const MDF& mdf,
111-
const float alpha_x,
112-
const float alpha_y,
113-
const foundation::Basis3f& shading_basis,
114-
const foundation::Vector3f& outgoing,
115-
const foundation::Vector3f& incoming,
116-
FresnelFun f,
117-
const float cos_in,
118-
const float cos_on,
119-
Spectrum& value)
120-
{
121-
return evaluate(
122-
mdf,
123-
alpha_x,
124-
alpha_y,
125-
alpha_x,
126-
alpha_y,
127-
shading_basis,
128-
outgoing,
129-
incoming,
130-
f,
131-
cos_in,
132-
cos_on,
133-
value);
134-
}
135-
136-
template <typename MDF>
137-
static float pdf(
138-
const MDF& mdf,
139-
const float alpha_x,
140-
const float alpha_y,
141-
const foundation::Basis3f& shading_basis,
142-
const foundation::Vector3f& outgoing,
143-
const foundation::Vector3f& incoming)
144-
{
145-
const foundation::Vector3f h = foundation::normalize(incoming + outgoing);
146-
const float cos_oh = foundation::dot(outgoing, h);
147-
return
148-
mdf.pdf(
149-
shading_basis.transform_to_local(outgoing),
150-
shading_basis.transform_to_local(h),
151-
alpha_x,
152-
alpha_y) / (4.0f * cos_oh);
153-
}
154-
155-
//
156-
// Decoupled distribution and shadowing alpha parameters.
157-
// They are used in the Disney BRDF implementation.
158-
//
159-
160-
template <typename MDF, typename FresnelFun>
161-
static void sample(
162-
SamplingContext& sampling_context,
163-
const MDF& mdf,
164-
const float alpha_x,
165-
const float alpha_y,
166-
const float g_alpha_x,
167-
const float g_alpha_y,
168-
FresnelFun f,
169-
const float cos_on,
170-
BSDFSample& sample)
17193
{
17294
// Compute the incoming direction by sampling the MDF.
17395
sampling_context.split_in_place(3, 1);
@@ -190,8 +112,8 @@ class MicrofacetBRDFHelper
190112
sample.m_shading_basis.transform_to_local(incoming),
191113
wo,
192114
m,
193-
g_alpha_x,
194-
g_alpha_y);
115+
alpha_x,
116+
alpha_y);
195117

196118
f(sample.m_outgoing.get_value(), h, sample.m_shading_basis.get_normal(), sample.m_value);
197119
sample.m_value *= D * G / (4.0f * cos_on * cos_in);
@@ -206,8 +128,6 @@ class MicrofacetBRDFHelper
206128
const MDF& mdf,
207129
const float alpha_x,
208130
const float alpha_y,
209-
const float g_alpha_x,
210-
const float g_alpha_y,
211131
const foundation::Basis3f& shading_basis,
212132
const foundation::Vector3f& outgoing,
213133
const foundation::Vector3f& incoming,
@@ -226,14 +146,33 @@ class MicrofacetBRDFHelper
226146
shading_basis.transform_to_local(incoming),
227147
wo,
228148
m,
229-
g_alpha_x,
230-
g_alpha_y);
149+
alpha_x,
150+
alpha_y);
231151

232152
const float cos_oh = foundation::dot(outgoing, h);
233153
f(outgoing, h, shading_basis.get_normal(), value);
234154
value *= D * G / (4.0f * cos_on * cos_in);
235155
return mdf.pdf(wo, m, alpha_x, alpha_y) / (4.0f * cos_oh);
236156
}
157+
158+
template <typename MDF>
159+
static float pdf(
160+
const MDF& mdf,
161+
const float alpha_x,
162+
const float alpha_y,
163+
const foundation::Basis3f& shading_basis,
164+
const foundation::Vector3f& outgoing,
165+
const foundation::Vector3f& incoming)
166+
{
167+
const foundation::Vector3f h = foundation::normalize(incoming + outgoing);
168+
const float cos_oh = foundation::dot(outgoing, h);
169+
return
170+
mdf.pdf(
171+
shading_basis.transform_to_local(outgoing),
172+
shading_basis.transform_to_local(h),
173+
alpha_x,
174+
alpha_y) / (4.0f * cos_oh);
175+
}
237176
};
238177

239178
} // namespace renderer

0 commit comments

Comments
 (0)