blender/release/scripts/startup/bl_ui/properties_render.py
Dalai Felinto d5f1b9c222 Multi-View and Stereo 3D
Official Documentation:
http://www.blender.org/manual/render/workflows/multiview.html

Implemented Features
====================
Builtin Stereo Camera
* Convergence Mode
* Interocular Distance
* Convergence Distance
* Pivot Mode

Viewport
* Cameras
* Plane
* Volume

Compositor
* View Switch Node
* Image Node Multi-View OpenEXR support

Sequencer
* Image/Movie Strips 'Use Multiview'

UV/Image Editor
* Option to see Multi-View images in Stereo-3D or its individual images
* Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images

I/O
* Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images

Scene Render Views
* Ability to have an arbitrary number of views in the scene

Missing Bits
============
First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report.

Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report.

Everything else is likely small todos, and may wait until we are sure none of the above is happening.

Apart from that there are those known issues:
* Compositor Image Node poorly working for Multi-View OpenEXR
(this was working prefectly before the 'Use Multi-View' functionality)
* Selecting camera from Multi-View when looking from camera is problematic
* Animation Playback (ctrl+F11) doesn't support stereo formats
* Wrong filepath when trying to play back animated scene
* Viewport Rendering doesn't support Multi-View
* Overscan Rendering
* Fullscreen display modes need to warn the user
* Object copy should be aware of views suffix

Acknowledgments
===============
* Francesco Siddi for the help with the original feature specs and design
* Brecht Van Lommel for the original review of the code and design early on
* Blender Foundation for the Development Fund to support the project wrap up

Final patch reviewers:
* Antony Riakiotakis (psy-fi)
* Campbell Barton (ideasman42)
* Julian Eisel (Severin)
* Sergey Sharybin (nazgul)
* Thomas Dinged (dingto)

Code contributors of the original branch in github:
* Alexey Akishin
* Gabriel Caraballo
2015-04-06 10:40:12 -03:00

571 lines
18 KiB
Python

# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel
class RENDER_MT_presets(Menu):
bl_label = "Render Presets"
preset_subdir = "render"
preset_operator = "script.execute_preset"
draw = Menu.draw_preset
class RENDER_MT_ffmpeg_presets(Menu):
bl_label = "FFMPEG Presets"
preset_subdir = "ffmpeg"
preset_operator = "script.python_file_run"
draw = Menu.draw_preset
class RENDER_MT_framerate_presets(Menu):
bl_label = "Frame Rate Presets"
preset_subdir = "framerate"
preset_operator = "script.execute_preset"
draw = Menu.draw_preset
class RenderButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "render"
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
@classmethod
def poll(cls, context):
scene = context.scene
return scene and (scene.render.engine in cls.COMPAT_ENGINES)
class RENDER_PT_render(RenderButtonsPanel, Panel):
bl_label = "Render"
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
row = layout.row(align=True)
row.operator("render.render", text="Render", icon='RENDER_STILL')
row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True
row.operator("sound.mixdown", text="Audio", icon='PLAY_AUDIO')
split = layout.split(percentage=0.33)
split.label(text="Display:")
row = split.row(align=True)
row.prop(rd, "display_mode", text="")
row.prop(rd, "use_lock_interface", icon_only=True)
class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
bl_label = "Dimensions"
COMPAT_ENGINES = {'BLENDER_RENDER'}
_frame_rate_args_prev = None
_preset_class = None
@staticmethod
def _draw_framerate_label(*args):
# avoids re-creating text string each draw
if RENDER_PT_dimensions._frame_rate_args_prev == args:
return RENDER_PT_dimensions._frame_rate_ret
fps, fps_base, preset_label = args
if fps_base == 1.0:
fps_rate = round(fps)
else:
fps_rate = round(fps / fps_base, 2)
# TODO: Change the following to iterate over existing presets
custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60})
if custom_framerate is True:
fps_label_text = "Custom (%r fps)" % fps_rate
show_framerate = True
else:
fps_label_text = "%r fps" % fps_rate
show_framerate = (preset_label == "Custom")
RENDER_PT_dimensions._frame_rate_args_prev = args
RENDER_PT_dimensions._frame_rate_ret = args = (fps_label_text, show_framerate)
return args
@staticmethod
def draw_framerate(sub, rd):
if RENDER_PT_dimensions._preset_class is None:
RENDER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets
args = rd.fps, rd.fps_base, RENDER_PT_dimensions._preset_class.bl_label
fps_label_text, show_framerate = RENDER_PT_dimensions._draw_framerate_label(*args)
sub.menu("RENDER_MT_framerate_presets", text=fps_label_text)
if show_framerate:
sub.prop(rd, "fps")
sub.prop(rd, "fps_base", text="/")
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
row = layout.row(align=True)
row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label)
row.operator("render.preset_add", text="", icon='ZOOMIN')
row.operator("render.preset_add", text="", icon='ZOOMOUT').remove_active = True
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.label(text="Resolution:")
sub.prop(rd, "resolution_x", text="X")
sub.prop(rd, "resolution_y", text="Y")
sub.prop(rd, "resolution_percentage", text="")
sub.label(text="Aspect Ratio:")
sub.prop(rd, "pixel_aspect_x", text="X")
sub.prop(rd, "pixel_aspect_y", text="Y")
row = col.row()
row.prop(rd, "use_border", text="Border")
sub = row.row()
sub.active = rd.use_border
sub.prop(rd, "use_crop_to_border", text="Crop")
col = split.column()
sub = col.column(align=True)
sub.label(text="Frame Range:")
sub.prop(scene, "frame_start")
sub.prop(scene, "frame_end")
sub.prop(scene, "frame_step")
sub.label(text="Frame Rate:")
self.draw_framerate(sub, rd)
subrow = sub.row(align=True)
subrow.label(text="Time Remapping:")
subrow = sub.row(align=True)
subrow.prop(rd, "frame_map_old", text="Old")
subrow.prop(rd, "frame_map_new", text="New")
class RENDER_PT_antialiasing(RenderButtonsPanel, Panel):
bl_label = "Anti-Aliasing"
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_antialiasing", text="")
def draw(self, context):
layout = self.layout
rd = context.scene.render
layout.active = rd.use_antialiasing
split = layout.split()
col = split.column()
col.row().prop(rd, "antialiasing_samples", expand=True)
sub = col.row()
sub.enabled = not rd.use_border
sub.prop(rd, "use_full_sample")
col = split.column()
col.prop(rd, "pixel_filter_type", text="")
col.prop(rd, "filter_size", text="Size")
class RENDER_PT_motion_blur(RenderButtonsPanel, Panel):
bl_label = "Sampled Motion Blur"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
rd = context.scene.render
return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES)
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_motion_blur", text="")
def draw(self, context):
layout = self.layout
rd = context.scene.render
layout.active = rd.use_motion_blur
row = layout.row()
row.prop(rd, "motion_blur_samples")
row.prop(rd, "motion_blur_shutter")
class RENDER_PT_shading(RenderButtonsPanel, Panel):
bl_label = "Shading"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
split = layout.split()
col = split.column()
col.prop(rd, "use_textures", text="Textures")
col.prop(rd, "use_shadows", text="Shadows")
col.prop(rd, "use_sss", text="Subsurface Scattering")
col.prop(rd, "use_envmaps", text="Environment Map")
col = split.column()
col.prop(rd, "use_raytrace", text="Ray Tracing")
col.prop(rd, "alpha_mode", text="Alpha")
class RENDER_PT_performance(RenderButtonsPanel, Panel):
bl_label = "Performance"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
split = layout.split()
col = split.column(align=True)
col.label(text="Threads:")
col.row(align=True).prop(rd, "threads_mode", expand=True)
sub = col.column(align=True)
sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
col.label(text="Tile Size:")
col.prop(rd, "tile_x", text="X")
col.prop(rd, "tile_y", text="Y")
col.separator()
col.prop(rd, 'preview_start_resolution')
col = split.column()
col.label(text="Memory:")
sub = col.column()
sub.enabled = not (rd.use_border or rd.use_full_sample)
sub.prop(rd, "use_save_buffers")
sub = col.column()
sub.active = rd.use_compositing
sub.prop(rd, "use_free_image_textures")
sub.prop(rd, "use_free_unused_nodes")
sub = col.column()
sub.active = rd.use_raytrace
sub.label(text="Acceleration structure:")
sub.prop(rd, "raytrace_method", text="")
if rd.raytrace_method == 'OCTREE':
sub.prop(rd, "octree_resolution", text="Resolution")
else:
sub.prop(rd, "use_instances", text="Instances")
sub.prop(rd, "use_local_coords", text="Local Coordinates")
class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
split = layout.split()
col = split.column()
col.prop(rd, "use_compositing")
col.prop(rd, "use_sequencer")
split.prop(rd, "dither_intensity", text="Dither", slider=True)
layout.separator()
split = layout.split()
col = split.column()
col.prop(rd, "use_fields", text="Fields")
sub = col.column()
sub.active = rd.use_fields
sub.row().prop(rd, "field_order", expand=True)
sub.prop(rd, "use_fields_still", text="Still")
col = split.column()
col.prop(rd, "use_edge_enhance")
sub = col.column()
sub.active = rd.use_edge_enhance
sub.prop(rd, "edge_threshold", text="Threshold", slider=True)
sub.prop(rd, "edge_color", text="")
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
bl_label = "Stamp"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_stamp", text="")
def draw(self, context):
layout = self.layout
rd = context.scene.render
layout.active = rd.use_stamp
layout.prop(rd, "stamp_font_size", text="Font Size")
row = layout.row()
row.column().prop(rd, "stamp_foreground", slider=True)
row.column().prop(rd, "stamp_background", slider=True)
split = layout.split()
col = split.column()
col.prop(rd, "use_stamp_time", text="Time")
col.prop(rd, "use_stamp_date", text="Date")
col.prop(rd, "use_stamp_render_time", text="RenderTime")
col.prop(rd, "use_stamp_frame", text="Frame")
col.prop(rd, "use_stamp_scene", text="Scene")
col = split.column()
col.prop(rd, "use_stamp_camera", text="Camera")
col.prop(rd, "use_stamp_lens", text="Lens")
col.prop(rd, "use_stamp_filename", text="Filename")
col.prop(rd, "use_stamp_marker", text="Marker")
col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip")
row = layout.split(percentage=0.2)
row.prop(rd, "use_stamp_note", text="Note")
sub = row.row()
sub.active = rd.use_stamp_note
sub.prop(rd, "stamp_note_text", text="")
class RENDER_PT_output(RenderButtonsPanel, Panel):
bl_label = "Output"
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
image_settings = rd.image_settings
file_format = image_settings.file_format
layout.prop(rd, "filepath", text="")
split = layout.split()
col = split.column()
col.active = not rd.is_movie_format
col.prop(rd, "use_overwrite")
col.prop(rd, "use_placeholder")
col = split.column()
col.prop(rd, "use_file_extension")
col.prop(rd, "use_render_cache")
layout.template_image_settings(image_settings, color_management=False)
if rd.use_multiview:
layout.template_image_views(image_settings)
if file_format == 'QUICKTIME':
quicktime = rd.quicktime
split = layout.split()
col = split.column()
col.prop(quicktime, "codec_type", text="Video Codec")
col.prop(quicktime, "codec_spatial_quality", text="Quality")
# Audio
col.prop(quicktime, "audiocodec_type", text="Audio Codec")
if quicktime.audiocodec_type != 'No audio':
split = layout.split()
if quicktime.audiocodec_type == 'LPCM':
split.prop(quicktime, "audio_bitdepth", text="")
split.prop(quicktime, "audio_samplerate", text="")
split = layout.split()
col = split.column()
if quicktime.audiocodec_type == 'AAC':
col.prop(quicktime, "audio_bitrate")
subsplit = split.split()
col = subsplit.column()
if quicktime.audiocodec_type == 'AAC':
col.prop(quicktime, "audio_codec_isvbr")
col = subsplit.column()
col.prop(quicktime, "audio_resampling_hq")
class RENDER_PT_encoding(RenderButtonsPanel, Panel):
bl_label = "Encoding"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
rd = context.scene.render
return rd.image_settings.file_format in {'FFMPEG', 'XVID', 'H264', 'THEORA'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
ffmpeg = rd.ffmpeg
layout.menu("RENDER_MT_ffmpeg_presets", text="Presets")
split = layout.split()
split.prop(rd.ffmpeg, "format")
if ffmpeg.format in {'AVI', 'QUICKTIME', 'MKV', 'OGG'}:
split.prop(ffmpeg, "codec")
elif rd.ffmpeg.format == 'H264':
split.prop(ffmpeg, "use_lossless_output")
else:
split.label()
row = layout.row()
row.prop(ffmpeg, "video_bitrate")
row.prop(ffmpeg, "gopsize")
split = layout.split()
col = split.column()
col.label(text="Rate:")
col.prop(ffmpeg, "minrate", text="Minimum")
col.prop(ffmpeg, "maxrate", text="Maximum")
col.prop(ffmpeg, "buffersize", text="Buffer")
col = split.column()
col.prop(ffmpeg, "use_autosplit")
col.label(text="Mux:")
col.prop(ffmpeg, "muxrate", text="Rate")
col.prop(ffmpeg, "packetsize", text="Packet Size")
layout.separator()
# Audio:
if ffmpeg.format != 'MP3':
layout.prop(ffmpeg, "audio_codec", text="Audio Codec")
row = layout.row()
row.prop(ffmpeg, "audio_bitrate")
row.prop(ffmpeg, "audio_volume", slider=True)
class RENDER_PT_bake(RenderButtonsPanel, Panel):
bl_label = "Bake"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
layout.operator("object.bake_image", icon='RENDER_STILL')
layout.prop(rd, "bake_type")
multires_bake = False
if rd.bake_type in ['NORMALS', 'DISPLACEMENT', 'DERIVATIVE', 'AO']:
layout.prop(rd, "use_bake_multires")
multires_bake = rd.use_bake_multires
if not multires_bake:
if rd.bake_type == 'NORMALS':
layout.prop(rd, "bake_normal_space")
elif rd.bake_type in {'DISPLACEMENT', 'AO'}:
layout.prop(rd, "use_bake_normalize")
# col.prop(rd, "bake_aa_mode")
# col.prop(rd, "use_bake_antialiasing")
layout.separator()
split = layout.split()
col = split.column()
col.prop(rd, "use_bake_to_vertex_color")
sub = col.column()
sub.active = not rd.use_bake_to_vertex_color
sub.prop(rd, "use_bake_clear")
sub.prop(rd, "bake_margin")
sub.prop(rd, "bake_quad_split", text="Split")
col = split.column()
col.prop(rd, "use_bake_selected_to_active")
sub = col.column()
sub.active = rd.use_bake_selected_to_active
sub.prop(rd, "bake_distance")
sub.prop(rd, "bake_bias")
else:
split = layout.split()
col = split.column()
col.prop(rd, "use_bake_clear")
col.prop(rd, "bake_margin")
if rd.bake_type == 'DISPLACEMENT':
col = split.column()
col.prop(rd, "use_bake_lores_mesh")
if rd.bake_type == 'AO':
col = split.column()
col.prop(rd, "bake_bias")
col.prop(rd, "bake_samples")
if rd.bake_type == 'DERIVATIVE':
row = layout.row()
row.prop(rd, "use_bake_user_scale", text="")
sub = row.column()
sub.active = rd.use_bake_user_scale
sub.prop(rd, "bake_user_scale", text="User Scale")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)