1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 /*! \brief utility library containing sampling functions */
7 
8 // convention is to return the sample (Vec3fa) generated from given Vec2f 's'ample as last parameter
9 // sampling functions often come in pairs: sample and pdf (needed later for MIS)
10 // good reference is "Total Compendium" by Philip Dutre http://people.cs.kuleuven.be/~philip.dutre/GI/
11 
12 #include "../math/vec.h"
13 #include "../math/linearspace.h"
14 
15 namespace embree {
16 
17 struct Sample3f
18 {
19   Vec3fa v;
20   float pdf;
21 };
22 
make_Sample3f(const Vec3fa & v,const float pdf)23 inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) {
24   Sample3f s; s.v = v; s.pdf = pdf; return s;
25 }
26 
27 #if defined(ISPC)
make_Sample3f(const Vec3fa & v,const float pdf)28 inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) {
29   Sample3f s; s.v = v; s.pdf = pdf; return s;
30 }
31 #endif
32 
cartesian(const float phi,const float sinTheta,const float cosTheta)33 inline Vec3fa cartesian(const float phi, const float sinTheta, const float cosTheta)
34 {
35   const float sinPhi = sinf(phi);
36   const float cosPhi = cosf(phi);
37   //sincosf(phi, &sinPhi, &cosPhi);
38   return Vec3fa(cosPhi * sinTheta,
39                     sinPhi * sinTheta,
40                     cosTheta);
41 }
42 
cartesian(const float phi,const float cosTheta)43 inline Vec3fa cartesian(const float phi, const float cosTheta)
44 {
45   return cartesian(phi, cos2sin(cosTheta), cosTheta);
46 }
47 
48 
49 /// cosine-weighted sampling of hemisphere oriented along the +z-axis
50 ////////////////////////////////////////////////////////////////////////////////
51 
cosineSampleHemisphere(const Vec2f s)52 inline Vec3fa cosineSampleHemisphere(const Vec2f s)
53 {
54   const float phi =float(two_pi) * s.x;
55   const float cosTheta = sqrt(s.y);
56   const float sinTheta = sqrt(1.0f - s.y);
57   return cartesian(phi, sinTheta, cosTheta);
58 }
59 
cosineSampleHemispherePDF(const Vec3fa & dir)60 inline float cosineSampleHemispherePDF(const Vec3fa &dir)
61 {
62   return dir.z / float(M_PI);
63 }
64 
cosineSampleHemispherePDF(float cosTheta)65 inline float cosineSampleHemispherePDF(float cosTheta)
66 {
67   return cosTheta / float(M_PI);
68 }
69 
70 /*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */
cosineSampleHemisphere(const float u,const float v,const Vec3fa & N)71 inline Sample3f cosineSampleHemisphere(const float  u, const float  v, const Vec3fa& N)
72 {
73   Vec3fa localDir = cosineSampleHemisphere(Vec2f(u,v));
74   Sample3f s;
75   s.v = frame(N) * localDir;
76   s.pdf = cosineSampleHemispherePDF(localDir);
77   return s;
78 }
79 
80 /// power cosine-weighted sampling of hemisphere oriented along the +z-axis
81 ////////////////////////////////////////////////////////////////////////////////
82 
powerCosineSampleHemisphere(const float n,const Vec2f & s)83 inline Vec3fa powerCosineSampleHemisphere(const float n, const Vec2f &s)
84 {
85   const float phi =float(two_pi) * s.x;
86   const float cosTheta = pow(s.y, 1.0f / (n + 1.0f));
87   return cartesian(phi, cosTheta);
88 }
89 
powerCosineSampleHemispherePDF(const float cosTheta,const float n)90 inline float powerCosineSampleHemispherePDF(const float cosTheta, const float n) // TODO: order of arguments
91 {
92   return (n + 1.0f) * (0.5f / float(M_PI)) * pow(cosTheta, n);
93 }
94 
powerCosineSampleHemispherePDF(const Vec3fa & dir,const float n)95 inline float powerCosineSampleHemispherePDF(const Vec3fa& dir, const float n) // TODO: order of arguments
96 {
97   return (n + 1.0f) * (0.5f / float(M_PI)) * pow(dir.z, n);
98 }
99 
100 /// sampling of cone of directions oriented along the +z-axis
101 ////////////////////////////////////////////////////////////////////////////////
102 
uniformSampleCone(const float cosAngle,const Vec2f & s)103 inline Vec3fa uniformSampleCone(const float cosAngle, const Vec2f &s)
104 {
105   const float phi =float(two_pi) * s.x;
106   const float cosTheta = 1.0f - s.y * (1.0f - cosAngle);
107   return cartesian(phi, cosTheta);
108 }
109 
uniformSampleConePDF(const float cosAngle)110 inline float uniformSampleConePDF(const float cosAngle)
111 {
112     return rcp(float(two_pi)*(1.0f - cosAngle));
113 }
114 
_uniformSampleConePDF(const float cosAngle)115 inline float _uniformSampleConePDF(const float cosAngle)
116 {
117     return rcp(float(two_pi)*(1.0f - cosAngle));
118 }
119 
120 
121 /// sampling of disk
122 ////////////////////////////////////////////////////////////////////////////////
123 
uniformSampleDisk(const float radius,const Vec2f & s)124 inline Vec3fa uniformSampleDisk(const float radius, const Vec2f &s)
125 {
126   const float r = sqrtf(s.x) * radius;
127   const float phi =float(two_pi) * s.y;
128   const float sinPhi = sinf(phi);
129   const float cosPhi = cosf(phi);
130   //sincosf(phi, &sinPhi, &cosPhi);
131   return Vec3fa(r * cosPhi, r * sinPhi, 0.f);
132 }
133 
uniformSampleDiskPDF(const float radius)134 inline float uniformSampleDiskPDF(const float radius)
135 {
136   return rcp(float(M_PI) * sqr(radius));
137 }
138 
_uniformSampleDiskPDF(const float radius)139 inline float _uniformSampleDiskPDF(const float radius)
140 {
141   return rcp(float(M_PI) * sqr(radius));
142 }
143 
144 
145 /// sampling of triangle abc
146 ////////////////////////////////////////////////////////////////////////////////
147 
uniformSampleTriangle(const Vec3fa & a,const Vec3fa & b,const Vec3fa & c,const Vec2f & s)148 inline Vec3fa uniformSampleTriangle(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c, const Vec2f &s)
149 {
150   const float su = sqrtf(s.x);
151   return c + (1.0f - su) * (a-c) + (s.y*su) * (b-c);
152 }
153 
uniformSampleTrianglePDF(const Vec3fa & a,const Vec3fa & b,const Vec3fa & c)154 inline float uniformSampleTrianglePDF(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c)
155 {
156   return 2.0f * rcp(abs(length(cross(a-c, b-c))));
157 }
158 
159 } // namespace embree
160