e11f179e2cb20dd69934b6cd53b5a15cda8c5c35
[blender.git] / release / scripts / startup / bl_ui / properties_render.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2
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 # ##### END GPL LICENSE BLOCK #####
19
20 # <pep8 compliant>
21 import bpy
22 from bpy.types import Menu, Panel
23
24
25 class RENDER_MT_presets(Menu):
26     bl_label = "Render Presets"
27     preset_subdir = "render"
28     preset_operator = "script.execute_preset"
29     draw = Menu.draw_preset
30
31
32 class RENDER_MT_ffmpeg_presets(Menu):
33     bl_label = "FFMPEG Presets"
34     preset_subdir = "ffmpeg"
35     preset_operator = "script.python_file_run"
36     draw = Menu.draw_preset
37
38
39 class RENDER_MT_framerate_presets(Menu):
40     bl_label = "Frame Rate Presets"
41     preset_subdir = "framerate"
42     preset_operator = "script.execute_preset"
43     draw = Menu.draw_preset
44
45
46 class RenderButtonsPanel():
47     bl_space_type = 'PROPERTIES'
48     bl_region_type = 'WINDOW'
49     bl_context = "render"
50     # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
51
52     @classmethod
53     def poll(cls, context):
54         scene = context.scene
55         return scene and (scene.render.engine in cls.COMPAT_ENGINES)
56
57
58 class RENDER_PT_render(RenderButtonsPanel, Panel):
59     bl_label = "Render"
60     COMPAT_ENGINES = {'BLENDER_RENDER'}
61
62     def draw(self, context):
63         layout = self.layout
64
65         rd = context.scene.render
66
67         row = layout.row(align=True)
68         row.operator("render.render", text="Render", icon='RENDER_STILL')
69         row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True
70         row.operator("render.play_rendered_anim", text="Play", icon='PLAY')
71
72         layout.prop(rd, "display_mode", text="Display")
73
74
75 class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
76     bl_label = "Dimensions"
77     COMPAT_ENGINES = {'BLENDER_RENDER'}
78
79     _frame_rate_args_prev = None
80     _preset_class = None
81
82     @staticmethod
83     def _draw_framerate_label(*args):
84         # avoids re-creating text string each draw
85         if RENDER_PT_dimensions._frame_rate_args_prev == args:
86             return RENDER_PT_dimensions._frame_rate_ret
87
88         fps, fps_base, preset_label = args
89
90         if fps_base == 1.0:
91             fps_rate = round(fps)
92         else:
93             fps_rate = round(fps / fps_base, 2)
94
95         # TODO: Change the following to iterate over existing presets
96         custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60})
97
98         if custom_framerate is True:
99             fps_label_text = "Custom (%r fps)" % fps_rate
100             show_framerate = True
101         else:
102             fps_label_text = "%r fps" % fps_rate
103             show_framerate = (preset_label == "Custom")
104
105         RENDER_PT_dimensions._frame_rate_args_prev = args
106         RENDER_PT_dimensions._frame_rate_ret = args = (fps_label_text, show_framerate)
107         return args
108
109     @staticmethod
110     def draw_framerate(sub, rd):
111         if RENDER_PT_dimensions._preset_class is None:
112             RENDER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets
113
114         args = rd.fps, rd.fps_base, RENDER_PT_dimensions._preset_class.bl_label
115         fps_label_text, show_framerate = RENDER_PT_dimensions._draw_framerate_label(*args)
116
117         sub.menu("RENDER_MT_framerate_presets", text=fps_label_text)
118
119         if show_framerate:
120             sub.prop(rd, "fps")
121             sub.prop(rd, "fps_base", text="/")
122
123     def draw(self, context):
124         layout = self.layout
125
126         scene = context.scene
127         rd = scene.render
128
129         row = layout.row(align=True)
130         row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label)
131         row.operator("render.preset_add", text="", icon='ZOOMIN')
132         row.operator("render.preset_add", text="", icon='ZOOMOUT').remove_active = True
133
134         split = layout.split()
135
136         col = split.column()
137         sub = col.column(align=True)
138         sub.label(text="Resolution:")
139         sub.prop(rd, "resolution_x", text="X")
140         sub.prop(rd, "resolution_y", text="Y")
141         sub.prop(rd, "resolution_percentage", text="")
142
143         sub.label(text="Aspect Ratio:")
144         sub.prop(rd, "pixel_aspect_x", text="X")
145         sub.prop(rd, "pixel_aspect_y", text="Y")
146
147         row = col.row()
148         row.prop(rd, "use_border", text="Border")
149         sub = row.row()
150         sub.active = rd.use_border
151         sub.prop(rd, "use_crop_to_border", text="Crop")
152
153         col = split.column()
154         sub = col.column(align=True)
155         sub.label(text="Frame Range:")
156         sub.prop(scene, "frame_start")
157         sub.prop(scene, "frame_end")
158         sub.prop(scene, "frame_step")
159
160         sub.label(text="Frame Rate:")
161
162         self.draw_framerate(sub, rd)
163
164         subrow = sub.row(align=True)
165         subrow.label(text="Time Remapping:")
166         subrow = sub.row(align=True)
167         subrow.prop(rd, "frame_map_old", text="Old")
168         subrow.prop(rd, "frame_map_new", text="New")
169
170
171 class RENDER_PT_antialiasing(RenderButtonsPanel, Panel):
172     bl_label = "Anti-Aliasing"
173     COMPAT_ENGINES = {'BLENDER_RENDER'}
174
175     def draw_header(self, context):
176         rd = context.scene.render
177
178         self.layout.prop(rd, "use_antialiasing", text="")
179
180     def draw(self, context):
181         layout = self.layout
182
183         rd = context.scene.render
184         layout.active = rd.use_antialiasing
185
186         split = layout.split()
187
188         col = split.column()
189         col.row().prop(rd, "antialiasing_samples", expand=True)
190         sub = col.row()
191         sub.enabled = not rd.use_border
192         sub.prop(rd, "use_full_sample")
193
194         col = split.column()
195         col.prop(rd, "pixel_filter_type", text="")
196         col.prop(rd, "filter_size", text="Size")
197
198
199 class RENDER_PT_motion_blur(RenderButtonsPanel, Panel):
200     bl_label = "Sampled Motion Blur"
201     bl_options = {'DEFAULT_CLOSED'}
202     COMPAT_ENGINES = {'BLENDER_RENDER'}
203
204     @classmethod
205     def poll(cls, context):
206         rd = context.scene.render
207         return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES)
208
209     def draw_header(self, context):
210         rd = context.scene.render
211
212         self.layout.prop(rd, "use_motion_blur", text="")
213
214     def draw(self, context):
215         layout = self.layout
216
217         rd = context.scene.render
218         layout.active = rd.use_motion_blur
219
220         row = layout.row()
221         row.prop(rd, "motion_blur_samples")
222         row.prop(rd, "motion_blur_shutter")
223
224
225 class RENDER_PT_shading(RenderButtonsPanel, Panel):
226     bl_label = "Shading"
227     bl_options = {'DEFAULT_CLOSED'}
228     COMPAT_ENGINES = {'BLENDER_RENDER'}
229
230     def draw(self, context):
231         layout = self.layout
232
233         rd = context.scene.render
234
235         split = layout.split()
236
237         col = split.column()
238         col.prop(rd, "use_textures", text="Textures")
239         col.prop(rd, "use_shadows", text="Shadows")
240         col.prop(rd, "use_sss", text="Subsurface Scattering")
241         col.prop(rd, "use_envmaps", text="Environment Map")
242
243         col = split.column()
244         col.prop(rd, "use_raytrace", text="Ray Tracing")
245         col.prop(rd, "alpha_mode", text="Alpha")
246
247
248 class RENDER_PT_performance(RenderButtonsPanel, Panel):
249     bl_label = "Performance"
250     bl_options = {'DEFAULT_CLOSED'}
251     COMPAT_ENGINES = {'BLENDER_RENDER'}
252
253     def draw(self, context):
254         layout = self.layout
255
256         rd = context.scene.render
257
258         split = layout.split()
259
260         col = split.column(align=True)
261         col.label(text="Threads:")
262         col.row(align=True).prop(rd, "threads_mode", expand=True)
263         sub = col.column(align=True)
264         sub.enabled = rd.threads_mode == 'FIXED'
265         sub.prop(rd, "threads")
266
267         col.label(text="Tile Size:")
268         col.prop(rd, "tile_x", text="X")
269         col.prop(rd, "tile_y", text="Y")
270
271         col = split.column()
272         col.label(text="Memory:")
273         sub = col.column()
274         sub.enabled = not (rd.use_border or rd.use_full_sample)
275         sub.prop(rd, "use_save_buffers")
276         sub = col.column()
277         sub.active = rd.use_compositing
278         sub.prop(rd, "use_free_image_textures")
279         sub.prop(rd, "use_free_unused_nodes")
280         sub = col.column()
281         sub.active = rd.use_raytrace
282         sub.label(text="Acceleration structure:")
283         sub.prop(rd, "raytrace_method", text="")
284         if rd.raytrace_method == 'OCTREE':
285             sub.prop(rd, "octree_resolution", text="Resolution")
286         else:
287             sub.prop(rd, "use_instances", text="Instances")
288         sub.prop(rd, "use_local_coords", text="Local Coordinates")
289
290
291 class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
292     bl_label = "Post Processing"
293     bl_options = {'DEFAULT_CLOSED'}
294     COMPAT_ENGINES = {'BLENDER_RENDER'}
295
296     def draw(self, context):
297         layout = self.layout
298
299         rd = context.scene.render
300
301         split = layout.split()
302
303         col = split.column()
304         col.prop(rd, "use_compositing")
305         col.prop(rd, "use_sequencer")
306
307         split.prop(rd, "dither_intensity", text="Dither", slider=True)
308
309         layout.separator()
310
311         split = layout.split()
312
313         col = split.column()
314         col.prop(rd, "use_fields", text="Fields")
315         sub = col.column()
316         sub.active = rd.use_fields
317         sub.row().prop(rd, "field_order", expand=True)
318         sub.prop(rd, "use_fields_still", text="Still")
319
320         col = split.column()
321         col.prop(rd, "use_edge_enhance")
322         sub = col.column()
323         sub.active = rd.use_edge_enhance
324         sub.prop(rd, "edge_threshold", text="Threshold", slider=True)
325         sub.prop(rd, "edge_color", text="")
326
327
328 class RENDER_PT_stamp(RenderButtonsPanel, Panel):
329     bl_label = "Stamp"
330     bl_options = {'DEFAULT_CLOSED'}
331     COMPAT_ENGINES = {'BLENDER_RENDER'}
332
333     def draw_header(self, context):
334         rd = context.scene.render
335
336         self.layout.prop(rd, "use_stamp", text="")
337
338     def draw(self, context):
339         layout = self.layout
340
341         rd = context.scene.render
342
343         layout.active = rd.use_stamp
344
345         layout.prop(rd, "stamp_font_size", text="Font Size")
346
347         row = layout.row()
348         row.column().prop(rd, "stamp_foreground", slider=True)
349         row.column().prop(rd, "stamp_background", slider=True)
350
351         split = layout.split()
352
353         col = split.column()
354         col.prop(rd, "use_stamp_time", text="Time")
355         col.prop(rd, "use_stamp_date", text="Date")
356         col.prop(rd, "use_stamp_render_time", text="RenderTime")
357         col.prop(rd, "use_stamp_frame", text="Frame")
358         col.prop(rd, "use_stamp_scene", text="Scene")
359
360         col = split.column()
361         col.prop(rd, "use_stamp_camera", text="Camera")
362         col.prop(rd, "use_stamp_lens", text="Lens")
363         col.prop(rd, "use_stamp_filename", text="Filename")
364         col.prop(rd, "use_stamp_marker", text="Marker")
365         col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip")
366
367         row = layout.split(percentage=0.2)
368         row.prop(rd, "use_stamp_note", text="Note")
369         sub = row.row()
370         sub.active = rd.use_stamp_note
371         sub.prop(rd, "stamp_note_text", text="")
372
373
374 class RENDER_PT_output(RenderButtonsPanel, Panel):
375     bl_label = "Output"
376     COMPAT_ENGINES = {'BLENDER_RENDER'}
377
378     def draw(self, context):
379         layout = self.layout
380
381         rd = context.scene.render
382         image_settings = rd.image_settings
383         file_format = image_settings.file_format
384
385         layout.prop(rd, "filepath", text="")
386
387         split = layout.split()
388
389         col = split.column()
390         col.active = not rd.is_movie_format
391         col.prop(rd, "use_overwrite")
392         col.prop(rd, "use_placeholder")
393
394         split.prop(rd, "use_file_extension")
395
396         layout.template_image_settings(image_settings, color_management=False)
397
398         if file_format == 'QUICKTIME_CARBON':
399             layout.operator("scene.render_data_set_quicktime_codec")
400
401         elif file_format == 'QUICKTIME_QTKIT':
402             quicktime = rd.quicktime
403
404             split = layout.split()
405             col = split.column()
406             col.prop(quicktime, "codec_type", text="Video Codec")
407             col.prop(quicktime, "codec_spatial_quality", text="Quality")
408
409             # Audio
410             col.prop(quicktime, "audiocodec_type", text="Audio Codec")
411             if quicktime.audiocodec_type != 'No audio':
412                 split = layout.split()
413                 if quicktime.audiocodec_type == 'LPCM':
414                     split.prop(quicktime, "audio_bitdepth", text="")
415
416                 split.prop(quicktime, "audio_samplerate", text="")
417
418                 split = layout.split()
419                 col = split.column()
420                 if quicktime.audiocodec_type == 'AAC':
421                     col.prop(quicktime, "audio_bitrate")
422
423                 subsplit = split.split()
424                 col = subsplit.column()
425
426                 if quicktime.audiocodec_type == 'AAC':
427                     col.prop(quicktime, "audio_codec_isvbr")
428
429                 col = subsplit.column()
430                 col.prop(quicktime, "audio_resampling_hq")
431
432
433 class RENDER_PT_encoding(RenderButtonsPanel, Panel):
434     bl_label = "Encoding"
435     bl_options = {'DEFAULT_CLOSED'}
436     COMPAT_ENGINES = {'BLENDER_RENDER'}
437
438     @classmethod
439     def poll(cls, context):
440         rd = context.scene.render
441         return rd.image_settings.file_format in {'FFMPEG', 'XVID', 'H264', 'THEORA'}
442
443     def draw(self, context):
444         layout = self.layout
445
446         rd = context.scene.render
447         ffmpeg = rd.ffmpeg
448
449         layout.menu("RENDER_MT_ffmpeg_presets", text="Presets")
450
451         split = layout.split()
452         split.prop(rd.ffmpeg, "format")
453         if ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG'}:
454             split.prop(ffmpeg, "codec")
455         elif rd.ffmpeg.format == 'H264':
456             split.prop(ffmpeg, "use_lossless_output")
457         else:
458             split.label()
459
460         row = layout.row()
461         row.prop(ffmpeg, "video_bitrate")
462         row.prop(ffmpeg, "gopsize")
463
464         split = layout.split()
465
466         col = split.column()
467         col.label(text="Rate:")
468         col.prop(ffmpeg, "minrate", text="Minimum")
469         col.prop(ffmpeg, "maxrate", text="Maximum")
470         col.prop(ffmpeg, "buffersize", text="Buffer")
471
472         col = split.column()
473         col.prop(ffmpeg, "use_autosplit")
474         col.label(text="Mux:")
475         col.prop(ffmpeg, "muxrate", text="Rate")
476         col.prop(ffmpeg, "packetsize", text="Packet Size")
477
478         layout.separator()
479
480         # Audio:
481         if ffmpeg.format != 'MP3':
482             layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
483
484         row = layout.row()
485         row.prop(ffmpeg, "audio_bitrate")
486         row.prop(ffmpeg, "audio_volume", slider=True)
487
488
489 class RENDER_PT_bake(RenderButtonsPanel, Panel):
490     bl_label = "Bake"
491     bl_options = {'DEFAULT_CLOSED'}
492     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
493
494     def draw(self, context):
495         layout = self.layout
496
497         rd = context.scene.render
498
499         layout.operator("object.bake_image", icon='RENDER_STILL')
500
501         layout.prop(rd, "bake_type")
502
503         multires_bake = False
504         if rd.bake_type in ['NORMALS', 'DISPLACEMENT', 'AO']:
505             layout.prop(rd, "use_bake_multires")
506             multires_bake = rd.use_bake_multires
507
508         if not multires_bake:
509             if rd.bake_type == 'NORMALS':
510                 layout.prop(rd, "bake_normal_space")
511             elif rd.bake_type in {'DISPLACEMENT', 'AO'}:
512                 layout.prop(rd, "use_bake_normalize")
513
514             # col.prop(rd, "bake_aa_mode")
515             # col.prop(rd, "use_bake_antialiasing")
516
517             layout.separator()
518
519             split = layout.split()
520
521             col = split.column()
522             col.prop(rd, "use_bake_to_vertex_color")
523             sub = col.column()
524             sub.active = not rd.use_bake_to_vertex_color
525             sub.prop(rd, "use_bake_clear")
526             sub.prop(rd, "bake_margin")
527             sub.prop(rd, "bake_quad_split", text="Split")
528
529             col = split.column()
530             col.prop(rd, "use_bake_selected_to_active")
531             sub = col.column()
532             sub.active = rd.use_bake_selected_to_active
533             sub.prop(rd, "bake_distance")
534             sub.prop(rd, "bake_bias")
535         else:
536             split = layout.split()
537
538             col = split.column()
539             col.prop(rd, "use_bake_clear")
540             col.prop(rd, "bake_margin")
541
542             if rd.bake_type == 'DISPLACEMENT':
543                 col = split.column()
544                 col.prop(rd, "use_bake_lores_mesh")
545             if rd.bake_type == 'AO':
546                 col = split.column()
547                 col.prop(rd, "bake_bias")
548                 col.prop(rd, "bake_samples")
549
550
551 if __name__ == "__main__":  # only for live edit.
552     bpy.utils.register_module(__name__)