diff options
Diffstat (limited to 'intern/cycles/blender/addon')
-rw-r--r-- | intern/cycles/blender/addon/__init__.py | 19 | ||||
-rw-r--r-- | intern/cycles/blender/addon/engine.py | 59 | ||||
-rw-r--r-- | intern/cycles/blender/addon/osl.py | 2 | ||||
-rw-r--r-- | intern/cycles/blender/addon/presets.py | 2 | ||||
-rw-r--r-- | intern/cycles/blender/addon/properties.py | 112 | ||||
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 237 | ||||
-rw-r--r-- | intern/cycles/blender/addon/version_update.py | 85 |
7 files changed, 445 insertions, 71 deletions
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 415f6e81be8..7a9caa7b06b 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> @@ -49,26 +49,23 @@ class CyclesRender(bpy.types.RenderEngine): # final render def update(self, data, scene): - if self.is_preview: - if not self.session: + if not self.session: + if self.is_preview: cscene = bpy.context.scene.cycles use_osl = cscene.shading_system and cscene.device == 'CPU' engine.create(self, data, scene, None, None, None, use_osl) - else: - if not self.session: - engine.create(self, data, scene) else: - engine.reset(self, data, scene) - - engine.update(self, data, scene) + engine.create(self, data, scene) + else: + engine.reset(self, data, scene) def render(self, scene): engine.render(self) - def bake(self, scene, obj, pass_type, pixel_array, num_pixels, depth, result): - engine.bake(self, obj, pass_type, pixel_array, num_pixels, depth, result) + def bake(self, scene, obj, pass_type, object_id, pixel_array, num_pixels, depth, result): + engine.bake(self, obj, pass_type, object_id, pixel_array, num_pixels, depth, result) # viewport render def view_update(self, context): diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 18235eca790..030f0dbbf14 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -11,21 +11,67 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> +def _is_using_buggy_driver(): + import bgl + # We need to be conservative here because in multi-GPU systems display card + # might be quite old, but others one might be just good. + # + # So We shouldn't disable possible good dedicated cards just because display + # card seems weak. And instead we only blacklist configurations which are + # proven to cause problems. + if bgl.glGetString(bgl.GL_VENDOR) == "ATI Technologies Inc.": + import re + version = bgl.glGetString(bgl.GL_VERSION) + if version.endswith("Compatibility Profile Context"): + # Old HD 4xxx and 5xxx series drivers did not have driver version + # in the version string, but those cards do not quite work and + # causing crashes. + return True + regex = re.compile(".*Compatibility Profile Context ([0-9]+(\.[0-9]+)+)$") + if not regex.match(version): + # Skip cards like FireGL + return False + version = regex.sub("\\1", version).split('.') + return int(version[0]) == 8 + return False + + +def _workaround_buggy_drivers(): + if _is_using_buggy_driver(): + import _cycles + if hasattr(_cycles, "opencl_disable"): + print("Cycles: OpenGL driver known to be buggy, disabling OpenCL platform.") + _cycles.opencl_disable() + + def init(): import bpy import _cycles import os.path + # Workaround possibly buggy legacy drivers which crashes on the OpenCL + # device enumeration. + # + # This checks are not really correct because they might still fail + # in the case of multiple GPUs. However, currently buggy drivers + # are really old and likely to be used in single GPU systems only + # anyway. + # + # Can't do it in the background mode, so we hope OpenCL is no enabled + # in the user preferences. + if not bpy.app.background: + _workaround_buggy_drivers() + path = os.path.dirname(__file__) user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', ''))) - _cycles.init(path, user_path) + _cycles.init(path, user_path, bpy.app.background) def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False): @@ -59,11 +105,11 @@ def render(engine): _cycles.render(engine.session) -def bake(engine, obj, pass_type, pixel_array, num_pixels, depth, result): +def bake(engine, obj, pass_type, object_id, pixel_array, num_pixels, depth, result): import _cycles session = getattr(engine, "session", None) if session is not None: - _cycles.bake(engine.session, obj.as_pointer(), pass_type, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer()) + _cycles.bake(engine.session, obj.as_pointer(), pass_type, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer()) def reset(engine, data, scene): @@ -100,3 +146,8 @@ def with_osl(): def with_network(): import _cycles return _cycles.with_network + + +def system_info(): + import _cycles + return _cycles.system_info() diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py index c5f9d93013e..f4aaaab5eab 100644 --- a/intern/cycles/blender/addon/osl.py +++ b/intern/cycles/blender/addon/osl.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py index 2ec65d7183a..f97b51b629d 100644 --- a/intern/cycles/blender/addon/presets.py +++ b/intern/cycles/blender/addon/presets.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 12c1cd820be..c130594dbf7 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> @@ -59,7 +59,7 @@ enum_filter_types = ( enum_aperture_types = ( ('RADIUS', "Radius", "Directly change the size of the aperture"), - ('FSTOP', "F/stop", "Change the size of the aperture by f/stops"), + ('FSTOP', "F-stop", "Change the size of the aperture by f-stop"), ) enum_panorama_types = ( @@ -67,6 +67,7 @@ enum_panorama_types = ( ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"), ('FISHEYE_EQUISOLID', "Fisheye Equisolid", "Similar to most fisheye modern lens, takes sensor dimensions into consideration"), + ('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"), ) enum_curve_primitives = ( @@ -115,6 +116,11 @@ enum_volume_sampling = ( ('MULTIPLE_IMPORTANCE', "Multiple Importance", "Combine distance and equi-angular sampling for volumes where neither method is ideal"), ) +enum_volume_interpolation = ( + ('LINEAR', "Linear", "Good smoothness and speed"), + ('CUBIC', "Cubic", "Smoothed high quality interpolation, but slower") + ) + class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod @@ -346,7 +352,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Distance between volume shader samples when rendering the volume " "(lower values give more accurate and detailed results, but also increased render time)", default=0.1, - min=0.0000001, max=100000.0 + min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0 ) cls.volume_max_steps = IntProperty( @@ -389,6 +395,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=0, ) + cls.use_animated_seed = BoolProperty( + name="Use Animated Seed", + description="Use different seed values (and hence noise patterns) at different frames", + default=False, + ) + cls.sample_clamp_direct = FloatProperty( name="Clamp Direct", description="If non-zero, the maximum value for a direct sample, " @@ -452,11 +464,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Use BVH spatial splits: longer builder time, faster render", default=False, ) - cls.use_cache = BoolProperty( - name="Cache BVH", - description="Cache last built BVH to disk for faster re-render if no geometry changed", - default=False, - ) cls.tile_order = EnumProperty( name="Tile Order", description="Tile order for rendering", @@ -477,7 +484,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): name="Bake Type", default='COMBINED', description="Type of pass to bake", - items = ( + items=( ('COMBINED', "Combined", ""), ('AO', "Ambient Occlusion", ""), ('SHADOW', "Shadow", ""), @@ -500,6 +507,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): ), ) + cls.use_camera_cull = BoolProperty( + name="Use Camera Cull", + description="Allow objects to be culled based on the camera frustum", + default=False, + ) + + cls.camera_cull_margin = FloatProperty( + name="Camera Cull Margin", + description="Margin for the camera space culling", + default=0.1, + min=0.0, max=5.0 + ) + @classmethod def unregister(cls): del bpy.types.Scene.cycles @@ -518,13 +538,13 @@ class CyclesCameraSettings(bpy.types.PropertyGroup): cls.aperture_type = EnumProperty( name="Aperture Type", - description="Use F/stop number or aperture radius", + description="Use f-stop number or aperture radius", items=enum_aperture_types, default='RADIUS', ) cls.aperture_fstop = FloatProperty( - name="Aperture F/stop", - description="F/stop ratio (lower numbers give more defocus, higher numbers give a sharper image)", + name="Aperture f-stop", + description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)", min=0.0, soft_min=0.1, soft_max=64.0, default=5.6, step=10, @@ -578,6 +598,34 @@ class CyclesCameraSettings(bpy.types.PropertyGroup): min=0.01, soft_max=15.0, max=100.0, default=10.5, ) + cls.latitude_min = FloatProperty( + name="Min Latitude", + description="Minimum latitude (vertical angle) for the equirectangular lens", + min=-0.5 * math.pi, max=0.5 * math.pi, + subtype='ANGLE', + default=-0.5 * math.pi, + ) + cls.latitude_max = FloatProperty( + name="Max Latitude", + description="Maximum latitude (vertical angle) for the equirectangular lens", + min=-0.5 * math.pi, max=0.5 * math.pi, + subtype='ANGLE', + default=0.5 * math.pi, + ) + cls.longitude_min = FloatProperty( + name="Min Longitude", + description="Minimum longitude (horizontal angle) for the equirectangular lens", + min=-math.pi, max=math.pi, + subtype='ANGLE', + default=-math.pi, + ) + cls.longitude_max = FloatProperty( + name="Max Longitude", + description="Maximum longitude (horizontal angle) for the equirectangular lens", + min=-math.pi, max=math.pi, + subtype='ANGLE', + default=math.pi, + ) cls.nodes = StringProperty( name="nodes", description="Camera ray nodes") @@ -621,6 +669,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup): default='DISTANCE', ) + cls.volume_interpolation = EnumProperty( + name="Volume Interpolation", + description="Interpolation method to use for smoke/fire volumes", + items=enum_volume_interpolation, + default='LINEAR', + ) + @classmethod def unregister(cls): del bpy.types.Material.cycles @@ -645,12 +700,24 @@ class CyclesLampSettings(bpy.types.PropertyGroup): min=1, max=10000, default=1, ) + cls.max_bounces = IntProperty( + name="Max Bounces", + description="Maximum number of bounces the light will contribute to the render", + min=0, max=1024, + default=1024, + ) cls.use_multiple_importance_sampling = BoolProperty( name="Multiple Importance Sample", description="Use multiple importance sampling for the lamp, " "reduces noise for area lamps and sharp glossy materials", default=False, ) + cls.is_portal = BoolProperty( + name="Is Portal", + description="Use this area lamp to guide sampling of the background, " + "note that this will make the lamp invisible", + default=False, + ) @classmethod def unregister(cls): @@ -675,7 +742,7 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): name="Map Resolution", description="Importance map size is resolution x resolution; " "higher values potentially produce less noise, at the cost of memory and speed", - min=4, max=8096, + min=4, max=8192, default=256, ) cls.samples = IntProperty( @@ -684,6 +751,12 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): min=1, max=10000, default=4, ) + cls.max_bounces = IntProperty( + name="Max Bounces", + description="Maximum number of bounces the background light will contribute to the render", + min=0, max=1024, + default=1024, + ) cls.homogeneous_volume = BoolProperty( name="Homogeneous Volume", description="When using volume rendering, assume volume has the same density everywhere" @@ -697,6 +770,13 @@ class CyclesWorldSettings(bpy.types.PropertyGroup): default='EQUIANGULAR', ) + cls.volume_interpolation = EnumProperty( + name="Volume Interpolation", + description="Interpolation method to use for volumes", + items=enum_volume_interpolation, + default='LINEAR', + ) + @classmethod def unregister(cls): del bpy.types.World.cycles @@ -828,6 +908,12 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup): default=1, ) + cls.use_camera_cull = BoolProperty( + name="Use Camera Cull", + description="Allow this object and its duplicators to be culled by camera space culling", + default=False, + ) + @classmethod def unregister(cls): del bpy.types.Object.cycles diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index b544c476c11..a44a0b46960 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -11,14 +11,18 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> import bpy -from bpy.types import Panel, Menu, Operator +from bpy.types import ( + Panel, + Menu, + Operator, + ) class CYCLES_MT_sampling_presets(Menu): @@ -37,7 +41,7 @@ class CYCLES_MT_integrator_presets(Menu): draw = Menu.draw_preset -class CyclesButtonsPanel(): +class CyclesButtonsPanel: bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "render" @@ -56,7 +60,15 @@ def use_cpu(context): return (device_type == 'NONE' or cscene.device == 'CPU') -def draw_samples_info(layout, cscene): +def use_branched_path(context): + cscene = context.scene.cycles + device_type = context.user_preferences.system.compute_device_type + + return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL') + + +def draw_samples_info(layout, context): + cscene = context.scene.cycles integrator = cscene.progressive # Calculate sample values @@ -86,7 +98,7 @@ def draw_samples_info(layout, cscene): # Draw interface # Do not draw for progressive, when Square Samples are disabled - if (integrator == 'BRANCHED_PATH') or (cscene.use_square_samples and integrator == 'PATH'): + if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'): col = layout.column(align=True) col.scale_y = 0.6 col.label("Total Samples:") @@ -110,6 +122,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles + device_type = context.user_preferences.system.compute_device_type row = layout.row(align=True) row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label) @@ -117,7 +130,9 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): row.operator("render.cycles_sampling_preset_add", text="", icon="ZOOMOUT").remove_active = True row = layout.row() - row.prop(cscene, "progressive", text="") + sub = row.row() + sub.active = device_type != 'OPENCL' + sub.prop(cscene, "progressive", text="") row.prop(cscene, "use_square_samples") split = layout.split() @@ -125,11 +140,15 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): col = split.column() sub = col.column(align=True) sub.label("Settings:") - sub.prop(cscene, "seed") + + seed_sub = sub.row(align=True) + seed_sub.prop(cscene, "seed") + seed_sub.prop(cscene, "use_animated_seed", text="", icon="TIME") + sub.prop(cscene, "sample_clamp_direct") sub.prop(cscene, "sample_clamp_indirect") - if cscene.progressive == 'PATH': + if cscene.progressive == 'PATH' or use_branched_path(context) == False: col = split.column() sub = col.column(align=True) sub.label(text="Samples:") @@ -163,7 +182,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): layout.row().prop(cscene, "use_layer_samples") break - draw_samples_info(layout, cscene) + draw_samples_info(layout, context) class CyclesRender_PT_volume_sampling(CyclesButtonsPanel, Panel): @@ -313,7 +332,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): col.separator() col.label(text="Final Render:") - col.prop(cscene, "use_cache") col.prop(rd, "use_persistent_data", text="Persistent Images") col.separator() @@ -412,6 +430,52 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel): col.prop(rl, "use_pass_emit", text="Emission") col.prop(rl, "use_pass_environment") + if hasattr(rd, "debug_pass_type"): + layout.prop(rd, "debug_pass_type") + + +class CyclesRender_PT_views(CyclesButtonsPanel, Panel): + bl_label = "Views" + bl_context = "render_layer" + bl_options = {'DEFAULT_CLOSED'} + + def draw_header(self, context): + rd = context.scene.render + self.layout.prop(rd, "use_multiview", text="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + rd = scene.render + rv = rd.views.active + + layout.active = rd.use_multiview + basic_stereo = (rd.views_format == 'STEREO_3D') + + row = layout.row() + row.prop(rd, "views_format", expand=True) + + if basic_stereo: + row = layout.row() + row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) + + row = layout.row() + row.label(text="File Suffix:") + row.prop(rv, "file_suffix", text="") + + else: + row = layout.row() + row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) + + col = row.column(align=True) + col.operator("scene.render_view_add", icon='ZOOMIN', text="") + col.operator("scene.render_view_remove", icon='ZOOMOUT', text="") + + row = layout.row() + row.label(text="Camera Suffix:") + row.prop(rv, "camera_suffix", text="") + class Cycles_PT_post_processing(CyclesButtonsPanel, Panel): bl_label = "Post Processing" @@ -445,6 +509,7 @@ class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel): cam = context.camera ccam = cam.cycles + dof_options = cam.gpu_dof split = layout.split() @@ -456,6 +521,16 @@ class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel): sub.active = cam.dof_object is None sub.prop(cam, "dof_distance", text="Distance") + hq_support = dof_options.is_hq_supported + sub = col.column(align=True) + sub.label("Viewport:") + subhq = sub.column() + subhq.active = hq_support + subhq.prop(dof_options, "use_high_quality") + sub.prop(dof_options, "fstop") + if dof_options.use_high_quality and hq_support: + sub.prop(dof_options, "blades") + col = split.column() col.label("Aperture:") @@ -506,11 +581,16 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel): ob = context.object slot = context.material_slot space = context.space_data + is_sortable = len(ob.material_slots) > 1 if ob: + rows = 1 + if (is_sortable): + rows = 4 + row = layout.row() - row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=1) + row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows) col = row.column(align=True) col.operator("object.material_slot_add", icon='ZOOMIN', text="") @@ -518,6 +598,12 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel): col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="") + if is_sortable: + col.separator() + + col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP' + col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + if ob.mode == 'EDIT': row = layout.row(align=True) row.operator("object.material_slot_assign", text="Assign") @@ -579,7 +665,13 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): ob = context.object - return CyclesButtonsPanel.poll(context) and ob and ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'} + if CyclesButtonsPanel.poll(context) and ob: + if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}: + return True + if ob.dupli_type == 'GROUP' and ob.dupli_group: + return True + # TODO(sergey): More duplicator types here? + return False def draw_header(self, context): layout = self.layout @@ -613,8 +705,8 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel): sub.prop(cob, "motion_steps", text="Steps") -class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel): - bl_label = "Ray Visibility" +class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): + bl_label = "Cycles Settings" bl_context = "object" bl_options = {'DEFAULT_CLOSED'} @@ -622,15 +714,19 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel): def poll(cls, context): ob = context.object return (CyclesButtonsPanel.poll(context) and - ob and ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'} or - ob and ob.dupli_type == 'GROUP' and ob.dupli_group) + ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'}) or + (ob.dupli_type == 'GROUP' and ob.dupli_group))) def draw(self, context): layout = self.layout + scene = context.scene + cscene = scene.cycles ob = context.object + cob = ob.cycles visibility = ob.cycles_visibility + layout.label(text="Ray Visibility:") flow = layout.column_flow() flow.prop(visibility, "camera") @@ -642,6 +738,12 @@ class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel): if ob.type != 'LAMP': flow.prop(visibility, "shadow") + col = layout.column() + col.label(text="Performance:") + row = col.row() + row.active = scene.render.use_simplify and cscene.use_camera_cull + row.prop(cob, "use_camera_cull") + class CYCLES_OT_use_shading_nodes(Operator): """Enable nodes on a material, world or lamp""" @@ -668,9 +770,14 @@ def find_node(material, nodetype): if material and material.node_tree: ntree = material.node_tree + active_output_node = None for node in ntree.nodes: if getattr(node, "type", None) == nodetype: - return node + if getattr(node, "is_active_output", True): + return node + if not active_output_node: + active_output_node = node + return active_output_node return None @@ -707,7 +814,10 @@ class CyclesLamp_PT_preview(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return context.lamp and CyclesButtonsPanel.poll(context) + return context.lamp and \ + not (context.lamp.type == 'AREA' and + context.lamp.cycles.is_portal) \ + and CyclesButtonsPanel.poll(context) def draw(self, context): self.layout.template_preview(context.lamp) @@ -745,13 +855,21 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel): sub.prop(lamp, "size", text="Size X") sub.prop(lamp, "size_y", text="Size Y") - if cscene.progressive == 'BRANCHED_PATH': - col.prop(clamp, "samples") + if not (lamp.type == 'AREA' and clamp.is_portal): + sub = col.column(align=True) + if use_branched_path(context): + sub.prop(clamp, "samples") + sub.prop(clamp, "max_bounces") col = split.column() - col.prop(clamp, "cast_shadow") - layout.prop(clamp, "use_multiple_importance_sampling") + sub = col.column(align=True) + sub.active = not (lamp.type == 'AREA' and clamp.is_portal) + sub.prop(clamp, "cast_shadow") + sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance") + + if lamp.type == 'AREA': + col.prop(clamp, "is_portal", text="Portal") if lamp.type == 'HEMI': layout.label(text="Not supported, interpreted as sun lamp") @@ -763,7 +881,9 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return context.lamp and CyclesButtonsPanel.poll(context) + return context.lamp and not (context.lamp.type == 'AREA' and + context.lamp.cycles.is_portal) and \ + CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout @@ -946,14 +1066,16 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): sub = col.column(align=True) sub.active = cworld.sample_as_light sub.prop(cworld, "sample_map_resolution") - if cscene.progressive == 'BRANCHED_PATH': + if use_branched_path(context): sub.prop(cworld, "samples") + sub.prop(cworld, "max_bounces") col = split.column() col.label(text="Volume:") sub = col.column() sub.active = use_cpu(context) sub.prop(cworld, "volume_sampling", text="") + sub.prop(cworld, "volume_interpolation", text="") col.prop(cworld, "homogeneous_volume", text="Homogeneous") @@ -1037,17 +1159,6 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel): cmat = mat.cycles split = layout.split() - - col = split.column(align=True) - col.prop(mat, "diffuse_color", text="Viewport Color") - col.prop(mat, "alpha") - - col = split.column(align=True) - col.label() - col.prop(mat, "pass_index") - - split = layout.split() - col = split.column() col.label(text="Surface:") col.prop(cmat, "sample_as_light", text="Multiple Importance") @@ -1058,8 +1169,29 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel): sub = col.column() sub.active = use_cpu(context) sub.prop(cmat, "volume_sampling", text="") + sub.prop(cmat, "volume_interpolation", text="") col.prop(cmat, "homogeneous_volume", text="Homogeneous") + layout.separator() + split = layout.split() + + col = split.column(align=True) + col.label("Viewport Color:") + col.prop(mat, "diffuse_color", text="") + col.prop(mat, "alpha") + + col.separator() + col.label("Viewport Alpha:") + col.prop(mat.game_settings, "alpha_blend", text="") + + col = split.column(align=True) + col.label("Viewport Specular:") + col.prop(mat, "specular_color", text="") + col.prop(mat, "specular_hardness", text="Hardness") + + col.separator() + col.prop(mat, "pass_index") + class CyclesTexture_PT_context(CyclesButtonsPanel, Panel): bl_label = "" @@ -1126,7 +1258,8 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): node = context.texture_node - return node and CyclesButtonsPanel.poll(context) + # TODO(sergey): perform a faster/nicer check? + return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout @@ -1350,13 +1483,28 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): def draw(self, context): layout = self.layout - rd = context.scene.render + scene = context.scene + rd = scene.render + cscene = scene.cycles layout.active = rd.use_simplify + split = layout.split() - row = layout.row() - row.prop(rd, "simplify_subdivision", text="Subdivision") - row.prop(rd, "simplify_child_particles", text="Child Particles") + col = split.column() + col.label(text="Viewport:") + col.prop(rd, "simplify_subdivision", text="Subdivision") + col.prop(rd, "simplify_child_particles", text="Child Particles") + + col = split.column() + col.label(text="Render:") + col.prop(rd, "simplify_subdivision_render", text="Subdivision") + col.prop(rd, "simplify_child_particles_render", text="Child Particles") + + col = layout.column() + col.prop(cscene, "use_camera_cull") + subsub = col.column() + subsub.active = cscene.use_camera_cull + subsub.prop(cscene, "camera_cull_margin") def draw_device(self, context): @@ -1399,7 +1547,11 @@ def get_panels(): "RENDER_PT_encoding", "RENDER_PT_dimensions", "RENDER_PT_stamp", + "RENDER_PT_freestyle", "RENDERLAYER_PT_layers", + "RENDERLAYER_PT_freestyle", + "RENDERLAYER_PT_freestyle_lineset", + "RENDERLAYER_PT_freestyle_linestyle", "SCENE_PT_scene", "SCENE_PT_color_management", "SCENE_PT_custom_props", @@ -1424,6 +1576,8 @@ def get_panels(): "DATA_PT_vertex_colors", "DATA_PT_camera", "DATA_PT_camera_display", + "DATA_PT_camera_stereoscopy", + "DATA_PT_camera_safe_areas", "DATA_PT_lens", "DATA_PT_speaker", "DATA_PT_distance", @@ -1437,6 +1591,7 @@ def get_panels(): "DATA_PT_custom_props_curve", "DATA_PT_custom_props_lattice", "DATA_PT_custom_props_metaball", + "TEXTURE_PT_preview", "TEXTURE_PT_custom_props", "TEXTURE_PT_clouds", "TEXTURE_PT_wood", @@ -1454,6 +1609,7 @@ def get_panels(): "TEXTURE_PT_pointdensity", "TEXTURE_PT_pointdensity_turbulence", "TEXTURE_PT_mapping", + "TEXTURE_PT_ocean", "TEXTURE_PT_influence", "TEXTURE_PT_colors", "PARTICLE_PT_context_particles", @@ -1475,6 +1631,7 @@ def get_panels(): "PARTICLE_PT_force_fields", "PARTICLE_PT_vertexgroups", "MATERIAL_PT_custom_props", + "MATERIAL_PT_freestyle_line", "BONE_PT_custom_props", "OBJECT_PT_custom_props", ] diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index eaeec703ff5..2fbb01ba5b8 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -11,7 +11,7 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License +# limitations under the License. # # <pep8 compliant> @@ -21,6 +21,85 @@ import bpy from bpy.app.handlers import persistent +def check_is_new_shading_ntree(node_tree): + for node in node_tree.nodes: + # If material has any node with ONLY new shading system + # compatibility then it's considered a Cycles material + # and versioning code would need to perform on it. + # + # We can not check for whether NEW_SHADING in compatibility + # because some nodes could have compatibility with both old + # and new shading system and they can't be used for any + # decision here. + if node.shading_compatibility == {'NEW_SHADING'}: + return True + + # If node is only compatible with old shading system + # then material can not be Cycles material and we + # can stopiterating nodes now. + if node.shading_compatibility == {'OLD_SHADING'}: + return False + return False + + +def check_is_new_shading_material(material): + if not material.node_tree: + return False + return check_is_new_shading_ntree(material.node_tree) + + +def check_is_new_shading_world(world): + if not world.node_tree: + return False + return check_is_new_shading_ntree(world.node_tree) + + +def check_is_new_shading_lamp(lamp): + if not lamp.node_tree: + return False + return check_is_new_shading_ntree(lamp.node_tree) + + +def foreach_notree_node(nodetree, callback, traversed): + if nodetree in traversed: + return + traversed.add(nodetree) + for node in nodetree.nodes: + callback(node) + if node.bl_idname == 'ShaderNodeGroup': + foreach_notree_node(node.node_tree, callback, traversed) + + +def foreach_cycles_node(callback): + traversed = set() + for material in bpy.data.materials: + if check_is_new_shading_material(material): + foreach_notree_node(material.node_tree, + callback, + traversed) + for world in bpy.data.worlds: + if check_is_new_shading_world(world): + foreach_notree_node(world.node_tree, + callback, + traversed) + for lamp in bpy.data.lamps: + if check_is_new_shading_world(lamp): + foreach_notree_node(lamp.node_tree, + callback, + traversed) + + +def mapping_node_order_flip(node): + """ + Flip euler order of mapping shader node + """ + if node.bl_idname == 'ShaderNodeMapping': + rot = node.rotation.copy() + rot.order = 'ZYX' + quat = rot.to_quaternion() + node.rotation = quat.to_euler('XYZ') + + @persistent def do_versions(self): # We don't modify startup file because it assumes to @@ -57,3 +136,7 @@ def do_versions(self): cscene.caustics_reflective = False cscene.caustics_refractive = False + + # Euler order was ZYX in previous versions. + if bpy.data.version <= (2, 73, 4): + foreach_cycles_node(mapping_node_order_flip) |