Blender V5.0
init_from_bake.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
8
11
14
16
18
19/* In order to perform anti-aliasing during baking, we jitter the input barycentric coordinates
20 * (which are for the center of the texel) within the texel.
21 * However, the baking code currently doesn't support going to neighboring triangle, so if the
22 * jittered location falls outside of the input triangle, we need to bring it back in somehow.
23 * Clamping is a bad choice here since it can produce noticeable artifacts at triangle edges,
24 * but properly uniformly sampling the intersection of triangle and texel would be very
25 * performance-heavy, so cheat by just trying different jittering until we end up inside the
26 * triangle.
27 * For triangles that are smaller than a texel, this might take too many attempts, so eventually
28 * we just give up and don't jitter in that case.
29 * This is not a particularly elegant solution, but it's probably the best we can do. */
31 ccl_private float &v,
32 float2 rand_filter,
33 const float dudx,
34 const float dudy,
35 const float dvdx,
36 const float dvdy)
37{
38 for (int i = 0; i < 10; i++) {
39 /* Offset UV according to differentials. */
40 const float jitterU = u + (rand_filter.x - 0.5f) * dudx + (rand_filter.y - 0.5f) * dudy;
41 const float jitterV = v + (rand_filter.x - 0.5f) * dvdx + (rand_filter.y - 0.5f) * dvdy;
42 /* If this location is inside the triangle, return. */
43 if (jitterU > 0.0f && jitterV > 0.0f && jitterU + jitterV < 1.0f) {
44 u = jitterU;
45 v = jitterV;
46 return;
47 }
48 /* Retry with new jitter value. */
49 rand_filter = hash_float2_to_float2(rand_filter);
50 }
51 /* Retries exceeded, give up and just use center value. */
52}
53
54/* Offset towards center of triangle to avoid ray-tracing precision issues. */
56 const int prim,
57 const float u,
58 const float v)
59{
60 float3 tri_verts[3];
61 triangle_vertices(kg, prim, tri_verts);
62
63 /* Empirically determined values, by no means perfect. */
64 const float position_offset = 1e-4f;
65 const float uv_offset = 1e-5f;
66
67 /* Offset position towards center, amount relative to absolute size of position coordinates. */
68 const float3 P = u * tri_verts[0] + v * tri_verts[1] + (1.0f - u - v) * tri_verts[2];
69 const float3 center = (tri_verts[0] + tri_verts[1] + tri_verts[2]) / 3.0f;
70 const float3 to_center = center - P;
71
72 const float3 offset_P = P + normalize(to_center) *
73 min(len(to_center),
74 max(reduce_max(fabs(P)), 1.0f) * position_offset);
75
76 /* Compute barycentric coordinates at new position. */
77 const float3 v1 = tri_verts[1] - tri_verts[0];
78 const float3 v2 = tri_verts[2] - tri_verts[0];
79 const float3 vP = offset_P - tri_verts[0];
80
81 const float d11 = dot(v1, v1);
82 const float d12 = dot(v1, v2);
83 const float d22 = dot(v2, v2);
84 const float dP1 = dot(vP, v1);
85 const float dP2 = dot(vP, v2);
86
87 const float denom = d11 * d22 - d12 * d12;
88 if (denom == 0.0f) {
89 return make_float2(0.0f, 0.0f);
90 }
91
92 const float offset_v = clamp((d22 * dP1 - d12 * dP2) / denom, uv_offset, 1.0f - uv_offset);
93 const float offset_w = clamp((d11 * dP2 - d12 * dP1) / denom, uv_offset, 1.0f - uv_offset);
94 const float offset_u = clamp(1.0f - offset_v - offset_w, uv_offset, 1.0f - uv_offset);
95
96 return make_float2(offset_u, offset_v);
97}
98
99/* Return false to indicate that this pixel is finished.
100 * Used by CPU implementation to not attempt to sample pixel for multiple samples once its known
101 * that the pixel did converge. */
106 const int x,
107 const int y,
108 const int scheduled_sample)
109{
111
112 /* Initialize path state to give basic buffer access and allow early outputs. */
114
115 /* Check whether the pixel has converged and should not be sampled anymore. */
117 return false;
118 }
119
120 /* Always count the sample, even if the camera sample will reject the ray. */
121 const int sample = film_write_sample(
122 kg, state, render_buffer, scheduled_sample, tile->sample_offset);
123
124 /* Setup render buffers. */
126
127 ccl_global float *primitive = buffer + kernel_data.film.pass_bake_primitive;
128 ccl_global float *differential = buffer + kernel_data.film.pass_bake_differential;
129
130 int prim = __float_as_uint(primitive[2]);
131 if (prim == -1) {
132 /* Accumulate transparency for empty pixels. */
133 film_write_transparent(kg, 0, 1.0f, buffer);
134 return true;
135 }
136
137 prim += kernel_data.bake.tri_offset;
138
139 /* Random number generator. */
140 uint rng_pixel = 0;
141 if (kernel_data.film.pass_bake_seed != 0) {
142 const uint seed = __float_as_uint(buffer[kernel_data.film.pass_bake_seed]);
143 rng_pixel = hash_uint(seed) ^ kernel_data.integrator.seed;
144 }
145 else {
146 rng_pixel = path_rng_pixel_init(kg, sample, x, y);
147 }
148
149 const float2 rand_filter = (sample == 0) ? make_float2(0.5f, 0.5f) :
150 path_rng_2D(kg, rng_pixel, sample, PRNG_FILTER);
151
152 /* Initialize path state for path integration. */
154
155 /* Barycentric UV. */
156 float u = primitive[0];
157 float v = primitive[1];
158
159 float dudx = differential[0];
160 float dudy = differential[1];
161 float dvdx = differential[2];
162 float dvdy = differential[3];
163
164 /* Exactly at vertex? Nudge inwards to avoid self-intersection. */
165 if ((u == 0.0f || u == 1.0f) && (v == 0.0f || v == 1.0f)) {
166 const float2 uv = bake_offset_towards_center(kg, prim, u, v);
167 u = uv.x;
168 v = uv.y;
169 }
170
171 /* Sub-pixel offset. */
172 bake_jitter_barycentric(u, v, rand_filter, dudx, dudy, dvdx, dvdy);
173
174 /* Convert from Blender to Cycles/Embree/OptiX barycentric convention. */
175 const float tmp = u;
176 u = v;
177 v = 1.0f - tmp - v;
178
179 const float tmpdx = dudx;
180 const float tmpdy = dudy;
181 dudx = dvdx;
182 dudy = dvdy;
183 dvdx = -tmpdx - dvdx;
184 dvdy = -tmpdy - dvdy;
185
186 /* Position and normal on triangle. */
187 const int object = kernel_data.bake.object_index;
188 float3 P;
189 float3 Ng;
190 int shader;
191 triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
192
193 const int object_flag = kernel_data_fetch(object_flag, object);
194 if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
195 const Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
196 P = transform_point_auto(&tfm, P);
197 }
198
199 if (kernel_data.film.pass_background != PASS_UNUSED) {
200 /* Environment baking. */
201
202 /* Setup and write ray. */
204 ray.P = zero_float3();
205 ray.D = normalize(P);
206 ray.tmin = 0.0f;
207 ray.tmax = FLT_MAX;
208 ray.time = 0.5f;
209 ray.dP = differential_zero_compact();
210 ray.dD = differential_zero_compact();
212
213 /* Setup next kernel to execute. */
215 }
216 else {
217 /* Surface baking. */
218 float3 N = (shader & SHADER_SMOOTH_NORMAL) ? triangle_smooth_normal(kg, Ng, prim, u, v) : Ng;
219
220 if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
224 }
225
226 const int shader_index = shader & SHADER_MASK;
227 const int shader_flags = kernel_data_fetch(shaders, shader_index).flags;
228
229 /* Fast path for position and normal passes not affected by shaders. */
230 if (kernel_data.film.pass_position != PASS_UNUSED) {
231 film_write_pass_float3(buffer + kernel_data.film.pass_position, P);
232 return true;
233 }
234 if (kernel_data.film.pass_normal != PASS_UNUSED && !(shader_flags & SD_HAS_BUMP)) {
235 film_write_pass_float3(buffer + kernel_data.film.pass_normal, N);
236 return true;
237 }
238
239 /* Setup ray. */
241
242 if (kernel_data.bake.use_camera) {
244
245 const float DN = dot(D, N);
246
247 /* Nudge camera direction, so that the faces facing away from the camera still have
248 * somewhat usable shading. (Otherwise, glossy faces would be simply black.)
249 *
250 * The surface normal offset affects smooth surfaces. Lower values will make
251 * smooth surfaces more faceted, but higher values may show up from the camera
252 * at grazing angles.
253 *
254 * This value can actually be pretty high before it's noticeably wrong. */
255 const float surface_normal_offset = 0.2f;
256
257 /* Keep the ray direction at least `surface_normal_offset` "above" the smooth normal. */
258 if (DN <= surface_normal_offset) {
259 D -= N * (DN - surface_normal_offset);
260 D = normalize(D);
261 }
262
263 /* On the backside, just lerp towards the surface normal for the ray direction,
264 * as DN goes from 0.0 to -1.0. */
265 if (DN <= 0.0f) {
266 D = normalize(mix(D, N, -DN));
267 }
268
269 /* We don't want to bake the back face, so make sure the ray direction never
270 * goes behind the geometry (flat) normal. This is a fail-safe, and should rarely happen. */
271 const float true_normal_epsilon = 0.00001f;
272
273 if (dot(D, Ng) <= true_normal_epsilon) {
274 D -= Ng * (dot(D, Ng) - true_normal_epsilon);
275 D = normalize(D);
276 }
277
278 ray.P = P + D;
279 ray.D = -D;
280 }
281 else {
282 ray.P = P + N;
283 ray.D = -N;
284 }
285
286 ray.tmin = 0.0f;
287 ray.tmax = FLT_MAX;
288 ray.time = 0.5f;
289
290 /* Setup differentials. */
291 float3 dPdu;
292 float3 dPdv;
293 triangle_dPdudv(kg, prim, &dPdu, &dPdv);
294 if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
295 const Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
296 dPdu = transform_direction(&tfm, dPdu);
297 dPdv = transform_direction(&tfm, dPdv);
298 }
299
300 differential3 dP;
301 dP.dx = dPdu * dudx + dPdv * dvdx;
302 dP.dy = dPdu * dudy + dPdv * dvdy;
303 ray.dP = differential_make_compact(dP);
304 ray.dD = differential_zero_compact();
305
306 /* Write ray. */
308
309 /* Setup and write intersection. */
311 isect.object = kernel_data.bake.object_index;
312 isect.prim = prim;
313 isect.u = u;
314 isect.v = v;
315 isect.t = 1.0f;
316 isect.type = PRIMITIVE_TRIANGLE;
318
319 /* Setup next kernel to execute. */
320 const bool use_caustics = kernel_data.integrator.use_caustics &&
321 (object_flag & SD_OBJECT_CAUSTICS);
322 const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE);
323
324 if (use_caustics) {
327 }
328 else if (use_raytrace_kernel) {
331 }
332 else {
334 }
335
336#ifdef __SHADOW_CATCHER__
337 integrator_split_shadow_catcher(kg, state, &isect, render_buffer);
338#endif
339 }
340
341 return true;
342}
343
#define D
unsigned int uint
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition btSoftBody.h:39
reduce_max(value.rgb)") DEFINE_VALUE("REDUCE(lhs
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define kernel_data
#define PASS_UNUSED
#define ccl_restrict
#define ccl_optional_struct_init
#define transform_point_auto
#define kernel_data_fetch(name, index)
#define one_spectrum
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
#define __float_as_uint(x)
ccl_device_forceinline float differential_make_compact(const float dD)
ccl_device_forceinline float differential_zero_compact()
ccl_device_inline void triangle_dPdudv(KernelGlobals kg, const int prim, ccl_private float3 *dPdu, ccl_private float3 *dPdv)
ccl_device_inline void triangle_vertices(KernelGlobals kg, const int prim, float3 P[3])
ccl_device_inline float3 triangle_smooth_normal(KernelGlobals kg, const float3 Ng, const int prim, const float u, float v)
ccl_device_inline void triangle_point_normal(KernelGlobals kg, const int object, const int prim, const float u, const float v, ccl_private float3 *P, ccl_private float3 *Ng, ccl_private int *shader)
VecBase< float, D > normalize(VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
ccl_device_inline float2 hash_float2_to_float2(const float2 k)
Definition hash.h:278
ccl_device_inline uint hash_uint(const uint kx)
Definition hash.h:126
ccl_device float2 bake_offset_towards_center(KernelGlobals kg, const int prim, const float u, const float v)
ccl_device bool integrator_init_from_bake(KernelGlobals kg, IntegratorState state, const ccl_global KernelWorkTile *ccl_restrict tile, ccl_global float *render_buffer, const int x, const int y, const int scheduled_sample)
CCL_NAMESPACE_BEGIN ccl_device_inline void bake_jitter_barycentric(ccl_private float &u, ccl_private float &v, float2 rand_filter, const float dudx, const float dudy, const float dvdx, const float dvdy)
ccl_device_inline float3 camera_direction_from_point(KernelGlobals kg, const float3 P)
const ccl_global KernelWorkTile * tile
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
CCL_NAMESPACE_BEGIN ccl_device_forceinline bool film_need_sample_pixel(KernelGlobals kg, ConstIntegratorState state, ccl_global float *render_buffer)
@ OBJECT_INVERSE_TRANSFORM
@ OBJECT_TRANSFORM
ccl_device_inline Transform object_fetch_transform(KernelGlobals kg, const int object, enum ObjectTransform type)
@ SD_HAS_BUMP
@ SD_HAS_RAYTRACE
@ PRIMITIVE_TRIANGLE
@ PRNG_FILTER
@ SHADER_SMOOTH_NORMAL
@ SHADER_MASK
@ SD_OBJECT_CAUSTICS
@ SD_OBJECT_TRANSFORM_APPLIED
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND
ccl_device_inline int film_write_sample(KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer, const int sample, const int sample_offset)
ccl_device_inline void film_write_transparent(KernelGlobals kg, const uint32_t path_flag, const float transparent, ccl_global float *ccl_restrict buffer)
ccl_device_inline float2 fabs(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
static ulong state[N]
#define N
#define PROFILING_INIT(kg, event)
ccl_device_inline void path_state_init_integrator(KernelGlobals kg, IntegratorState state, const int sample, const uint rng_pixel, const Spectrum throughput)
Definition path_state.h:40
ccl_device_inline void path_state_init(IntegratorState state, const ccl_global KernelWorkTile *ccl_restrict tile, const int x, const int y)
Definition path_state.h:27
ccl_device_forceinline float2 path_rng_2D(KernelGlobals kg, const uint rng_pixel, const int sample, const int dimension)
Definition pattern.h:83
ccl_device_inline uint path_rng_pixel_init(KernelGlobals kg, const int, const int x, const int y)
Definition pattern.h:134
@ PROFILING_RAY_SETUP
Definition profiling.h:17
#define mix
#define ccl_device
#define make_float2
#define min(a, b)
Definition sort.cc:36
IntegratorStateCPU * IntegratorState
Definition state.h:228
ccl_device_forceinline void integrator_path_init_sorted(KernelGlobals, IntegratorState state, const DeviceKernel next_kernel, const uint32_t key)
Definition state_flow.h:186
ccl_device_forceinline void integrator_path_init(IntegratorState state, const DeviceKernel next_kernel)
Definition state_flow.h:180
CCL_NAMESPACE_BEGIN ccl_device_forceinline void integrator_state_write_ray(IntegratorState state, const ccl_private Ray *ccl_restrict ray)
Definition state_util.h:17
ccl_device_forceinline void integrator_state_write_isect(IntegratorState state, const ccl_private Intersection *ccl_restrict isect)
Definition state_util.h:149
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
ccl_device_inline float3 transform_direction_transposed(const ccl_private Transform *t, const float3 a)
Definition transform.h:149
uint len
ccl_device_inline void film_write_pass_float3(ccl_global float *ccl_restrict buffer, const float3 value)
Definition write.h:68
CCL_NAMESPACE_BEGIN ccl_device_forceinline ccl_global float * film_pass_pixel_render_buffer(KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer)
Definition write.h:24