Blender V4.3
sample/mapping.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Adapted code from Open Shading Language. */
7
8#pragma once
9
11
12/* Distribute 2D uniform random samples on [0, 1] over unit disk [-1, 1], with concentric mapping
13 * to better preserve stratification for some RNG sequences. */
15{
16 float phi, r;
17 float a = 2.0f * rand.x - 1.0f;
18 float b = 2.0f * rand.y - 1.0f;
19
20 if (a == 0.0f && b == 0.0f) {
21 return zero_float2();
22 }
23 else if (a * a > b * b) {
24 r = a;
25 phi = M_PI_4_F * (b / a);
26 }
27 else {
28 r = b;
29 phi = M_PI_2_F - M_PI_4_F * (a / b);
30 }
31
32 return make_float2(r * cosf(phi), r * sinf(phi));
33}
34
35/* return an orthogonal tangent and bitangent given a normal and tangent that
36 * may not be exactly orthogonal */
38 const float3 T,
41{
42 *b = normalize(cross(N, T));
43 *a = cross(*b, N);
44}
45
47 const float3 T,
50{
51 *b = safe_normalize(cross(N, T));
52 if (len_squared(*b) < 0.99f) {
53 /* Normalization failed, so fall back to basic orthonormals. */
55 }
56 else {
57 *a = cross(*b, N);
58 }
59}
60
61/* sample direction with cosine weighted distributed in hemisphere */
63 float2 rand_in,
65 ccl_private float *pdf)
66{
67 float2 rand = sample_uniform_disk(rand_in);
68 float costheta = safe_sqrtf(1.0f - len_squared(rand));
69
70 float3 T, B;
71 make_orthonormals(N, &T, &B);
72 *wo = rand.x * T + rand.y * B + costheta * N;
73 *pdf = costheta * M_1_PI_F;
74}
75
77{
78 const float cos_theta = dot(N, D);
79 return cos_theta > 0 ? cos_theta * M_1_PI_F : 0.0f;
80}
81
82/* sample direction uniformly distributed in hemisphere */
84 const float2 rand,
86 ccl_private float *pdf)
87{
89 float z = 1.0f - len_squared(xy);
90
91 xy *= safe_sqrtf(z + 1.0f);
92
93 float3 T, B;
94 make_orthonormals(N, &T, &B);
95
96 *wo = xy.x * T + xy.y * B + z * N;
97 *pdf = M_1_2PI_F;
98}
99
101{
102 float z = precise_angle(N, D);
103 if (z < angle) {
104 return M_1_2PI_F / one_minus_cos(angle);
105 }
106 return 0.0f;
107}
108
109/* Uniformly sample a direction in a cone of given angle around `N`. Use concentric mapping to
110 * better preserve stratification. Return the angle between `N` and the sampled direction as
111 * `cos_theta`.
112 * Pass `1 - cos(angle)` as argument instead of `angle` to alleviate precision issues at small
113 * angles (see sphere light for reference). */
115 const float one_minus_cos_angle,
116 const float2 rand,
117 ccl_private float *cos_theta,
118 ccl_private float *pdf)
119{
120 if (one_minus_cos_angle > 0) {
121 /* Remap radius to get a uniform distribution w.r.t. solid angle on the cone.
122 * The logic to derive this mapping is as follows:
123 *
124 * Sampling a cone is comparable to sampling the hemisphere, we just restrict theta. Therefore,
125 * the same trick of first sampling the unit disk and the projecting the result up towards the
126 * hemisphere by calculating the appropriate z coordinate still works.
127 *
128 * However, by itself this results in cosine-weighted hemisphere sampling, so we need some kind
129 * of remapping. Cosine-weighted hemisphere and uniform cone sampling have the same conditional
130 * PDF for phi (both are constant), so we only need to think about theta, which corresponds
131 * directly to the radius.
132 *
133 * To find this mapping, we consider the simplest sampling strategies for cosine-weighted
134 * hemispheres and uniform cones. In both, phi is chosen as `2pi * random()`. For the former,
135 * `r_disk(rand) = sqrt(rand)`. This is just naive disk sampling, since the projection to the
136 * hemisphere doesn't change the radius.
137 * For the latter, `r_cone(rand) = sin_from_cos(mix(cos_angle, 1, rand))`.
138 *
139 * So, to remap, we just invert r_disk `(-> rand(r_disk) = r_disk^2)` and insert it into
140 * r_cone: `r_cone(r_disk) = r_cone(rand(r_disk)) = sin_from_cos(mix(cos_angle, 1, r_disk^2))`.
141 * In practice, we need to replace `rand` with `1 - rand` to preserve the stratification,
142 * but since it's uniform, that's fine. */
144 const float r2 = len_squared(xy);
145
146 /* Equivalent to `mix(cos_angle, 1.0f, 1.0f - r2)`. */
147 *cos_theta = 1.0f - r2 * one_minus_cos_angle;
148
149 /* Remap disk radius to cone radius, equivalent to `xy *= sin_theta / sqrt(r2)`. */
150 xy *= safe_sqrtf(one_minus_cos_angle * (2.0f - one_minus_cos_angle * r2));
151
152 *pdf = M_1_2PI_F / one_minus_cos_angle;
153
154 float3 T, B;
155 make_orthonormals(N, &T, &B);
156 return xy.x * T + xy.y * B + *cos_theta * N;
157 }
158
159 *cos_theta = 1.0f;
160 *pdf = 1.0f;
161
162 return N;
163}
164
165/* sample uniform point on the surface of a sphere */
167{
168 float z = 1.0f - 2.0f * rand.x;
169 float r = sin_from_cos(z);
170 float phi = M_2PI_F * rand.y;
171 float x = r * cosf(phi);
172 float y = r * sinf(phi);
173
174 return make_float3(x, y, z);
175}
176
177/* sample point in unit polygon with given number of corners and rotation */
178ccl_device float2 regular_polygon_sample(float corners, float rotation, const float2 rand)
179{
180 float u = rand.x, v = rand.y;
181
182 /* sample corner number and reuse u */
183 float corner = floorf(u * corners);
184 u = u * corners - corner;
185
186 /* uniform sampled triangle weights */
187 u = sqrtf(u);
188 v = v * u;
189 u = 1.0f - u;
190
191 /* point in triangle */
192 float angle = M_PI_F / corners;
193 float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle));
194
195 /* rotate */
196 rotation += corner * 2.0f * angle;
197
198 float cr = cosf(rotation);
199 float sr = sinf(rotation);
200
201 return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y);
202}
203
MINLINE float safe_sqrtf(float a)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float cos_theta(const float3 w)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define sinf(x)
#define cosf(x)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define floorf(x)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define sqrtf(x)
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:14
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
ccl_device_inline float cross(const float2 a, const float2 b)
#define N
#define T
#define B
#define M_PI_F
Definition mikk_util.hh:15
ccl_device_inline void sample_uniform_hemisphere(const float3 N, const float2 rand, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device float2 regular_polygon_sample(float corners, float rotation, const float2 rand)
CCL_NAMESPACE_BEGIN ccl_device float2 sample_uniform_disk(const float2 rand)
ccl_device_inline void sample_cos_hemisphere(const float3 N, float2 rand_in, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device float3 sample_uniform_sphere(const float2 rand)
ccl_device void make_orthonormals_tangent(const float3 N, const float3 T, ccl_private float3 *a, ccl_private float3 *b)
ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
ccl_device_inline float3 sample_uniform_cone(const float3 N, const float one_minus_cos_angle, const float2 rand, ccl_private float *cos_theta, ccl_private float *pdf)
ccl_device_inline float pdf_cos_hemisphere(const float3 N, const float3 D)
ccl_device void make_orthonormals_safe_tangent(const float3 N, const float3 T, ccl_private float3 *a, ccl_private float3 *b)
#define M_PI_2_F
Definition sky_float3.h:20
#define M_2PI_F
Definition sky_float3.h:23
float x
float y
ccl_device_inline float sin_from_cos(const float c)
Definition util/math.h:787
ccl_device_inline float precise_angle(float3 a, float3 b)
Definition util/math.h:988
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
Definition util/math.h:593
ccl_device_inline float one_minus_cos(const float angle)
Definition util/math.h:803
int xy[2]
Definition wm_draw.cc:170