Photon Engine 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
THemisphere.h
Go to the documentation of this file.
1#pragma once
2
3#include "Math/constant.h"
4
5#include <Common/assertion.h>
6
7#include <cmath>
8#include <array>
9
10namespace ph::math
11{
12
19template<typename T>
20class THemisphere final
21{
22public:
23 static THemisphere makeUnit();
24
25 THemisphere() = default;
26
27 explicit THemisphere(T radius);
28
31 T getArea() const;
32
40 TVector3<T> sampleToSurfaceArchimedes(const std::array<T, 2>& sample) const;
41 TVector3<T> sampleToSurfaceArchimedes(const std::array<T, 2>& sample, T* out_pdfA) const;
42
43 TVector3<T> sampleToSurfaceCosThetaWeighted(const std::array<T, 2>& sample) const;
44 TVector3<T> sampleToSurfaceCosThetaWeighted(const std::array<T, 2>& sample, T* out_pdfA) const;
45
46 TVector3<T> sampleToSurfaceCosLobeWeighted(const std::array<T, 2>& sample, T exponent) const;
47 TVector3<T> sampleToSurfaceCosLobeWeighted(const std::array<T, 2>& sample, T exponent, T* out_pdfA) const;
48
49private:
50 T m_radius;
51};
52
53// In-header Implementations:
54
55template<typename T>
60
61template<typename T>
62inline THemisphere<T>::THemisphere(const T radius) :
63 m_radius(radius)
64{
65 PH_ASSERT_GE(radius, T(0));
66}
67
68template<typename T>
70{
71 return constant::two_pi<T> * m_radius * m_radius;
72}
73
74template<typename T>
75inline TVector3<T> THemisphere<T>::sampleToSurfaceArchimedes(const std::array<T, 2>& sample) const
76{
77 PH_ASSERT_LE(T(0), sample[0]); PH_ASSERT_LE(sample[0], T(1));
78 PH_ASSERT_LE(T(0), sample[1]); PH_ASSERT_LE(sample[1], T(1));
79
80 const T phi = constant::two_pi<T> * sample[0];
81 const T yValue = sample[1];
82 const T yRadius = std::sqrt(T(1) - yValue * yValue);
83
84 const auto localUnitPos = TVector3<T>(
85 std::sin(phi) * yRadius,
86 yValue,
87 std::cos(phi) * yRadius);
88
89 return localUnitPos.mul(m_radius);
90}
91
92template<typename T>
94 const std::array<T, 2>& sample, T* const out_pdfA) const
95{
96 // PDF_A is 1/(2*pi*r^2)
97 PH_ASSERT(out_pdfA);
98 *out_pdfA = T(1) / getArea();
99
100 return sampleToSurfaceArchimedes(sample);
101}
102
103template<typename T>
104inline TVector3<T> THemisphere<T>::sampleToSurfaceCosThetaWeighted(const std::array<T, 2>& sample) const
105{
106 PH_ASSERT_LE(static_cast<T>(0), sample[0]); PH_ASSERT_LE(sample[0], static_cast<T>(1));
107 PH_ASSERT_LE(static_cast<T>(0), sample[1]); PH_ASSERT_LE(sample[1], static_cast<T>(1));
108
109 const T phi = constant::two_pi<T> * sample[0];
110 const T yValue = std::sqrt(sample[1]);
111 const T yRadius = std::sqrt(static_cast<T>(1) - yValue * yValue);// TODO: y*y is in fact valueB?
112
113 const auto localUnitPos = TVector3<T>(
114 std::sin(phi) * yRadius,
115 yValue,
116 std::cos(phi) * yRadius);
117
118 return localUnitPos.mul(m_radius);
119}
120
121template<typename T>
123 const std::array<T, 2>& sample, T* const out_pdfA) const
124{
125 const auto localPos = sampleToSurfaceCosThetaWeighted(sample);
126
127 PH_ASSERT_GE(localPos.y(), static_cast<T>(0));
128 const T cosTheta = localPos.y() / m_radius;
129
130 // PDF_A is cos(theta)/(pi*r^2)
131 PH_ASSERT(out_pdfA);
132 *out_pdfA = cosTheta / (constant::pi<real> * m_radius * m_radius);
133
134 return localPos;
135}
136
137template<typename T>
139 const std::array<T, 2>& sample, const T exponent) const
140{
141 PH_ASSERT_LE(static_cast<T>(0), sample[0]); PH_ASSERT_LE(sample[0], static_cast<T>(1));
142 PH_ASSERT_LE(static_cast<T>(0), sample[1]); PH_ASSERT_LE(sample[1], static_cast<T>(1));
143
144 const T phi = constant::two_pi<T> * sample[0];
145 const T cosTheta = std::pow(sample[1], static_cast<T>(1) / (exponent + static_cast<T>(1)));
146 const T sinTheta = std::sqrt(static_cast<T>(1) - cosTheta * cosTheta);
147
148 const auto localUnitPos = TVector3<T>(
149 std::sin(phi) * sinTheta,
150 cosTheta,
151 std::cos(phi) * sinTheta);
152
153 return localUnitPos.mul(m_radius);
154}
155
156template<typename T>
158 const std::array<T, 2>& sample, const T exponent, T* const out_pdfA) const
159{
160 const auto localPos = sampleToSurfaceCosLobeWeighted(exponent, sample);
161
162 PH_ASSERT_GE(localPos.y, static_cast<T>(0));
163 const T cosTheta = localPos.y / m_radius;
164
165 // PDF_A is (exponent+1)/(2*pi)*cos(theta)^n
166 PH_ASSERT(out_pdfA);
167 *out_pdfA = (exponent + static_cast<T>(1)) * constant::rcp_two_pi<T> * std::pow(cosTheta, exponent);
168 *out_pdfA /= m_radius * m_radius;
169
170 return localPos;
171}
172
173}// end namespace ph::math
A hemisphere in 3-D space.
Definition THemisphere.h:21
TVector3< T > sampleToSurfaceCosLobeWeighted(const std::array< T, 2 > &sample, T exponent) const
Definition THemisphere.h:138
TVector3< T > sampleToSurfaceCosThetaWeighted(const std::array< T, 2 > &sample) const
Definition THemisphere.h:104
static THemisphere makeUnit()
Definition THemisphere.h:56
T getArea() const
The area of the dome part.
Definition THemisphere.h:69
TVector3< T > sampleToSurfaceArchimedes(const std::array< T, 2 > &sample) const
Map the 2D sample to a position on the surface of the hemisphere.
Definition THemisphere.h:75
Represents a 3-D vector.
Definition TVector3.h:17
constexpr T rcp_two_pi
Value of .
Definition constant.h:33
constexpr T two_pi
Value of .
Definition constant.h:27
constexpr T pi
Value of .
Definition constant.h:15
Math functions and utilities.
Definition TransformInfo.h:10