ClangFormat: apply to source, most of intern
[blender.git] / intern / cycles / kernel / svm / svm_bevel.h
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 CCL_NAMESPACE_BEGIN
18
19 /* Bevel shader averaging normals from nearby surfaces.
20  *
21  * Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013
22  * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
23  */
24
25 ccl_device_noinline float3 svm_bevel(KernelGlobals *kg,
26                                      ShaderData *sd,
27                                      ccl_addr_space PathState *state,
28                                      float radius,
29                                      int num_samples)
30 {
31   /* Early out if no sampling needed. */
32   if (radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
33     return sd->N;
34   }
35
36   /* Can't raytrace from shaders like displacement, before BVH exists. */
37   if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
38     return sd->N;
39   }
40
41   /* Don't bevel for blurry indirect rays. */
42   if (state->min_ray_pdf < 8.0f) {
43     return sd->N;
44   }
45
46   /* Setup for multi intersection. */
47   LocalIntersection isect;
48   uint lcg_state = lcg_state_init_addrspace(state, 0x64c6a40e);
49
50   /* Sample normals from surrounding points on surface. */
51   float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
52
53   for (int sample = 0; sample < num_samples; sample++) {
54     float disk_u, disk_v;
55     path_branched_rng_2D(
56         kg, state->rng_hash, state, sample, num_samples, PRNG_BEVEL_U, &disk_u, &disk_v);
57
58     /* Pick random axis in local frame and point on disk. */
59     float3 disk_N, disk_T, disk_B;
60     float pick_pdf_N, pick_pdf_T, pick_pdf_B;
61
62     disk_N = sd->Ng;
63     make_orthonormals(disk_N, &disk_T, &disk_B);
64
65     float axisu = disk_u;
66
67     if (axisu < 0.5f) {
68       pick_pdf_N = 0.5f;
69       pick_pdf_T = 0.25f;
70       pick_pdf_B = 0.25f;
71       disk_u *= 2.0f;
72     }
73     else if (axisu < 0.75f) {
74       float3 tmp = disk_N;
75       disk_N = disk_T;
76       disk_T = tmp;
77       pick_pdf_N = 0.25f;
78       pick_pdf_T = 0.5f;
79       pick_pdf_B = 0.25f;
80       disk_u = (disk_u - 0.5f) * 4.0f;
81     }
82     else {
83       float3 tmp = disk_N;
84       disk_N = disk_B;
85       disk_B = tmp;
86       pick_pdf_N = 0.25f;
87       pick_pdf_T = 0.25f;
88       pick_pdf_B = 0.5f;
89       disk_u = (disk_u - 0.75f) * 4.0f;
90     }
91
92     /* Sample point on disk. */
93     float phi = M_2PI_F * disk_u;
94     float disk_r = disk_v;
95     float disk_height;
96
97     /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */
98     bssrdf_cubic_sample(radius, 0.0f, disk_r, &disk_r, &disk_height);
99
100     float3 disk_P = (disk_r * cosf(phi)) * disk_T + (disk_r * sinf(phi)) * disk_B;
101
102     /* Create ray. */
103     Ray *ray = &isect.ray;
104     ray->P = sd->P + disk_N * disk_height + disk_P;
105     ray->D = -disk_N;
106     ray->t = 2.0f * disk_height;
107     ray->dP = sd->dP;
108     ray->dD = differential3_zero();
109     ray->time = sd->time;
110
111     /* Intersect with the same object. if multiple intersections are found it
112      * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
113     scene_intersect_local(kg, *ray, &isect, sd->object, &lcg_state, LOCAL_MAX_HITS);
114
115     int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS);
116
117     for (int hit = 0; hit < num_eval_hits; hit++) {
118       /* Quickly retrieve P and Ng without setting up ShaderData. */
119       float3 hit_P;
120       if (sd->type & PRIMITIVE_TRIANGLE) {
121         hit_P = triangle_refine_local(kg, sd, &isect.hits[hit], ray);
122       }
123 #ifdef __OBJECT_MOTION__
124       else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
125         float3 verts[3];
126         motion_triangle_vertices(
127             kg, sd->object, kernel_tex_fetch(__prim_index, isect.hits[hit].prim), sd->time, verts);
128         hit_P = motion_triangle_refine_local(kg, sd, &isect.hits[hit], ray, verts);
129       }
130 #endif /* __OBJECT_MOTION__ */
131
132       /* Get geometric normal. */
133       float3 hit_Ng = isect.Ng[hit];
134       int object = (isect.hits[hit].object == OBJECT_NONE) ?
135                        kernel_tex_fetch(__prim_object, isect.hits[hit].prim) :
136                        isect.hits[hit].object;
137       int object_flag = kernel_tex_fetch(__object_flag, object);
138       if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
139         hit_Ng = -hit_Ng;
140       }
141
142       /* Compute smooth normal. */
143       float3 N = hit_Ng;
144       int prim = kernel_tex_fetch(__prim_index, isect.hits[hit].prim);
145       int shader = kernel_tex_fetch(__tri_shader, prim);
146
147       if (shader & SHADER_SMOOTH_NORMAL) {
148         float u = isect.hits[hit].u;
149         float v = isect.hits[hit].v;
150
151         if (sd->type & PRIMITIVE_TRIANGLE) {
152           N = triangle_smooth_normal(kg, N, prim, u, v);
153         }
154 #ifdef __OBJECT_MOTION__
155         else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
156           N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
157         }
158 #endif /* __OBJECT_MOTION__ */
159       }
160
161       /* Transform normals to world space. */
162       if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
163         object_normal_transform(kg, sd, &N);
164         object_normal_transform(kg, sd, &hit_Ng);
165       }
166
167       /* Probability densities for local frame axes. */
168       float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
169       float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
170       float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
171
172       /* Multiple importance sample between 3 axes, power heuristic
173        * found to be slightly better than balance heuristic. pdf_N
174        * in the MIS weight and denominator cancelled out. */
175       float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
176       if (isect.num_hits > LOCAL_MAX_HITS) {
177         w *= isect.num_hits / (float)LOCAL_MAX_HITS;
178       }
179
180       /* Real distance to sampled point. */
181       float r = len(hit_P - sd->P);
182
183       /* Compute weight. */
184       float pdf = bssrdf_cubic_pdf(radius, 0.0f, r);
185       float disk_pdf = bssrdf_cubic_pdf(radius, 0.0f, disk_r);
186
187       w *= pdf / disk_pdf;
188
189       /* Sum normal and weight. */
190       sum_N += w * N;
191     }
192   }
193
194   /* Normalize. */
195   float3 N = safe_normalize(sum_N);
196   return is_zero(N) ? sd->N : (sd->flag & SD_BACKFACING) ? -N : N;
197 }
198
199 ccl_device void svm_node_bevel(
200     KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, float *stack, uint4 node)
201 {
202   uint num_samples, radius_offset, normal_offset, out_offset;
203   decode_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset);
204
205   float radius = stack_load_float(stack, radius_offset);
206   float3 bevel_N = svm_bevel(kg, sd, state, radius, num_samples);
207
208   if (stack_valid(normal_offset)) {
209     /* Preserve input normal. */
210     float3 ref_N = stack_load_float3(stack, normal_offset);
211     bevel_N = normalize(ref_N + (bevel_N - sd->N));
212   }
213
214   stack_store_float3(stack, out_offset, bevel_N);
215 }
216
217 CCL_NAMESPACE_END