Blender V4.3
light/triangle.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/geom/geom.h"
8
10
11/* returns true if the triangle is has motion blur or an instancing transform applied */
13 KernelGlobals kg, int object, int prim, float time, float3 V[3])
14{
15 bool has_motion = false;
16 const int object_flag = kernel_data_fetch(object_flag, object);
17
18 if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
19 motion_triangle_vertices(kg, object, prim, time, V);
20 has_motion = true;
21 }
22 else {
23 triangle_vertices(kg, prim, V);
24 }
25
26 if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
27#ifdef __OBJECT_MOTION__
28 float object_time = (time >= 0.0f) ? time : 0.5f;
29 Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL);
30#else
32#endif
33 V[0] = transform_point(&tfm, V[0]);
34 V[1] = transform_point(&tfm, V[1]);
35 V[2] = transform_point(&tfm, V[2]);
36 has_motion = true;
37 }
38 return has_motion;
39}
40
42{
43 float cos_pi = fabsf(dot(Ng, I));
44
45 if (cos_pi == 0.0f) {
46 return 0.0f;
47 }
48
49 return t * t / cos_pi;
50}
51
53 ccl_private const ShaderData *sd,
54 float t)
55{
56 /* A naive heuristic to decide between costly solid angle sampling
57 * and simple area sampling, comparing the distance to the triangle plane
58 * to the length of the edges of the triangle. */
59
60 float3 V[3];
61 bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V);
62
63 const float3 e0 = V[1] - V[0];
64 const float3 e1 = V[2] - V[0];
65 const float3 e2 = V[2] - V[1];
66 const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
67 const float3 N = cross(e0, e1);
68 const float distance_to_plane = fabsf(dot(N, sd->wi * t)) / dot(N, N);
69 const float area = 0.5f * len(N);
70
71 float pdf;
72
73 if (longest_edge_squared > distance_to_plane * distance_to_plane) {
74 /* sd contains the point on the light source
75 * calculate Px, the point that we're shading */
76 const float3 Px = sd->P + sd->wi * t;
77
78 const float3 A = safe_normalize(V[0] - Px);
79 const float3 B = safe_normalize(V[1] - Px);
80 const float3 C = safe_normalize(V[2] - Px);
81
82 const float solid_angle = 2.0f * fast_atan2f(fabsf(dot(A, cross(B, C))),
83 (1.0f + dot(B, C) + dot(A, C) + dot(A, B)));
84
85 /* distribution_pdf_triangles is calculated over triangle area, but we're not sampling over
86 * its area */
87 if (UNLIKELY(solid_angle == 0.0f)) {
88 return 0.0f;
89 }
90 else {
91 pdf = 1.0f / solid_angle;
92 }
93 }
94 else {
95 if (UNLIKELY(area == 0.0f)) {
96 return 0.0f;
97 }
98
99 pdf = triangle_light_pdf_area_sampling(sd->Ng, sd->wi, t) / area;
100 }
101
102 /* Belongs in distribution.h but can reuse computations here. */
103 if (!kernel_data.integrator.use_light_tree) {
104 float distribution_area = area;
105
106 if (has_motion && area != 0.0f) {
107 /* For motion blur need area of triangle at fixed time as used in the CDF. */
108 triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
109 distribution_area = triangle_area(V[0], V[1], V[2]);
110 }
111
112 pdf *= distribution_area * kernel_data.integrator.distribution_pdf_triangles;
113 }
114
115 return pdf;
116}
117
118template<bool in_volume_segment>
120 int prim,
121 int object,
122 const float2 rand,
123 float time,
125 const float3 P)
126{
127 /* A naive heuristic to decide between costly solid angle sampling
128 * and simple area sampling, comparing the distance to the triangle plane
129 * to the length of the edges of the triangle. */
130
131 float3 V[3];
132 bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V);
133
134 const float3 e0 = V[1] - V[0];
135 const float3 e1 = V[2] - V[0];
136 const float3 e2 = V[2] - V[1];
137 const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
138 float3 N0 = cross(e0, e1);
139 /* Flip normal if necessary. */
140 const int object_flag = kernel_data_fetch(object_flag, object);
141 if (object_flag & SD_OBJECT_NEGATIVE_SCALE) {
142 N0 = -N0;
143 }
144
145 /* Do not draw samples from the side without MIS. */
146 ls->shader = kernel_data_fetch(tri_shader, prim);
147 const float distance_to_plane = dot(N0, V[0] - P) / dot(N0, N0);
148 const int ls_shader_flag = kernel_data_fetch(shaders, ls->shader & SHADER_MASK).flags;
149 if (!in_volume_segment &&
150 !(ls_shader_flag & (distance_to_plane > 0 ? SD_MIS_BACK : SD_MIS_FRONT)))
151 {
152 return false;
153 }
154
155 float Nl = 0.0f;
156 ls->Ng = safe_normalize_len(N0, &Nl);
157 const float area = 0.5f * Nl;
158
159 ls->eval_fac = 1.0f;
160 ls->object = object;
161 ls->prim = prim;
162 ls->lamp = LAMP_NONE;
163 ls->shader |= SHADER_USE_MIS;
164 ls->type = LIGHT_TRIANGLE;
165 ls->group = object_lightgroup(kg, object);
166
167 if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) {
168 /* A modified version of James Arvo, "Stratified Sampling of Spherical Triangles"
169 * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */
170
171 /* Project the triangle to the unit sphere and calculate the three unit vector that spans the
172 * spherical triangle. */
173 const float3 A = safe_normalize(V[0] - P);
174 const float3 B = safe_normalize(V[1] - P);
175 const float3 C = safe_normalize(V[2] - P);
176
177 const float cos_a = dot(B, C);
178 const float cos_b = dot(A, C);
179 const float cos_c = dot(A, B);
180
181 const float mixed_product = fabsf(dot(A, cross(B, C)));
182
183 /* The area of the spherical triangle is equal to the subtended solid angle. */
184 const float solid_angle = 2.0f * fast_atan2f(mixed_product, (1.0f + cos_a + cos_b + cos_c));
185
186 /* Compute the angle at A. */
187 const float cos_alpha = dot(safe_normalize(cross(A, B)), safe_normalize(cross(A, C)));
188 const float sin_alpha = sin_from_cos(cos_alpha);
189 const float alpha = safe_acosf(cos_alpha);
190
191 /* Select a random sub-area of the spherical triangle and calculate the third vertex C_ of that
192 * new triangle. */
193 const float A_hat = rand.x * solid_angle;
194 float sin_phi, cos_phi;
195 fast_sincosf(A_hat - alpha, &sin_phi, &cos_phi);
196 const float u = cos_phi - cos_alpha;
197 const float v = sin_phi + sin_alpha * cos_c;
198 const float num = (v * cos_phi - u * sin_phi) * cos_alpha - v;
199 const float den = (v * sin_phi + u * cos_phi) * sin_alpha;
200 const float q = (den == 0.0f) ? 1.0f : num / den;
201
202 const float3 U = safe_normalize(C - cos_b * A);
203 const float3 C_ = safe_normalize(q * A + sin_from_cos(q) * U);
204
205 /* Finally, select a random point along the edge of the new triangle
206 * That point on the spherical triangle is the sampled ray direction */
207 const float z = 1.0f - rand.y * (1.0f - dot(C_, B));
208 ls->D = z * B + sin_from_cos(z) * safe_normalize(C_ - dot(C_, B) * B);
209
210 /* calculate intersection with the planar triangle */
211 if (!ray_triangle_intersect(P, ls->D, 0.0f, FLT_MAX, V[0], V[1], V[2], &ls->u, &ls->v, &ls->t))
212 {
213 ls->pdf = 0.0f;
214 return false;
215 }
216
217 ls->P = P + ls->D * ls->t;
218
219 /* distribution_pdf_triangles is calculated over triangle area, but we're sampling over solid
220 * angle */
221 if (UNLIKELY(solid_angle == 0.0f)) {
222 ls->pdf = 0.0f;
223 return false;
224 }
225 else {
226 ls->pdf = 1.0f / solid_angle;
227 }
228 }
229 else {
230 if (UNLIKELY(area == 0.0f)) {
231 return 0.0f;
232 }
233
234 /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle
235 * and Square" */
236 float u = rand.x;
237 float v = rand.y;
238 if (v > u) {
239 u *= 0.5f;
240 v -= u;
241 }
242 else {
243 v *= 0.5f;
244 u -= v;
245 }
246
247 const float t = 1.0f - u - v;
248 ls->P = t * V[0] + u * V[1] + v * V[2];
249 /* compute incoming direction, distance and pdf */
250 ls->D = normalize_len(ls->P - P, &ls->t);
251 ls->pdf = triangle_light_pdf_area_sampling(ls->Ng, -ls->D, ls->t) / area;
252 ls->u = u;
253 ls->v = v;
254 }
255
256 /* Belongs in distribution.h but can reuse computations here. */
257 if (!kernel_data.integrator.use_light_tree) {
258 float distribution_area = area;
259
260 if (has_motion && area != 0.0f) {
261 /* For motion blur need area of triangle at fixed time as used in the CDF. */
262 triangle_world_space_vertices(kg, object, prim, -1.0f, V);
263 distribution_area = triangle_area(V[0], V[1], V[2]);
264 }
265
266 ls->pdf_selection = distribution_area * kernel_data.integrator.distribution_pdf_triangles;
267 }
268
269 return (ls->pdf > 0.0f);
270}
271
272/* Find the ray segment lit by the triangle light. */
274 const float3 P,
275 const float3 D,
276 ccl_private float2 *t_range,
277 const ccl_private LightSample *ls)
278{
279 const int shader_flag = kernel_data_fetch(shaders, ls->shader & SHADER_MASK).flags;
280 const int SD_MIS_BOTH = SD_MIS_BACK | SD_MIS_FRONT;
281 if ((shader_flag & SD_MIS_BOTH) == SD_MIS_BOTH) {
282 /* Both sides are sampled, the complete ray segment is visible. */
283 return true;
284 }
285
286 /* Only one side is sampled, intersect the ray and the triangle light plane to find the visible
287 * ray segment. Flip normal if Emission Sampling is set to back. */
288 const float3 N = ls->Ng;
289 return ray_plane_intersect((shader_flag & SD_MIS_BACK) ? -N : N, P, D, t_range);
290}
291
292template<bool in_volume_segment>
294 KernelGlobals kg,
295 const ccl_global KernelLightTreeEmitter *kemitter,
296 const float3 centroid,
297 const float3 P,
298 const float3 N,
299 const BoundingCone bcone,
300 ccl_private float &cos_theta_u,
301 ccl_private float2 &distance,
302 ccl_private float3 &point_to_centroid)
303{
304 /* TODO: a cheap substitute for minimal distance between point and primitive. Does it worth the
305 * overhead to compute the accurate minimal distance? */
306 float min_distance;
307 point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
308 distance = make_float2(min_distance, min_distance);
309
310 cos_theta_u = FLT_MAX;
311
312 float3 vertices[3];
313 triangle_vertices(kg, kemitter->triangle.id, vertices);
314
315 bool shape_above_surface = false;
316 for (int i = 0; i < 3; i++) {
317 const float3 corner = vertices[i];
318 float distance_point_to_corner;
319 const float3 point_to_corner = safe_normalize_len(corner - P, &distance_point_to_corner);
320 cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
321 shape_above_surface |= dot(point_to_corner, N) > 0;
322 if (!in_volume_segment) {
323 distance.x = fmaxf(distance.x, distance_point_to_corner);
324 }
325 }
326
327 const bool front_facing = bcone.theta_o != 0.0f || dot(bcone.axis, point_to_centroid) < 0;
328
329 return front_facing && shape_above_surface;
330}
331
#define D
MINLINE float safe_acosf(float a)
#define UNLIKELY(x)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device float sin_phi(const float3 w)
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_forceinline
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
#define NULL
#define fmaxf(x, y)
#define fminf(x, y)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
int len
ccl_device_inline void triangle_vertices(KernelGlobals kg, int prim, float3 P[3])
@ OBJECT_TRANSFORM
ccl_device_inline Transform object_fetch_transform(KernelGlobals kg, int object, enum ObjectTransform type)
ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals kg, int object, float time, ccl_private Transform *itfm)
struct BoundingCone { packed_float3 axis; float theta_o; float theta_e;} BoundingCone
@ SD_MIS_BACK
@ SD_MIS_FRONT
ShaderData
@ SHADER_USE_MIS
@ SHADER_MASK
@ SD_OBJECT_NEGATIVE_SCALE
@ SD_OBJECT_TRANSFORM_APPLIED
@ SD_OBJECT_HAS_VERTEX_MOTION
@ LIGHT_TRIANGLE
#define LAMP_NONE
ccl_device_forceinline bool triangle_light_tree_parameters(KernelGlobals kg, const ccl_global KernelLightTreeEmitter *kemitter, const float3 centroid, const float3 P, const float3 N, const BoundingCone bcone, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid)
ccl_device_inline float triangle_light_pdf_area_sampling(const float3 Ng, const float3 I, float t)
ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg, int prim, int object, const float2 rand, float time, ccl_private LightSample *ls, const float3 P)
CCL_NAMESPACE_BEGIN ccl_device_inline bool triangle_world_space_vertices(KernelGlobals kg, int object, int prim, float time, float3 V[3])
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg, const float3 P, const float3 D, ccl_private float2 *t_range, const ccl_private LightSample *ls)
ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg, ccl_private const ShaderData *sd, float t)
ccl_device void fast_sincosf(float x, ccl_private float *sine, ccl_private float *cosine)
Definition math_fast.h:141
ccl_device float fast_atan2f(float y, float x)
Definition math_fast.h:310
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
ccl_device_inline float2 normalize_len(const float2 a, ccl_private float *t)
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
ccl_device_forceinline bool ray_triangle_intersect(const float3 ray_P, const float3 ray_D, const float ray_tmin, const float ray_tmax, const float3 tri_a, const float3 tri_b, const float3 tri_c, ccl_private float *isect_u, ccl_private float *isect_v, ccl_private float *isect_t)
ccl_device bool ray_plane_intersect(const float3 N, const float3 P, const float3 ray_D, ccl_private float2 *t_range)
#define N
#define B
ccl_device_inline void motion_triangle_vertices(KernelGlobals kg, int object, uint3 tri_vindex, int numsteps, int numverts, int step, float t, float3 verts[3])
#define I
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
float max
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float triangle_area(ccl_private const float3 &v1, ccl_private const float3 &v2, ccl_private const float3 &v3)
Definition util/math.h:584
ccl_device_inline float sin_from_cos(const float c)
Definition util/math.h:787
CCL_NAMESPACE_BEGIN struct Window V