Merge remote-tracking branch 'origin/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
72             col = split.column()
73             col.label(text="Behavior:")
74             col.prop(domain, "alpha")
75             col.prop(domain, "beta", text="Temp. Diff.")
76             col.prop(domain, "vorticity")
77             col.prop(domain, "use_dissolve_smoke", text="Dissolve")
78             sub = col.column()
79             sub.active = domain.use_dissolve_smoke
80             sub.prop(domain, "dissolve_speed", text="Time")
81             sub.prop(domain, "use_dissolve_smoke_log", text="Slow")
82
83         elif md.smoke_type == 'FLOW':
84
85             flow = md.flow_settings
86
87             layout.prop(flow, "smoke_flow_type", expand=False)
88
89             if flow.smoke_flow_type != 'OUTFLOW':
90                 split = layout.split()
91                 col = split.column()
92                 col.label(text="Flow Source:")
93                 col.prop(flow, "smoke_flow_source", expand=False, text="")
94                 if flow.smoke_flow_source == 'PARTICLES':
95                     col.label(text="Particle System:")
96                     col.prop_search(flow, "particle_system", ob, "particle_systems", text="")
97                     col.prop(flow, "use_particle_size", text="Set Size")
98                     sub = col.column()
99                     sub.active = flow.use_particle_size
100                     sub.prop(flow, "particle_size")
101                 else:
102                     col.prop(flow, "surface_distance")
103                     col.prop(flow, "volume_density")
104
105                 sub = col.column(align=True)
106                 sub.prop(flow, "use_initial_velocity")
107
108                 sub = sub.column()
109                 sub.active = flow.use_initial_velocity
110                 sub.prop(flow, "velocity_factor")
111                 if flow.smoke_flow_source == 'MESH':
112                     sub.prop(flow, "velocity_normal")
113                     #sub.prop(flow, "velocity_random")
114
115                 sub = split.column()
116                 sub.label(text="Initial Values:")
117                 sub.prop(flow, "use_absolute")
118                 if flow.smoke_flow_type in {'SMOKE', 'BOTH'}:
119                     sub.prop(flow, "density")
120                     sub.prop(flow, "temperature")
121                     sub.prop(flow, "smoke_color")
122                 if flow.smoke_flow_type in {'FIRE', 'BOTH'}:
123                     sub.prop(flow, "fuel_amount")
124                 sub.label(text="Sampling:")
125                 sub.prop(flow, "subframes")
126
127         elif md.smoke_type == 'COLLISION':
128             coll = md.coll_settings
129
130             split = layout.split()
131
132             col = split.column()
133             col.prop(coll, "collision_type")
134
135
136 class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel):
137     bl_label = "Smoke Flow Advanced"
138     bl_options = {'DEFAULT_CLOSED'}
139     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
140
141     @classmethod
142     def poll(cls, context):
143         md = context.smoke
144         return md and (md.smoke_type == 'FLOW') and (md.flow_settings.smoke_flow_source == 'MESH')
145
146     def draw(self, context):
147         layout = self.layout
148         ob = context.object
149         flow = context.smoke.flow_settings
150
151         split = layout.split()
152         col = split.column()
153
154         col.prop(flow, "use_texture")
155         sub = col.column()
156         sub.active = flow.use_texture
157         sub.prop(flow, "noise_texture", text="")
158         sub.label(text="Mapping:")
159         sub.prop(flow, "texture_map_type", expand=False, text="")
160         if flow.texture_map_type == 'UV':
161             sub.prop_search(flow, "uv_layer", ob.data, "uv_layers", text="")
162         if flow.texture_map_type == 'AUTO':
163             sub.prop(flow, "texture_size")
164         sub.prop(flow, "texture_offset")
165
166         col = split.column()
167         col.label(text="Vertex Group:")
168         col.prop_search(flow, "density_vertex_group", ob, "vertex_groups", text="")
169
170
171 class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel):
172     bl_label = "Smoke Flames"
173     bl_options = {'DEFAULT_CLOSED'}
174     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
175
176     @classmethod
177     def poll(cls, context):
178         md = context.smoke
179         return md and (md.smoke_type == 'DOMAIN')
180
181     def draw(self, context):
182         layout = self.layout
183         domain = context.smoke.domain_settings
184
185         split = layout.split()
186         split.enabled = not domain.point_cache.is_baked
187
188         col = split.column(align=True)
189         col.label(text="Reaction:")
190         col.prop(domain, "burning_rate")
191         col.prop(domain, "flame_smoke")
192         col.prop(domain, "flame_vorticity")
193
194         col = split.column(align=True)
195         col.label(text="Temperatures:")
196         col.prop(domain, "flame_ignition")
197         col.prop(domain, "flame_max_temp")
198         col.prop(domain, "flame_smoke_color")
199
200
201 class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
202     bl_label = "Smoke Adaptive Domain"
203     bl_options = {'DEFAULT_CLOSED'}
204     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
205
206     @classmethod
207     def poll(cls, context):
208         md = context.smoke
209         return md and (md.smoke_type == 'DOMAIN')
210
211     def draw_header(self, context):
212         md = context.smoke.domain_settings
213
214         self.layout.prop(md, "use_adaptive_domain", text="")
215
216     def draw(self, context):
217         layout = self.layout
218
219         domain = context.smoke.domain_settings
220         layout.active = domain.use_adaptive_domain
221
222         split = layout.split()
223         split.enabled = (not domain.point_cache.is_baked)
224
225         col = split.column(align=True)
226         col.label(text="Resolution:")
227         col.prop(domain, "additional_res")
228         col.prop(domain, "adapt_margin")
229
230         col = split.column(align=True)
231         col.label(text="Advanced:")
232         col.prop(domain, "adapt_threshold")
233
234
235 class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel):
236     bl_label = "Smoke High Resolution"
237     bl_options = {'DEFAULT_CLOSED'}
238     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
239
240     @classmethod
241     def poll(cls, context):
242         md = context.smoke
243         view_render = context.scene.view_render
244         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
245
246     def draw_header(self, context):
247         md = context.smoke.domain_settings
248
249         self.layout.prop(md, "use_high_resolution", text="")
250
251     def draw(self, context):
252         layout = self.layout
253
254         md = context.smoke.domain_settings
255
256         layout.active = md.use_high_resolution
257
258         split = layout.split()
259         split.enabled = not md.point_cache.is_baked
260
261         col = split.column()
262         col.label(text="Resolution:")
263         col.prop(md, "amplify", text="Divisions")
264         col.label(text="Flow Sampling:")
265         col.row().prop(md, "highres_sampling", text="")
266
267         col = split.column()
268         col.label(text="Noise Method:")
269         col.row().prop(md, "noise_type", text="")
270         col.prop(md, "strength")
271
272         layout.prop(md, "show_high_resolution")
273
274
275 class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel):
276     bl_label = "Smoke Groups"
277     bl_options = {'DEFAULT_CLOSED'}
278     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
279
280     @classmethod
281     def poll(cls, context):
282         md = context.smoke
283         view_render = context.scene.view_render
284         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
285
286     def draw(self, context):
287         layout = self.layout
288         domain = context.smoke.domain_settings
289
290         split = layout.split()
291
292         col = split.column()
293         col.label(text="Flow Group:")
294         col.prop(domain, "fluid_group", text="")
295
296         #col.label(text="Effector Group:")
297         #col.prop(domain, "effector_group", text="")
298
299         col = split.column()
300         col.label(text="Collision Group:")
301         col.prop(domain, "collision_group", text="")
302
303
304 class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
305     bl_label = "Smoke Cache"
306     bl_options = {'DEFAULT_CLOSED'}
307     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
308
309     @classmethod
310     def poll(cls, context):
311         md = context.smoke
312         view_render = context.scene.view_render
313         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
314
315     def draw(self, context):
316         layout = self.layout
317
318         domain = context.smoke.domain_settings
319         cache_file_format = domain.cache_file_format
320
321         layout.prop(domain, "cache_file_format")
322
323         if cache_file_format == 'POINTCACHE':
324             layout.label(text="Compression:")
325             layout.row().prop(domain, "point_cache_compress_type", expand=True)
326         elif cache_file_format == 'OPENVDB':
327             if not bpy.app.build_options.openvdb:
328                 layout.label("Built without OpenVDB support")
329                 return
330
331             layout.label(text="Compression:")
332             layout.row().prop(domain, "openvdb_cache_compress_type", expand=True)
333             row = layout.row()
334             row.label("Data Depth:")
335             row.prop(domain, "data_depth", expand=True, text="Data Depth")
336
337         cache = domain.point_cache
338         point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
339
340
341 class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
342     bl_label = "Smoke Field Weights"
343     bl_options = {'DEFAULT_CLOSED'}
344     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
345
346     @classmethod
347     def poll(cls, context):
348         md = context.smoke
349         view_render = context.scene.view_render
350         return md and (md.smoke_type == 'DOMAIN') and (view_render.engine in cls.COMPAT_ENGINES)
351
352     def draw(self, context):
353         domain = context.smoke.domain_settings
354         effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
355
356
357 class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel):
358     bl_label = "Smoke Display Settings"
359     bl_options = {'DEFAULT_CLOSED'}
360
361     @classmethod
362     def poll(cls, context):
363         md = context.smoke
364         view_render = context.scene.view_render
365         return md and (md.smoke_type == 'DOMAIN') and (not view_render.use_game_engine)
366
367     def draw(self, context):
368         domain = context.smoke.domain_settings
369         layout = self.layout
370
371         layout.prop(domain, "display_thickness")
372
373         layout.separator()
374         layout.label(text="Slicing:")
375         layout.prop(domain, "slice_method")
376
377         slice_method = domain.slice_method
378         axis_slice_method = domain.axis_slice_method
379
380         do_axis_slicing = (slice_method == 'AXIS_ALIGNED')
381         do_full_slicing = (axis_slice_method == 'FULL')
382
383         row = layout.row()
384         row.enabled = do_axis_slicing
385         row.prop(domain, "axis_slice_method")
386
387         col = layout.column()
388         col.enabled = not do_full_slicing and do_axis_slicing
389         col.prop(domain, "slice_axis")
390         col.prop(domain, "slice_depth")
391
392         row = layout.row()
393         row.enabled = do_full_slicing or not do_axis_slicing
394         row.prop(domain, "slice_per_voxel")
395
396         layout.separator()
397         layout.label(text="Debug:")
398         layout.prop(domain, "draw_velocity")
399         col = layout.column()
400         col.enabled = domain.draw_velocity
401         col.prop(domain, "vector_draw_type")
402         col.prop(domain, "vector_scale")
403
404         layout.separator()
405         layout.label(text="Color Mapping:")
406         layout.prop(domain, "use_color_ramp")
407         col = layout.column()
408         col.enabled = domain.use_color_ramp
409         col.prop(domain, "coba_field")
410         col.template_color_ramp(domain, "color_ramp", expand=True)
411
412
413 classes = (
414     PHYSICS_PT_smoke,
415     PHYSICS_PT_smoke_flow_advanced,
416     PHYSICS_PT_smoke_fire,
417     PHYSICS_PT_smoke_adaptive_domain,
418     PHYSICS_PT_smoke_highres,
419     PHYSICS_PT_smoke_groups,
420     PHYSICS_PT_smoke_cache,
421     PHYSICS_PT_smoke_field_weights,
422     PHYSICS_PT_smoke_display_settings,
423 )
424
425 if __name__ == "__main__":  # only for live edit.
426     from bpy.utils import register_class
427     for cls in classes:
428         register_class(cls)