Merge branch 'master' into blender2.8
[blender.git] / release / scripts / startup / bl_ui / properties_physics_smoke.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 from bpy.types import Panel
22
23 from .properties_physics_common import (
24     point_cache_ui,
25     effector_weights_ui,
26 )
27
28
29 class PhysicButtonsPanel:
30     bl_space_type = 'PROPERTIES'
31     bl_region_type = 'WINDOW'
32     bl_context = "physics"
33
34     @classmethod
35     def poll(cls, context):
36         ob = context.object
37         view_render = context.scene.view_render
38         return (ob and ob.type == 'MESH') and (view_render.engine in cls.COMPAT_ENGINES) and (context.smoke)
39
40
41 class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel):
42     bl_label = "Smoke"
43     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
44
45     def draw(self, context):
46         layout = self.layout
47
48         if not bpy.app.build_options.mod_smoke:
49             layout.label("Built without Smoke modifier")
50             return
51
52         md = context.smoke
53         ob = context.object
54
55         layout.row().prop(md, "smoke_type", expand=True)
56
57         if md.smoke_type == 'DOMAIN':
58             domain = md.domain_settings
59
60             split = layout.split()
61
62             split.enabled = not domain.point_cache.is_baked
63
64             col = split.column()
65             col.label(text="Resolution:")
66             col.prop(domain, "resolution_max", text="Divisions")
67             col.label(text="Time:")
68             col.prop(domain, "time_scale", text="Scale")
69             col.label(text="Border Collisions:")
70             col.prop(domain, "collision_extents", text="")
71             col.label(text="Empty Space:")
72             col.prop(domain, "clipping")
73
74             col = split.column()
75             col.label(text="Behavior:")
76             col.prop(domain, "alpha")
77             col.prop(domain, "beta", text="Temp. Diff.")
78             col.prop(domain, "vorticity")
79             col.prop(domain, "use_dissolve_smoke", text="Dissolve")
80             sub = col.column()
81             sub.active = domain.use_dissolve_smoke
82             sub.prop(domain, "dissolve_speed", text="Time")
83             sub.prop(domain, "use_dissolve_smoke_log", text="Slow")
84
85         elif md.smoke_type == 'FLOW':
86
87             flow = md.flow_settings
88
89             layout.prop(flow, "smoke_flow_type", expand=False)
90
91             if flow.smoke_flow_type != 'OUTFLOW':
92                 split = layout.split()
93                 col = split.column()
94                 col.label(text="Flow Source:")
95                 col.prop(flow, "smoke_flow_source", expand=False, text="")
96                 if flow.smoke_flow_source == 'PARTICLES':
97                     col.label(text="Particle System:")
98                     col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
99                     col.prop(flow, "use_particle_size", text="Set Size")
100                     sub = col.column()
101                     sub.active = flow.use_particle_size
102                     sub.prop(flow, "particle_size")
103                 else:
104                     col.prop(flow, "surface_distance")
105                     col.prop(flow, "volume_density")
106
107                 sub = col.column(align=True)
108                 sub.prop(flow, "use_initial_velocity")
109
110                 sub = sub.column()
111                 sub.active = flow.use_initial_velocity
112                 sub.prop(flow, "velocity_factor")
113                 if flow.smoke_flow_source == 'MESH':
114                     sub.prop(flow, "velocity_normal")
115                     #sub.prop(flow, "velocity_random")
116
117                 sub = split.column()
118                 sub.label(text="Initial Values:")
119                 sub.prop(flow, "use_absolute")
120                 if flow.smoke_flow_type in {'SMOKE', 'BOTH'}:
121                     sub.prop(flow, "density")
122                     sub.prop(flow, "temperature")
123                     sub.prop(flow, "smoke_color")
124                 if flow.smoke_flow_type in {'FIRE', 'BOTH'}:
125                     sub.prop(flow, "fuel_amount")
126                 sub.label(text="Sampling:")
127                 sub.prop(flow, "subframes")
128
129         elif md.smoke_type == 'COLLISION':
130             coll = md.coll_settings
131
132             split = layout.split()
133
134             col = split.column()
135             col.prop(coll, "collision_type")
136
137
138 class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
139     bl_label = "Smoke Flow Advanced"
140     bl_options = {'DEFAULT_CLOSED'}
141     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
142
143     @classmethod
144     def poll(cls, context):
145         md = context.smoke
146         return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == 'MESH')
147
148     def draw(self, context):
149         layout = self.layout
150         ob = context.object
151         flow = context.smoke.flow_settings
152
153         split = layout.split()
154         col = split.column()
155
156         col.prop(flow, "use_texture")
157         sub = col.column()
158         sub.active = flow.use_texture
159         sub.prop(flow, "noise_texture", text="")
160         sub.label(text="Mapping:")
161         sub.prop(flow, "texture_map_type", expand=False, text="")
162         if flow.texture_map_type == 'UV':
163             sub.prop_search(flow, "uv_layer", ob.data, "uv_layers", text="")
164         if flow.texture_map_type == 'AUTO':
165             sub.prop(flow, "texture_size")
166         sub.prop(flow, "texture_offset")
167
168         col = split.column()
169         col.label(text="Vertex Group:")
170         col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="")
171
172
173 class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
174     bl_label = "Smoke Flames"
175     bl_options = {'DEFAULT_CLOSED'}
176     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
177
178     @classmethod
179     def poll(cls, context):
180         md = context.smoke
181         return md and (md.smoke_type == 'DOMAIN')
182
183     def draw(self, context):
184         layout = self.layout
185         domain = context.smoke.domain_settings
186
187         split = layout.split()
188         split.enabled = not domain.point_cache.is_baked
189
190         col = split.column(align=True)
191         col.label(text="Reaction:")
192         col.prop(domain, "burning_rate")
193         col.prop(domain, "flame_smoke")
194         col.prop(domain, "flame_vorticity")
195
196         col = split.column(align=True)
197         col.label(text="Temperatures:")
198         col.prop(domain, "flame_ignition")
199         col.prop(domain, "flame_max_temp")
200         col.prop(domain, "flame_smoke_color")
201
202
203 class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
204     bl_label = "Smoke Adaptive Domain"
205     bl_options = {'DEFAULT_CLOSED'}
206     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
207
208     @classmethod
209     def poll(cls, context):
210         md = context.smoke
211         return md and (md.smoke_type == 'DOMAIN')
212
213     def draw_header(self, context):
214         md = context.smoke.domain_settings
215
216         self.layout.prop(md, "use_adaptive_domain", text="")
217
218     def draw(self, context):
219         layout = self.layout
220
221         domain = context.smoke.domain_settings
222         layout.active = domain.use_adaptive_domain
223
224         split = layout.split()
225         split.enabled = (not domain.point_cache.is_baked)
226
227         col = split.column(align=True)
228         col.label(text="Resolution:")
229         col.prop(domain, "additional_res")
230         col.prop(domain, "adapt_margin")
231
232         col = split.column(align=True)
233         col.label(text="Advanced:")
234         col.prop(domain, "adapt_threshold")
235
236
237 class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
238     bl_label = "Smoke High Resolution"
239     bl_options = {'DEFAULT_CLOSED'}
240     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
241
242     @classmethod
243     def poll(cls, context):
244         md = context.smoke
245         view_render = context.scene.view_render
246         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
247
248     def draw_header(self, context):
249         md = context.smoke.domain_settings
250
251         self.layout.prop(md, "use_high_resolution", text="")
252
253     def draw(self, context):
254         layout = self.layout
255
256         md = context.smoke.domain_settings
257
258         layout.active = md.use_high_resolution
259
260         split = layout.split()
261         split.enabled = not md.point_cache.is_baked
262
263         col = split.column()
264         col.label(text="Resolution:")
265         col.prop(md, "amplify", text="Divisions")
266         col.label(text="Flow Sampling:")
267         col.row().prop(md, "highres_sampling", text="")
268
269         col = split.column()
270         col.label(text="Noise Method:")
271         col.row().prop(md, "noise_type", text="")
272         col.prop(md, "strength")
273
274         layout.prop(md, "show_high_resolution")
275
276
277 class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
278     bl_label = "Smoke Groups"
279     bl_options = {'DEFAULT_CLOSED'}
280     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
281
282     @classmethod
283     def poll(cls, context):
284         md = context.smoke
285         view_render = context.scene.view_render
286         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
287
288     def draw(self, context):
289         layout = self.layout
290         domain = context.smoke.domain_settings
291
292         split = layout.split()
293
294         col = split.column()
295         col.label(text="Flow Group:")
296         col.prop(domain, "fluid_group", text="")
297
298         #col.label(text="Effector Group:")
299         #col.prop(domain, "effector_group", text="")
300
301         col = split.column()
302         col.label(text="Collision Group:")
303         col.prop(domain, "collision_group", text="")
304
305
306 class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
307     bl_label = "Smoke Cache"
308     bl_options = {'DEFAULT_CLOSED'}
309     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
310
311     @classmethod
312     def poll(cls, context):
313         md = context.smoke
314         view_render = context.scene.view_render
315         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
316
317     def draw(self, context):
318         layout = self.layout
319
320         domain = context.smoke.domain_settings
321         cache_file_format = domain.cache_file_format
322
323         layout.prop(domain, "cache_file_format")
324
325         if cache_file_format == 'POINTCACHE':
326             layout.label(text="Compression:")
327             layout.row().prop(domain, "point_cache_compress_type", expand=True)
328         elif cache_file_format == 'OPENVDB':
329             if not bpy.app.build_options.openvdb:
330                 layout.label("Built without OpenVDB support")
331                 return
332
333             layout.label(text="Compression:")
334             layout.row().prop(domain, "openvdb_cache_compress_type", expand=True)
335             row = layout.row()
336             row.label("Data Depth:")
337             row.prop(domain, "data_depth", expand=True, text="Data Depth")
338
339         cache = domain.point_cache
340         point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
341
342
343 class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
344     bl_label = "Smoke Field Weights"
345     bl_options = {'DEFAULT_CLOSED'}
346     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
347
348     @classmethod
349     def poll(cls, context):
350         md = context.smoke
351         view_render = context.scene.view_render
352         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
353
354     def draw(self, context):
355         domain = context.smoke.domain_settings
356         effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
357
358
359 class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
360     bl_label = "Smoke Display Settings"
361     bl_options = {'DEFAULT_CLOSED'}
362
363     @classmethod
364     def poll(cls, context):
365         md = context.smoke
366         view_render = context.scene.view_render
367         return md and (md.smoke_type == 'DOMAIN') and (not view_render.use_game_engine)
368
369     def draw(self, context):
370         domain = context.smoke.domain_settings
371         layout = self.layout
372
373         layout.prop(domain, "display_thickness")
374
375         layout.separator()
376         layout.label(text="Slicing:")
377         layout.prop(domain, "slice_method")
378
379         slice_method = domain.slice_method
380         axis_slice_method = domain.axis_slice_method
381
382         do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
383         do_full_slicing = (axis_slice_method == 'FULL')
384
385         row = layout.row()
386         row.enabled = do_axis_slicing
387         row.prop(domain, "axis_slice_method")
388
389         col = layout.column()
390         col.enabled = not do_full_slicing and do_axis_slicing
391         col.prop(domain, "slice_axis")
392         col.prop(domain, "slice_depth")
393
394         row = layout.row()
395         row.enabled = do_full_slicing or not do_axis_slicing
396         row.prop(domain, "slice_per_voxel")
397
398         layout.separator()
399         layout.label(text="Debug:")
400         layout.prop(domain, "draw_velocity")
401         col = layout.column()
402         col.enabled = domain.draw_velocity
403         col.prop(domain, "vector_draw_type")
404         col.prop(domain, "vector_scale")
405
406         layout.separator()
407         layout.label(text="Color Mapping:")
408         layout.prop(domain, "use_color_ramp")
409         col = layout.column()
410         col.enabled = domain.use_color_ramp
411         col.prop(domain, "coba_field")
412         col.template_color_ramp(domain, "color_ramp", expand=True)
413
414
415 classes = (
416     PHYSICS_PT_smoke,
417     PHYSICS_PT_smoke_flow_advanced,
418     PHYSICS_PT_smoke_fire,
419     PHYSICS_PT_smoke_adaptive_domain,
420     PHYSICS_PT_smoke_highres,
421     PHYSICS_PT_smoke_groups,
422     PHYSICS_PT_smoke_cache,
423     PHYSICS_PT_smoke_field_weights,
424     PHYSICS_PT_smoke_display_settings,
425 )
426
427 if __name__ == "__main__":  # only for live edit.
428     from bpy.utils import register_class
429     for cls in classes:
430         register_class(cls)