Merge branch 'master' into blender2.8
[blender.git] / source / blender / draw / engines / workbench / workbench_studiolight.c
1 /*
2  * Copyright 2016, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Institute
19  *
20  */
21
22 /** \file workbench_studiolight.c
23  *  \ingroup draw_engine
24  */
25 #include "BKE_studiolight.h"
26
27 #include "DRW_engine.h"
28 #include "workbench_private.h"
29
30 #include "BKE_object.h"
31
32 #include "BLI_math.h"
33 #include "BKE_global.h"
34
35 void studiolight_update_world(WORKBENCH_PrivateData *wpd, StudioLight *studiolight, WORKBENCH_UBO_World *wd)
36 {
37         float view_matrix[4][4], rot_matrix[4][4];
38         DRW_viewport_matrix_get(view_matrix, DRW_MAT_VIEW);
39
40         if (USE_WORLD_ORIENTATION(wpd)) {
41                 axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z);
42                 mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix);
43                 swap_v3_v3(rot_matrix[2], rot_matrix[1]);
44                 negate_v3(rot_matrix[2]);
45         }
46         else {
47                 unit_m4(rot_matrix);
48         }
49
50         if (U.edit_studio_light) {
51                 studiolight = BKE_studiolight_studio_edit_get();
52         }
53
54         /* Studio Lights. */
55         for (int i = 0; i < 4; i++) {
56                 WORKBENCH_UBO_Light *light = &wd->lights[i];
57
58                 SolidLight *sl = &studiolight->light[i];
59                 if (sl->flag) {
60                         copy_v3_v3(light->light_direction, sl->vec);
61                         mul_mat3_m4_v3(rot_matrix, light->light_direction);
62                         /* We should predivide the power by PI but that makes the lights really dim. */
63                         copy_v3_v3(light->specular_color, sl->spec);
64                         copy_v3_v3(light->diffuse_color, sl->col);
65                         light->wrapped = sl->smooth;
66                 }
67                 else {
68                         copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f);
69                         copy_v3_fl(light->specular_color, 0.0f);
70                         copy_v3_fl(light->diffuse_color, 0.0f);
71                 }
72         }
73
74         copy_v3_v3(wd->ambient_color, studiolight->light_ambient);
75
76 #if 0
77         BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
78
79 #if STUDIOLIGHT_SH_BANDS == 2
80         /* Use Geomerics non-linear SH. */
81         mul_v3_v3fl(wd->spherical_harmonics_coefs[0], sl->spherical_harmonics_coefs[0], M_1_PI);
82         /* Swizzle to make shader code simpler. */
83         for (int i = 0; i < 3; ++i) {
84                 copy_v3_fl3(
85                         wd->spherical_harmonics_coefs[i + 1],
86                         -sl->spherical_harmonics_coefs[3][i],
87                         sl->spherical_harmonics_coefs[2][i],
88                         -sl->spherical_harmonics_coefs[1][i]);
89                 mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], M_1_PI * 1.5f); /* 1.5f is to improve the contrast a bit. */
90         }
91
92         /* Precompute as much as we can. See shader code for derivation. */
93         float len_r1[3], lr1_r0[3], p[3], a[3];
94         for (int i = 0; i < 3; ++i) {
95                 mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 0.5f);
96                 len_r1[i] = len_v3(wd->spherical_harmonics_coefs[i + 1]);
97                 mul_v3_fl(wd->spherical_harmonics_coefs[i + 1], 1.0f / len_r1[i]);
98         }
99         /* lr1_r0 = lenR1 / R0; */
100         copy_v3_v3(lr1_r0, wd->spherical_harmonics_coefs[0]);
101         invert_v3(lr1_r0);
102         mul_v3_v3(lr1_r0, len_r1);
103         /* p = 1.0 + 2.0 * lr1_r0; */
104         copy_v3_v3(p, lr1_r0);
105         mul_v3_fl(p, 2.0f);
106         add_v3_fl(p, 1.0f);
107         /* a = (1.0 - lr1_r0) / (1.0 + lr1_r0); */
108         copy_v3_v3(a, lr1_r0);
109         add_v3_fl(a, 1.0f);
110         invert_v3(a);
111         negate_v3(lr1_r0);
112         add_v3_fl(lr1_r0, 1.0f);
113         mul_v3_v3(a, lr1_r0);
114         /* sh_coefs[4] = p; */
115         copy_v3_v3(wd->spherical_harmonics_coefs[4], p);
116         /* sh_coefs[5] = R0 * a; */
117         mul_v3_v3v3(wd->spherical_harmonics_coefs[5], wd->spherical_harmonics_coefs[0], a);
118         /* sh_coefs[0] = R0 * (1.0 - a) * (p + 1.0); */
119         negate_v3(a);
120         add_v3_fl(a, 1.0f);
121         add_v3_fl(p, 1.0f);
122         mul_v3_v3(a, p);
123         mul_v3_v3(wd->spherical_harmonics_coefs[0], a);
124 #else
125         for (int i = 0; i < STUDIOLIGHT_SH_EFFECTIVE_COEFS_LEN; i++) {
126                 /* Can't memcpy because of alignment */
127                 copy_v3_v3(wd->spherical_harmonics_coefs[i], sl->spherical_harmonics_coefs[i]);
128         }
129 #endif
130 #endif
131 }
132
133 static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], float r_line[2])
134 {
135         sub_v2_v2v2(r_line, v2, v1);
136         /* Find orthogonal vector. */
137         SWAP(float, r_line[0], r_line[1]);
138         r_line[0] = -r_line[0];
139         /* Edge distances. */
140         r_line[2] = dot_v2v2(r_line, v1);
141         r_line[3] = dot_v2v2(r_line, v3);
142         /* Make sure r_line[2] is the minimum. */
143         if (r_line[2] > r_line[3]) {
144                 SWAP(float, r_line[2], r_line[3]);
145         }
146 }
147
148 void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
149 {
150         wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
151
152         if (wpd->shadow_changed) {
153                 float up[3] = {0.0f, 0.0f, 1.0f};
154                 unit_m4(wpd->shadow_mat);
155
156                 /* TODO fix singularity. */
157                 copy_v3_v3(wpd->shadow_mat[2], light_direction);
158                 cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
159                 normalize_v3(wpd->shadow_mat[0]);
160                 cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
161
162                 invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
163
164                 copy_v3_v3(wpd->cached_shadow_direction, light_direction);
165         }
166
167         float planes[6][4];
168         DRW_culling_frustum_planes_get(planes);
169         /* we only need the far plane. */
170         copy_v4_v4(wpd->shadow_far_plane, planes[2]);
171
172         BoundBox frustum_corners;
173         DRW_culling_frustum_corners_get(&frustum_corners);
174
175         mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
176         mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
177         mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
178         mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
179
180         INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max);
181         for (int i = 0; i < 4; ++i) {
182                 minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
183         }
184
185         compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0], wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_sides[0]);
186         compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_corners[0], wpd->shadow_near_sides[1]);
187 }
188
189 static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
190 {
191         if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) {
192                 float tmp_mat[4][4];
193                 mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat);
194
195                 /* Get AABB in shadow space. */
196                 INIT_MINMAX(oed->shadow_min, oed->shadow_max);
197
198                 /* From object space to shadow space */
199                 BoundBox *bbox = BKE_object_boundbox_get(ob);
200                 for (int i = 0; i < 8; ++i) {
201                         float corner[3];
202                         mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]);
203                         minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner);
204                 }
205                 oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2];
206                 /* Extend towards infinity. */
207                 oed->shadow_max[2] += 1e4f;
208
209                 /* Get extended AABB in world space. */
210                 BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max);
211                 for (int i = 0; i < 8; ++i) {
212                         mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]);
213                 }
214                 oed->shadow_bbox_dirty = false;
215         }
216
217         return &oed->shadow_bbox;
218 }
219
220 bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
221 {
222         BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
223         return DRW_culling_box_test(shadow_bbox);
224 }
225
226 float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
227 {
228         BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed);
229
230         int corners[4] = {0, 3, 4, 7};
231         float dist = 1e4f, dist_isect;
232         for (int i = 0; i < 4; ++i) {
233                 if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]],
234                                        wpd->cached_shadow_direction,
235                                        wpd->shadow_far_plane,
236                                        &dist_isect, true))
237                 {
238                         if (dist_isect < dist) {
239                                 dist = dist_isect;
240                         }
241                 }
242                 else {
243                         /* All rays are parallels. If one fails, the other will too. */
244                         break;
245                 }
246         }
247         return max_ii(dist - oed->shadow_depth, 0);
248 }
249
250 bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed)
251 {
252         /* Just to be sure the min, max are updated. */
253         studiolight_object_shadow_bbox_get(wpd, ob, oed);
254
255         /* Test if near plane is in front of the shadow. */
256         if (oed->shadow_min[2] > wpd->shadow_near_max[2]) {
257                 return false;
258         }
259
260         /* Separation Axis Theorem test */
261
262         /* Test bbox sides first (faster) */
263         if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) ||
264             (oed->shadow_max[0] < wpd->shadow_near_min[0]) ||
265             (oed->shadow_min[1] > wpd->shadow_near_max[1]) ||
266             (oed->shadow_max[1] < wpd->shadow_near_min[1]))
267         {
268                 return false;
269         }
270
271         /* Test projected near rectangle sides */
272         float pts[4][2] = {
273                 {oed->shadow_min[0], oed->shadow_min[1]},
274                 {oed->shadow_min[0], oed->shadow_max[1]},
275                 {oed->shadow_max[0], oed->shadow_min[1]},
276                 {oed->shadow_max[0], oed->shadow_max[1]}
277         };
278
279         for (int i = 0; i < 2; ++i) {
280                 float min_dst = FLT_MAX, max_dst = -FLT_MAX;
281                 for (int j = 0; j < 4; ++j) {
282                         float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]);
283                         /* Do min max */
284                         if (min_dst > dst) min_dst = dst;
285                         if (max_dst < dst) max_dst = dst;
286                 }
287
288                 if ((wpd->shadow_near_sides[i][2] > max_dst) ||
289                     (wpd->shadow_near_sides[i][3] < min_dst))
290                 {
291                         return false;
292                 }
293         }
294
295         /* No separation axis found. Both shape intersect. */
296         return true;
297 }