1 
2 
3 /*
4  * Copyright 2011-2013 Blender Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "render/light.h"
20 
21 #include "blender/blender_sync.h"
22 #include "blender/blender_util.h"
23 
24 #include "util/util_hash.h"
25 
26 CCL_NAMESPACE_BEGIN
27 
sync_light(BL::Object & b_parent,int persistent_id[OBJECT_PERSISTENT_ID_SIZE],BL::Object & b_ob,BL::Object & b_ob_instance,int random_id,Transform & tfm,bool * use_portal)28 void BlenderSync::sync_light(BL::Object &b_parent,
29                              int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
30                              BL::Object &b_ob,
31                              BL::Object &b_ob_instance,
32                              int random_id,
33                              Transform &tfm,
34                              bool *use_portal)
35 {
36   /* test if we need to sync */
37   Light *light;
38   ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
39   BL::Light b_light(b_ob.data());
40 
41   /* Update if either object or light data changed. */
42   if (!light_map.add_or_update(&light, b_ob, b_parent, key)) {
43     Shader *shader;
44     if (!shader_map.add_or_update(&shader, b_light)) {
45       if (light->is_portal)
46         *use_portal = true;
47       return;
48     }
49   }
50 
51   /* type */
52   switch (b_light.type()) {
53     case BL::Light::type_POINT: {
54       BL::PointLight b_point_light(b_light);
55       light->size = b_point_light.shadow_soft_size();
56       light->type = LIGHT_POINT;
57       break;
58     }
59     case BL::Light::type_SPOT: {
60       BL::SpotLight b_spot_light(b_light);
61       light->size = b_spot_light.shadow_soft_size();
62       light->type = LIGHT_SPOT;
63       light->spot_angle = b_spot_light.spot_size();
64       light->spot_smooth = b_spot_light.spot_blend();
65       break;
66     }
67     /* Hemi were removed from 2.8 */
68     // case BL::Light::type_HEMI: {
69     //  light->type = LIGHT_DISTANT;
70     //  light->size = 0.0f;
71     //  break;
72     // }
73     case BL::Light::type_SUN: {
74       BL::SunLight b_sun_light(b_light);
75       light->angle = b_sun_light.angle();
76       light->type = LIGHT_DISTANT;
77       break;
78     }
79     case BL::Light::type_AREA: {
80       BL::AreaLight b_area_light(b_light);
81       light->size = 1.0f;
82       light->axisu = transform_get_column(&tfm, 0);
83       light->axisv = transform_get_column(&tfm, 1);
84       light->sizeu = b_area_light.size();
85       switch (b_area_light.shape()) {
86         case BL::AreaLight::shape_SQUARE:
87           light->sizev = light->sizeu;
88           light->round = false;
89           break;
90         case BL::AreaLight::shape_RECTANGLE:
91           light->sizev = b_area_light.size_y();
92           light->round = false;
93           break;
94         case BL::AreaLight::shape_DISK:
95           light->sizev = light->sizeu;
96           light->round = true;
97           break;
98         case BL::AreaLight::shape_ELLIPSE:
99           light->sizev = b_area_light.size_y();
100           light->round = true;
101           break;
102       }
103       light->type = LIGHT_AREA;
104       break;
105     }
106   }
107 
108   /* strength */
109   light->strength = get_float3(b_light.color());
110   light->strength *= BL::PointLight(b_light).energy();
111 
112   /* location and (inverted!) direction */
113   light->co = transform_get_column(&tfm, 3);
114   light->dir = -transform_get_column(&tfm, 2);
115   light->tfm = tfm;
116 
117   /* shader */
118   vector<Shader *> used_shaders;
119   find_shader(b_light, used_shaders, scene->default_light);
120   light->shader = used_shaders[0];
121 
122   /* shadow */
123   PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
124   PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
125   light->cast_shadow = get_boolean(clight, "cast_shadow");
126   light->use_mis = get_boolean(clight, "use_multiple_importance_sampling");
127 
128   int samples = get_int(clight, "samples");
129   if (get_boolean(cscene, "use_square_samples"))
130     light->samples = samples * samples;
131   else
132     light->samples = samples;
133 
134   light->max_bounces = get_int(clight, "max_bounces");
135 
136   if (b_ob != b_ob_instance) {
137     light->random_id = random_id;
138   }
139   else {
140     light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0);
141   }
142 
143   if (light->type == LIGHT_AREA)
144     light->is_portal = get_boolean(clight, "is_portal");
145   else
146     light->is_portal = false;
147 
148   if (light->is_portal)
149     *use_portal = true;
150 
151   /* visibility */
152   uint visibility = object_ray_visibility(b_ob);
153   light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
154   light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
155   light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
156   light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
157 
158   /* tag */
159   light->tag_update(scene);
160 }
161 
sync_background_light(BL::SpaceView3D & b_v3d,bool use_portal)162 void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
163 {
164   BL::World b_world = b_scene.world();
165 
166   if (b_world) {
167     PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
168     PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
169 
170     enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
171     int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
172     bool sample_as_light = (sampling_method != SAMPLING_NONE);
173 
174     if (sample_as_light || use_portal) {
175       /* test if we need to sync */
176       Light *light;
177       ObjectKey key(b_world, 0, b_world, false);
178 
179       if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc ||
180           b_world.ptr.data != world_map) {
181         light->type = LIGHT_BACKGROUND;
182         if (sampling_method == SAMPLING_MANUAL) {
183           light->map_resolution = get_int(cworld, "sample_map_resolution");
184         }
185         else {
186           light->map_resolution = 0;
187         }
188         light->shader = scene->default_background;
189         light->use_mis = sample_as_light;
190         light->max_bounces = get_int(cworld, "max_bounces");
191 
192         /* force enable light again when world is resynced */
193         light->is_enabled = true;
194 
195         int samples = get_int(cworld, "samples");
196         if (get_boolean(cscene, "use_square_samples"))
197           light->samples = samples * samples;
198         else
199           light->samples = samples;
200 
201         light->tag_update(scene);
202         light_map.set_recalc(b_world);
203       }
204     }
205   }
206 
207   world_map = b_world.ptr.data;
208   world_recalc = false;
209   viewport_parameters = BlenderViewportParameters(b_v3d);
210 }
211 
212 CCL_NAMESPACE_END
213