Fix T57963: Cycles crash using AO for displacement.
[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(
26         KernelGlobals *kg,
27         ShaderData *sd,
28         ccl_addr_space PathState *state,
29         float radius,
30         int num_samples)
31 {
32         /* Early out if no sampling needed. */
33         if(radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
34                 return sd->N;
35         }
36
37         /* Can't raytrace from shaders like displacement, before BVH exists. */
38         if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
39                 return sd->N;
40         }
41
42         /* Don't bevel for blurry indirect rays. */
43         if(state->min_ray_pdf < 8.0f) {
44                 return sd->N;
45         }
46
47         /* Setup for multi intersection. */
48         LocalIntersection isect;
49         uint lcg_state = lcg_state_init_addrspace(state, 0x64c6a40e);
50
51         /* Sample normals from surrounding points on surface. */
52         float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
53
54         for(int sample = 0; sample < num_samples; sample++) {
55                 float disk_u, disk_v;
56                 path_branched_rng_2D(kg, state->rng_hash, state, sample, num_samples,
57                                      PRNG_BEVEL_U, &disk_u, &disk_v);
58
59                 /* Pick random axis in local frame and point on disk. */
60                 float3 disk_N, disk_T, disk_B;
61                 float pick_pdf_N, pick_pdf_T, pick_pdf_B;
62
63                 disk_N = sd->Ng;
64                 make_orthonormals(disk_N, &disk_T, &disk_B);
65
66                 float axisu = disk_u;
67
68                 if(axisu < 0.5f) {
69                         pick_pdf_N = 0.5f;
70                         pick_pdf_T = 0.25f;
71                         pick_pdf_B = 0.25f;
72                         disk_u *= 2.0f;
73                 }
74                 else if(axisu < 0.75f) {
75                         float3 tmp = disk_N;
76                         disk_N = disk_T;
77                         disk_T = tmp;
78                         pick_pdf_N = 0.25f;
79                         pick_pdf_T = 0.5f;
80                         pick_pdf_B = 0.25f;
81                         disk_u = (disk_u - 0.5f)*4.0f;
82                 }
83                 else {
84                         float3 tmp = disk_N;
85                         disk_N = disk_B;
86                         disk_B = tmp;
87                         pick_pdf_N = 0.25f;
88                         pick_pdf_T = 0.25f;
89                         pick_pdf_B = 0.5f;
90                         disk_u = (disk_u - 0.75f)*4.0f;
91                 }
92
93                 /* Sample point on disk. */
94                 float phi = M_2PI_F * disk_u;
95                 float disk_r = disk_v;
96                 float disk_height;
97
98                 /* Perhaps find something better than Cubic BSSRDF, but happens to work well. */
99                 bssrdf_cubic_sample(radius, 0.0f, disk_r, &disk_r, &disk_height);
100
101                 float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B;
102
103                 /* Create ray. */
104                 Ray *ray = &isect.ray;
105                 ray->P = sd->P + disk_N*disk_height + disk_P;
106                 ray->D = -disk_N;
107                 ray->t = 2.0f*disk_height;
108                 ray->dP = sd->dP;
109                 ray->dD = differential3_zero();
110                 ray->time = sd->time;
111
112                 /* Intersect with the same object. if multiple intersections are found it
113                  * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
114                 scene_intersect_local(kg,
115                                       *ray,
116                                       &isect,
117                                       sd->object,
118                                       &lcg_state,
119                                       LOCAL_MAX_HITS);
120
121                 int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS);
122
123                 for(int hit = 0; hit < num_eval_hits; hit++) {
124                         /* Quickly retrieve P and Ng without setting up ShaderData. */
125                         float3 hit_P;
126                         if(sd->type & PRIMITIVE_TRIANGLE) {
127                                 hit_P = triangle_refine_local(kg,
128                                                               sd,
129                                                               &isect.hits[hit],
130                                                               ray);
131                         }
132 #ifdef __OBJECT_MOTION__
133                         else  if(sd->type & PRIMITIVE_MOTION_TRIANGLE) {
134                                 float3 verts[3];
135                                 motion_triangle_vertices(
136                                         kg,
137                                         sd->object,
138                                         kernel_tex_fetch(__prim_index, isect.hits[hit].prim),
139                                         sd->time,
140                                         verts);
141                                 hit_P = motion_triangle_refine_local(kg,
142                                                                      sd,
143                                                                      &isect.hits[hit],
144                                                                      ray,
145                                                                      verts);
146                         }
147 #endif  /* __OBJECT_MOTION__ */
148
149                         float3 hit_Ng = isect.Ng[hit];
150
151                         /* Compute smooth normal. */
152                         float3 N = hit_Ng;
153                         int prim = kernel_tex_fetch(__prim_index, isect.hits[hit].prim);
154                         int shader = kernel_tex_fetch(__tri_shader, prim);
155
156                         if(shader & SHADER_SMOOTH_NORMAL) {
157                                 float u = isect.hits[hit].u;
158                                 float v = isect.hits[hit].v;
159
160                                 if(sd->type & PRIMITIVE_TRIANGLE) {
161                                         N = triangle_smooth_normal(kg, N, prim, u, v);
162                                 }
163 #ifdef __OBJECT_MOTION__
164                                 else if(sd->type & PRIMITIVE_MOTION_TRIANGLE) {
165                                         N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
166                                 }
167 #endif  /* __OBJECT_MOTION__ */
168                         }
169
170                         /* Transform normals to world space. */
171                         if(isect.hits[hit].object != OBJECT_NONE) {
172                                 object_normal_transform(kg, sd, &N);
173                                 object_normal_transform(kg, sd, &hit_Ng);
174                         }
175
176                         /* Probability densities for local frame axes. */
177                         float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
178                         float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
179                         float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
180
181                         /* Multiple importance sample between 3 axes, power heuristic
182                          * found to be slightly better than balance heuristic. pdf_N
183                          * in the MIS weight and denominator cancelled out. */
184                         float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
185                         if(isect.num_hits > LOCAL_MAX_HITS) {
186                                 w *= isect.num_hits/(float)LOCAL_MAX_HITS;
187                         }
188
189                         /* Real distance to sampled point. */
190                         float r = len(hit_P - sd->P);
191
192                         /* Compute weight. */
193                         float pdf = bssrdf_cubic_pdf(radius, 0.0f, r);
194                         float disk_pdf = bssrdf_cubic_pdf(radius, 0.0f, disk_r);
195
196                         w *= pdf / disk_pdf;
197
198                         /* Sum normal and weight. */
199                         sum_N += w * N;
200                 }
201         }
202
203         /* Normalize. */
204         float3 N = safe_normalize(sum_N);
205         return is_zero(N) ? sd->N : (sd->flag & SD_BACKFACING) ? -N : N;
206 }
207
208 ccl_device void svm_node_bevel(
209         KernelGlobals *kg,
210         ShaderData *sd,
211         ccl_addr_space PathState *state,
212         float *stack,
213         uint4 node)
214 {
215         uint num_samples, radius_offset, normal_offset, out_offset;
216         decode_node_uchar4(node.y, &num_samples, &radius_offset, &normal_offset, &out_offset);
217
218         float radius = stack_load_float(stack, radius_offset);
219         float3 bevel_N = svm_bevel(kg, sd, state, radius, num_samples);
220
221         if(stack_valid(normal_offset)) {
222                 /* Preserve input normal. */
223                 float3 ref_N = stack_load_float3(stack, normal_offset);
224                 bevel_N = normalize(ref_N + (bevel_N - sd->N));
225         }
226
227         stack_store_float3(stack, out_offset, bevel_N);
228 }
229
230 CCL_NAMESPACE_END