1 
2 /*
3  * Copyright 2011-2013 Blender Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "render/curves.h"
19 #include "render/hair.h"
20 #include "render/mesh.h"
21 #include "render/object.h"
22 #include "render/volume.h"
23 
24 #include "blender/blender_sync.h"
25 #include "blender/blender_util.h"
26 
27 #include "util/util_foreach.h"
28 
29 CCL_NAMESPACE_BEGIN
30 
determine_geom_type(BL::Object & b_ob,bool use_particle_hair)31 static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_hair)
32 {
33   if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
34     return Geometry::HAIR;
35   }
36 
37   if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
38     return Geometry::VOLUME;
39   }
40 
41   return Geometry::MESH;
42 }
43 
sync_geometry(BL::Depsgraph & b_depsgraph,BL::Object & b_ob,BL::Object & b_ob_instance,bool object_updated,bool use_particle_hair)44 Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
45                                      BL::Object &b_ob,
46                                      BL::Object &b_ob_instance,
47                                      bool object_updated,
48                                      bool use_particle_hair)
49 {
50   /* Test if we can instance or if the object is modified. */
51   BL::ID b_ob_data = b_ob.data();
52   BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
53   BL::Material material_override = view_layer.material_override;
54   Shader *default_shader = (b_ob.type() == BL::Object::type_VOLUME) ? scene->default_volume :
55                                                                       scene->default_surface;
56   Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
57   GeometryKey key(b_key_id.ptr.data, geom_type);
58 
59   /* Find shader indices. */
60   vector<Shader *> used_shaders;
61 
62   BL::Object::material_slots_iterator slot;
63   for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
64     if (material_override) {
65       find_shader(material_override, used_shaders, default_shader);
66     }
67     else {
68       BL::ID b_material(slot->material());
69       find_shader(b_material, used_shaders, default_shader);
70     }
71   }
72 
73   if (used_shaders.size() == 0) {
74     if (material_override)
75       find_shader(material_override, used_shaders, default_shader);
76     else
77       used_shaders.push_back(default_shader);
78   }
79 
80   /* Test if we need to sync. */
81   Geometry *geom = geometry_map.find(key);
82   bool sync = true;
83   if (geom == NULL) {
84     /* Add new geometry if it did not exist yet. */
85     if (geom_type == Geometry::HAIR) {
86       geom = scene->create_node<Hair>();
87     }
88     else if (geom_type == Geometry::VOLUME) {
89       geom = scene->create_node<Volume>();
90     }
91     else {
92       geom = scene->create_node<Mesh>();
93     }
94     geometry_map.add(key, geom);
95   }
96   else {
97     /* Test if we need to update existing geometry. */
98     sync = geometry_map.update(geom, b_key_id);
99   }
100 
101   if (!sync) {
102     /* If transform was applied to geometry, need full update. */
103     if (object_updated && geom->transform_applied) {
104       ;
105     }
106     /* Test if shaders changed, these can be object level so geometry
107      * does not get tagged for recalc. */
108     else if (geom->used_shaders != used_shaders) {
109       ;
110     }
111     else {
112       /* Even if not tagged for recalc, we may need to sync anyway
113        * because the shader needs different geometry attributes. */
114       bool attribute_recalc = false;
115 
116       foreach (Shader *shader, geom->used_shaders) {
117         if (shader->need_update_geometry) {
118           attribute_recalc = true;
119         }
120       }
121 
122       if (!attribute_recalc) {
123         return geom;
124       }
125     }
126   }
127 
128   /* Ensure we only sync instanced geometry once. */
129   if (geometry_synced.find(geom) != geometry_synced.end()) {
130     return geom;
131   }
132 
133   progress.set_sync_status("Synchronizing object", b_ob.name());
134 
135   geometry_synced.insert(geom);
136 
137   geom->name = ustring(b_ob_data.name().c_str());
138 
139   if (geom_type == Geometry::HAIR) {
140     Hair *hair = static_cast<Hair *>(geom);
141     sync_hair(b_depsgraph, b_ob, hair, used_shaders);
142   }
143   else if (geom_type == Geometry::VOLUME) {
144     Volume *volume = static_cast<Volume *>(geom);
145     sync_volume(b_ob, volume, used_shaders);
146   }
147   else {
148     Mesh *mesh = static_cast<Mesh *>(geom);
149     sync_mesh(b_depsgraph, b_ob, mesh, used_shaders);
150   }
151 
152   return geom;
153 }
154 
sync_geometry_motion(BL::Depsgraph & b_depsgraph,BL::Object & b_ob,Object * object,float motion_time,bool use_particle_hair)155 void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
156                                        BL::Object &b_ob,
157                                        Object *object,
158                                        float motion_time,
159                                        bool use_particle_hair)
160 {
161   /* Ensure we only sync instanced geometry once. */
162   Geometry *geom = object->geometry;
163 
164   if (geometry_motion_synced.find(geom) != geometry_motion_synced.end())
165     return;
166 
167   geometry_motion_synced.insert(geom);
168 
169   /* Ensure we only motion sync geometry that also had geometry synced, to avoid
170    * unnecessary work and to ensure that its attributes were clear. */
171   if (geometry_synced.find(geom) == geometry_synced.end())
172     return;
173 
174   /* Find time matching motion step required by geometry. */
175   int motion_step = geom->motion_step(motion_time);
176   if (motion_step < 0) {
177     return;
178   }
179 
180   if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
181     Hair *hair = static_cast<Hair *>(geom);
182     sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
183   }
184   else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
185     /* No volume motion blur support yet. */
186   }
187   else {
188     Mesh *mesh = static_cast<Mesh *>(geom);
189     sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
190   }
191 }
192 
193 CCL_NAMESPACE_END
194