1#
2# Copyright 2011-2013 Blender Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17# <pep8 compliant>
18
19import bpy
20from bpy_extras.node_utils import find_node_input
21from bl_ui.utils import PresetPanel
22
23from bpy.types import Panel
24
25from bl_ui.properties_grease_pencil_common import GreasePencilSimplifyPanel
26
27
28class CYCLES_PT_sampling_presets(PresetPanel, Panel):
29    bl_label = "Sampling Presets"
30    preset_subdir = "cycles/sampling"
31    preset_operator = "script.execute_preset"
32    preset_add_operator = "render.cycles_sampling_preset_add"
33    COMPAT_ENGINES = {'CYCLES'}
34
35
36class CYCLES_PT_integrator_presets(PresetPanel, Panel):
37    bl_label = "Integrator Presets"
38    preset_subdir = "cycles/integrator"
39    preset_operator = "script.execute_preset"
40    preset_add_operator = "render.cycles_integrator_preset_add"
41    COMPAT_ENGINES = {'CYCLES'}
42
43
44class CyclesButtonsPanel:
45    bl_space_type = "PROPERTIES"
46    bl_region_type = "WINDOW"
47    bl_context = "render"
48    COMPAT_ENGINES = {'CYCLES'}
49
50    @classmethod
51    def poll(cls, context):
52        return context.engine in cls.COMPAT_ENGINES
53
54
55# Adapt properties editor panel to display in node editor. We have to
56# copy the class rather than inherit due to the way bpy registration works.
57def node_panel(cls):
58    node_cls = type('NODE_' + cls.__name__, cls.__bases__, dict(cls.__dict__))
59
60    node_cls.bl_space_type = 'NODE_EDITOR'
61    node_cls.bl_region_type = 'UI'
62    node_cls.bl_category = "Options"
63    if hasattr(node_cls, 'bl_parent_id'):
64        node_cls.bl_parent_id = 'NODE_' + node_cls.bl_parent_id
65
66    return node_cls
67
68
69def get_device_type(context):
70    return context.preferences.addons[__package__].preferences.compute_device_type
71
72
73def use_cpu(context):
74    cscene = context.scene.cycles
75
76    return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
77
78
79def use_opencl(context):
80    cscene = context.scene.cycles
81
82    return (get_device_type(context) == 'OPENCL' and cscene.device == 'GPU')
83
84
85def use_cuda(context):
86    cscene = context.scene.cycles
87
88    return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU')
89
90
91def use_optix(context):
92    cscene = context.scene.cycles
93
94    return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
95
96
97def use_branched_path(context):
98    cscene = context.scene.cycles
99
100    return (cscene.progressive == 'BRANCHED_PATH' and not use_optix(context))
101
102
103def use_sample_all_lights(context):
104    cscene = context.scene.cycles
105
106    return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect
107
108
109def show_device_active(context):
110    cscene = context.scene.cycles
111    if cscene.device != 'GPU':
112        return True
113    return context.preferences.addons[__package__].preferences.has_active_device()
114
115
116def draw_samples_info(layout, context):
117    cscene = context.scene.cycles
118    integrator = cscene.progressive
119
120    # Calculate sample values
121    if integrator == 'PATH':
122        aa = cscene.samples
123        if cscene.use_square_samples:
124            aa = aa * aa
125    else:
126        aa = cscene.aa_samples
127        d = cscene.diffuse_samples
128        g = cscene.glossy_samples
129        t = cscene.transmission_samples
130        ao = cscene.ao_samples
131        ml = cscene.mesh_light_samples
132        sss = cscene.subsurface_samples
133        vol = cscene.volume_samples
134
135        if cscene.use_square_samples:
136            aa = aa * aa
137            d = d * d
138            g = g * g
139            t = t * t
140            ao = ao * ao
141            ml = ml * ml
142            sss = sss * sss
143            vol = vol * vol
144
145    # Draw interface
146    # Do not draw for progressive, when Square Samples are disabled
147    if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'):
148        col = layout.column(align=True)
149        col.scale_y = 0.6
150        col.label(text="Total Samples:")
151        col.separator()
152        if integrator == 'PATH':
153            col.label(text="%s AA" % aa)
154        else:
155            col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
156                      (aa, d * aa, g * aa, t * aa))
157            col.separator()
158            col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
159                      (ao * aa, ml * aa, sss * aa, vol * aa))
160
161
162class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
163    bl_label = "Sampling"
164
165    def draw_header_preset(self, context):
166        CYCLES_PT_sampling_presets.draw_panel_header(self.layout)
167
168    def draw(self, context):
169        layout = self.layout
170
171        scene = context.scene
172        cscene = scene.cycles
173
174        layout.use_property_split = True
175        layout.use_property_decorate = False
176
177        if not use_optix(context):
178            layout.prop(cscene, "progressive")
179
180        if not use_branched_path(context):
181            col = layout.column(align=True)
182            col.prop(cscene, "samples", text="Render")
183            col.prop(cscene, "preview_samples", text="Viewport")
184        else:
185            col = layout.column(align=True)
186            col.prop(cscene, "aa_samples", text="Render")
187            col.prop(cscene, "preview_aa_samples", text="Viewport")
188
189        if not use_branched_path(context):
190            draw_samples_info(layout, context)
191
192
193class CYCLES_RENDER_PT_sampling_sub_samples(CyclesButtonsPanel, Panel):
194    bl_label = "Sub Samples"
195    bl_parent_id = "CYCLES_RENDER_PT_sampling"
196
197    @classmethod
198    def poll(cls, context):
199        return use_branched_path(context)
200
201    def draw(self, context):
202        layout = self.layout
203        layout.use_property_split = True
204        layout.use_property_decorate = False
205
206        scene = context.scene
207        cscene = scene.cycles
208
209        col = layout.column(align=True)
210        col.prop(cscene, "diffuse_samples", text="Diffuse")
211        col.prop(cscene, "glossy_samples", text="Glossy")
212        col.prop(cscene, "transmission_samples", text="Transmission")
213        col.prop(cscene, "ao_samples", text="AO")
214
215        sub = col.row(align=True)
216        sub.active = use_sample_all_lights(context)
217        sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
218        col.prop(cscene, "subsurface_samples", text="Subsurface")
219        col.prop(cscene, "volume_samples", text="Volume")
220
221        draw_samples_info(layout, context)
222
223
224class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
225    bl_label = "Adaptive Sampling"
226    bl_parent_id = "CYCLES_RENDER_PT_sampling"
227    bl_options = {'DEFAULT_CLOSED'}
228
229    def draw_header(self, context):
230        layout = self.layout
231        scene = context.scene
232        cscene = scene.cycles
233
234        layout.prop(cscene, "use_adaptive_sampling", text="")
235
236    def draw(self, context):
237        layout = self.layout
238        layout.use_property_split = True
239        layout.use_property_decorate = False
240
241        scene = context.scene
242        cscene = scene.cycles
243
244        layout.active = cscene.use_adaptive_sampling
245
246        col = layout.column(align=True)
247        col.prop(cscene, "adaptive_threshold", text="Noise Threshold")
248        col.prop(cscene, "adaptive_min_samples", text="Min Samples")
249
250
251class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel):
252    bl_label = "Denoising"
253    bl_parent_id = "CYCLES_RENDER_PT_sampling"
254    bl_options = {'DEFAULT_CLOSED'}
255
256    def draw(self, context):
257        layout = self.layout
258        layout.use_property_split = True
259        layout.use_property_decorate = False
260
261        scene = context.scene
262        cscene = scene.cycles
263
264        heading = layout.column(align=True, heading="Render")
265        row = heading.row(align=True)
266        row.prop(cscene, "use_denoising", text="")
267        sub = row.row()
268
269        sub.active = cscene.use_denoising
270        for view_layer in scene.view_layers:
271            if view_layer.cycles.denoising_store_passes:
272                sub.active = True
273
274        sub.prop(cscene, "denoiser", text="")
275
276        heading = layout.column(align=False, heading="Viewport")
277        row = heading.row(align=True)
278        row.prop(cscene, "use_preview_denoising", text="")
279        sub = row.row()
280        sub.active = cscene.use_preview_denoising
281        sub.prop(cscene, "preview_denoiser", text="")
282
283        sub = heading.row(align=True)
284        sub.active = cscene.use_preview_denoising
285        sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
286
287
288class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
289    bl_label = "Advanced"
290    bl_parent_id = "CYCLES_RENDER_PT_sampling"
291    bl_options = {'DEFAULT_CLOSED'}
292
293    def draw(self, context):
294        layout = self.layout
295        layout.use_property_split = True
296        layout.use_property_decorate = False
297
298        scene = context.scene
299        cscene = scene.cycles
300
301        row = layout.row(align=True)
302        row.prop(cscene, "seed")
303        row.prop(cscene, "use_animated_seed", text="", icon='TIME')
304
305        col = layout.column(align=True)
306        col.active = not(cscene.use_adaptive_sampling)
307        col.prop(cscene, "sampling_pattern", text="Pattern")
308
309        layout.prop(cscene, "use_square_samples")
310
311        layout.separator()
312
313        col = layout.column(align=True)
314        col.prop(cscene, "min_light_bounces")
315        col.prop(cscene, "min_transparent_bounces")
316        col.prop(cscene, "light_sampling_threshold", text="Light Threshold")
317
318        if cscene.progressive != 'PATH' and use_branched_path(context):
319            col = layout.column(align=True)
320            col.prop(cscene, "sample_all_lights_direct")
321            col.prop(cscene, "sample_all_lights_indirect")
322
323        for view_layer in scene.view_layers:
324            if view_layer.samples > 0:
325                layout.separator()
326                layout.row().prop(cscene, "use_layer_samples")
327                break
328
329
330class CYCLES_RENDER_PT_sampling_total(CyclesButtonsPanel, Panel):
331    bl_label = "Total Samples"
332    bl_parent_id = "CYCLES_RENDER_PT_sampling"
333
334    @classmethod
335    def poll(cls, context):
336        scene = context.scene
337        cscene = scene.cycles
338
339        if cscene.use_square_samples:
340            return True
341
342        return cscene.progressive != 'PATH' and use_branched_path(context)
343
344    def draw(self, context):
345        layout = self.layout
346        cscene = context.scene.cycles
347        integrator = cscene.progressive
348
349        # Calculate sample values
350        if integrator == 'PATH':
351            aa = cscene.samples
352            if cscene.use_square_samples:
353                aa = aa * aa
354        else:
355            aa = cscene.aa_samples
356            d = cscene.diffuse_samples
357            g = cscene.glossy_samples
358            t = cscene.transmission_samples
359            ao = cscene.ao_samples
360            ml = cscene.mesh_light_samples
361            sss = cscene.subsurface_samples
362            vol = cscene.volume_samples
363
364            if cscene.use_square_samples:
365                aa = aa * aa
366                d = d * d
367                g = g * g
368                t = t * t
369                ao = ao * ao
370                ml = ml * ml
371                sss = sss * sss
372                vol = vol * vol
373
374        col = layout.column(align=True)
375        col.scale_y = 0.6
376        if integrator == 'PATH':
377            col.label(text="%s AA" % aa)
378        else:
379            col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
380                      (aa, d * aa, g * aa, t * aa))
381            col.separator()
382            col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
383                      (ao * aa, ml * aa, sss * aa, vol * aa))
384
385
386class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
387    bl_label = "Subdivision"
388    bl_options = {'DEFAULT_CLOSED'}
389
390    @classmethod
391    def poll(cls, context):
392        return (context.scene.render.engine == 'CYCLES') and (context.scene.cycles.feature_set == 'EXPERIMENTAL')
393
394    def draw(self, context):
395        layout = self.layout
396        layout.use_property_split = True
397        layout.use_property_decorate = False
398
399        scene = context.scene
400        cscene = scene.cycles
401
402        col = layout.column()
403        sub = col.column(align=True)
404        sub.prop(cscene, "dicing_rate", text="Dicing Rate Render")
405        sub.prop(cscene, "preview_dicing_rate", text="Viewport")
406
407        col.separator()
408
409        col.prop(cscene, "offscreen_dicing_scale", text="Offscreen Scale")
410        col.prop(cscene, "max_subdivisions")
411
412        col.prop(cscene, "dicing_camera")
413
414
415class CYCLES_RENDER_PT_hair(CyclesButtonsPanel, Panel):
416    bl_label = "Hair"
417    bl_options = {'DEFAULT_CLOSED'}
418
419    def draw(self, context):
420        layout = self.layout
421        layout.use_property_split = True
422        layout.use_property_decorate = False
423
424        scene = context.scene
425        ccscene = scene.cycles_curves
426
427        col = layout.column()
428        col.prop(ccscene, "shape", text="Shape")
429        if ccscene.shape == 'RIBBONS':
430            col.prop(ccscene, "subdivisions", text="Curve Subdivisions")
431
432
433class CYCLES_RENDER_PT_volumes(CyclesButtonsPanel, Panel):
434    bl_label = "Volumes"
435    bl_options = {'DEFAULT_CLOSED'}
436
437    def draw(self, context):
438        layout = self.layout
439        layout.use_property_split = True
440        layout.use_property_decorate = False
441
442        scene = context.scene
443        cscene = scene.cycles
444
445        col = layout.column(align=True)
446        col.prop(cscene, "volume_step_rate", text="Step Rate Render")
447        col.prop(cscene, "volume_preview_step_rate", text="Viewport")
448
449        layout.prop(cscene, "volume_max_steps", text="Max Steps")
450
451
452class CYCLES_RENDER_PT_light_paths(CyclesButtonsPanel, Panel):
453    bl_label = "Light Paths"
454    bl_options = {'DEFAULT_CLOSED'}
455
456    def draw_header_preset(self, context):
457        CYCLES_PT_integrator_presets.draw_panel_header(self.layout)
458
459    def draw(self, context):
460        pass
461
462
463class CYCLES_RENDER_PT_light_paths_max_bounces(CyclesButtonsPanel, Panel):
464    bl_label = "Max Bounces"
465    bl_parent_id = "CYCLES_RENDER_PT_light_paths"
466
467    def draw(self, context):
468        layout = self.layout
469        layout.use_property_split = True
470        layout.use_property_decorate = False
471
472        scene = context.scene
473        cscene = scene.cycles
474
475        col = layout.column(align=True)
476        col.prop(cscene, "max_bounces", text="Total")
477
478        col = layout.column(align=True)
479        col.prop(cscene, "diffuse_bounces", text="Diffuse")
480        col.prop(cscene, "glossy_bounces", text="Glossy")
481        col.prop(cscene, "transparent_max_bounces", text="Transparency")
482        col.prop(cscene, "transmission_bounces", text="Transmission")
483        col.prop(cscene, "volume_bounces", text="Volume")
484
485
486class CYCLES_RENDER_PT_light_paths_clamping(CyclesButtonsPanel, Panel):
487    bl_label = "Clamping"
488    bl_parent_id = "CYCLES_RENDER_PT_light_paths"
489
490    def draw(self, context):
491        layout = self.layout
492        layout.use_property_split = True
493        layout.use_property_decorate = False
494
495        scene = context.scene
496        cscene = scene.cycles
497
498        col = layout.column(align=True)
499        col.prop(cscene, "sample_clamp_direct", text="Direct Light")
500        col.prop(cscene, "sample_clamp_indirect", text="Indirect Light")
501
502
503class CYCLES_RENDER_PT_light_paths_caustics(CyclesButtonsPanel, Panel):
504    bl_label = "Caustics"
505    bl_parent_id = "CYCLES_RENDER_PT_light_paths"
506
507    def draw(self, context):
508        layout = self.layout
509        layout.use_property_split = True
510        layout.use_property_decorate = False
511
512        scene = context.scene
513        cscene = scene.cycles
514
515        col = layout.column()
516        col.prop(cscene, "blur_glossy")
517        col = layout.column(heading="Caustics", align=True)
518        col.prop(cscene, "caustics_reflective", text="Reflective")
519        col.prop(cscene, "caustics_refractive", text="Refractive")
520
521
522class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
523    bl_label = "Motion Blur"
524    bl_options = {'DEFAULT_CLOSED'}
525
526    def draw_header(self, context):
527        rd = context.scene.render
528
529        self.layout.prop(rd, "use_motion_blur", text="")
530
531    def draw(self, context):
532        layout = self.layout
533        layout.use_property_split = True
534        layout.use_property_decorate = False
535
536        scene = context.scene
537        cscene = scene.cycles
538        rd = scene.render
539        layout.active = rd.use_motion_blur
540
541        col = layout.column()
542        col.prop(cscene, "motion_blur_position", text="Position")
543        col.prop(rd, "motion_blur_shutter")
544        col.separator()
545        col.prop(cscene, "rolling_shutter_type", text="Rolling Shutter")
546        sub = col.column()
547        sub.active = cscene.rolling_shutter_type != 'NONE'
548        sub.prop(cscene, "rolling_shutter_duration")
549
550
551class CYCLES_RENDER_PT_motion_blur_curve(CyclesButtonsPanel, Panel):
552    bl_label = "Shutter Curve"
553    bl_parent_id = "CYCLES_RENDER_PT_motion_blur"
554    bl_options = {'DEFAULT_CLOSED'}
555
556    def draw(self, context):
557        layout = self.layout
558        layout.use_property_split = True
559        layout.use_property_decorate = False
560
561        scene = context.scene
562        rd = scene.render
563        layout.active = rd.use_motion_blur
564
565        col = layout.column()
566
567        col.template_curve_mapping(rd, "motion_blur_shutter_curve")
568
569        col = layout.column(align=True)
570        row = col.row(align=True)
571        row.operator("render.shutter_curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
572        row.operator("render.shutter_curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
573        row.operator("render.shutter_curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
574        row.operator("render.shutter_curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
575        row.operator("render.shutter_curve_preset", icon='LINCURVE', text="").shape = 'LINE'
576        row.operator("render.shutter_curve_preset", icon='NOCURVE', text="").shape = 'MAX'
577
578
579class CYCLES_RENDER_PT_film(CyclesButtonsPanel, Panel):
580    bl_label = "Film"
581    bl_options = {'DEFAULT_CLOSED'}
582
583    def draw(self, context):
584        layout = self.layout
585        layout.use_property_split = True
586        layout.use_property_decorate = False
587        scene = context.scene
588        cscene = scene.cycles
589
590        col = layout.column()
591        col.prop(cscene, "film_exposure")
592
593
594class CYCLES_RENDER_PT_film_transparency(CyclesButtonsPanel, Panel):
595    bl_label = "Transparent"
596    bl_parent_id = "CYCLES_RENDER_PT_film"
597
598    def draw_header(self, context):
599        layout = self.layout
600
601        scene = context.scene
602        rd = scene.render
603
604        layout.prop(rd, "film_transparent", text="")
605
606    def draw(self, context):
607        layout = self.layout
608        layout.use_property_split = True
609        layout.use_property_decorate = False
610        scene = context.scene
611        rd = scene.render
612        cscene = scene.cycles
613
614        layout.active = rd.film_transparent
615
616        col = layout.column()
617        col.prop(cscene, "film_transparent_glass", text="Transparent Glass")
618
619        sub = col.column()
620        sub.active = rd.film_transparent and cscene.film_transparent_glass
621        sub.prop(cscene, "film_transparent_roughness", text="Roughness Threshold")
622
623
624class CYCLES_RENDER_PT_film_pixel_filter(CyclesButtonsPanel, Panel):
625    bl_label = "Pixel Filter"
626    bl_parent_id = "CYCLES_RENDER_PT_film"
627
628    def draw(self, context):
629        layout = self.layout
630        layout.use_property_split = True
631        layout.use_property_decorate = False
632        scene = context.scene
633        cscene = scene.cycles
634
635        col = layout.column()
636        col.prop(cscene, "pixel_filter_type", text="Type")
637        if cscene.pixel_filter_type != 'BOX':
638            col.prop(cscene, "filter_width", text="Width")
639
640
641class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel):
642    bl_label = "Performance"
643    bl_options = {'DEFAULT_CLOSED'}
644
645    def draw(self, context):
646        pass
647
648
649class CYCLES_RENDER_PT_performance_threads(CyclesButtonsPanel, Panel):
650    bl_label = "Threads"
651    bl_parent_id = "CYCLES_RENDER_PT_performance"
652
653    def draw(self, context):
654        layout = self.layout
655        layout.use_property_split = True
656        layout.use_property_decorate = False
657
658        scene = context.scene
659        rd = scene.render
660
661        col = layout.column()
662
663        col.prop(rd, "threads_mode")
664        sub = col.column(align=True)
665        sub.enabled = rd.threads_mode == 'FIXED'
666        sub.prop(rd, "threads")
667
668
669class CYCLES_RENDER_PT_performance_tiles(CyclesButtonsPanel, Panel):
670    bl_label = "Tiles"
671    bl_parent_id = "CYCLES_RENDER_PT_performance"
672
673    def draw(self, context):
674        layout = self.layout
675        layout.use_property_split = True
676        layout.use_property_decorate = False
677
678        scene = context.scene
679        rd = scene.render
680        cscene = scene.cycles
681
682        col = layout.column()
683
684        sub = col.column(align=True)
685        sub.prop(rd, "tile_x", text="Tiles X")
686        sub.prop(rd, "tile_y", text="Y")
687        col.prop(cscene, "tile_order", text="Order")
688
689        sub = col.column()
690        sub.active = not rd.use_save_buffers
691        sub.prop(cscene, "use_progressive_refine")
692
693
694class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Panel):
695    bl_label = "Acceleration Structure"
696    bl_parent_id = "CYCLES_RENDER_PT_performance"
697
698    def draw(self, context):
699        import _cycles
700
701        layout = self.layout
702        layout.use_property_split = True
703        layout.use_property_decorate = False
704
705        scene = context.scene
706        cscene = scene.cycles
707
708        col = layout.column()
709
710        use_embree = False
711        if use_cpu(context):
712            use_embree = _cycles.with_embree
713            if not use_embree:
714                sub = col.column(align=True)
715                sub.label(text="Cycles built without Embree support")
716                sub.label(text="CPU raytracing performance will be poor")
717
718        col.prop(cscene, "debug_use_spatial_splits")
719        sub = col.column()
720        sub.active = not use_embree
721        sub.prop(cscene, "debug_use_hair_bvh")
722        sub = col.column()
723        sub.active = not cscene.debug_use_spatial_splits and not use_embree
724        sub.prop(cscene, "debug_bvh_time_steps")
725
726
727class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
728    bl_label = "Final Render"
729    bl_parent_id = "CYCLES_RENDER_PT_performance"
730
731    def draw(self, context):
732        layout = self.layout
733        layout.use_property_split = True
734        layout.use_property_decorate = False
735
736        scene = context.scene
737        rd = scene.render
738
739        col = layout.column()
740
741        col.prop(rd, "use_save_buffers")
742        col.prop(rd, "use_persistent_data", text="Persistent Images")
743
744
745class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
746    bl_label = "Viewport"
747    bl_parent_id = "CYCLES_RENDER_PT_performance"
748
749    def draw(self, context):
750        layout = self.layout
751        layout.use_property_split = True
752        layout.use_property_decorate = False
753
754        scene = context.scene
755        rd = scene.render
756        cscene = scene.cycles
757
758        col = layout.column()
759        col.prop(rd, "preview_pixel_size", text="Pixel Size")
760        col.prop(cscene, "preview_start_resolution", text="Start Pixels")
761
762
763class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
764    bl_label = "Filter"
765    bl_options = {'DEFAULT_CLOSED'}
766    bl_context = "view_layer"
767
768    def draw(self, context):
769        layout = self.layout
770        layout.use_property_split = True
771        layout.use_property_decorate = False
772
773        with_freestyle = bpy.app.build_options.freestyle
774
775        scene = context.scene
776        rd = scene.render
777        view_layer = context.view_layer
778
779        col = layout.column(heading="Include")
780        col.prop(view_layer, "use_sky", text="Environment")
781        col.prop(view_layer, "use_ao", text="Ambient Occlusion")
782        col.prop(view_layer, "use_solid", text="Surfaces")
783        col.prop(view_layer, "use_strand", text="Hair")
784        col.prop(view_layer, "use_volumes", text="Volumes")
785
786
787class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
788    bl_label = "Override"
789    bl_options = {'DEFAULT_CLOSED'}
790    bl_context = "view_layer"
791
792    def draw(self, context):
793        layout = self.layout
794        layout.use_property_split = True
795        layout.use_property_decorate = False
796
797        view_layer = context.view_layer
798
799        layout.prop(view_layer, "material_override")
800        layout.prop(view_layer, "samples")
801
802
803class CYCLES_RENDER_PT_passes(CyclesButtonsPanel, Panel):
804    bl_label = "Passes"
805    bl_context = "view_layer"
806
807    def draw(self, context):
808        pass
809
810
811class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
812    bl_label = "Data"
813    bl_context = "view_layer"
814    bl_parent_id = "CYCLES_RENDER_PT_passes"
815
816    def draw(self, context):
817        layout = self.layout
818        layout.use_property_split = True
819        layout.use_property_decorate = False
820
821        scene = context.scene
822        rd = scene.render
823        view_layer = context.view_layer
824        cycles_view_layer = view_layer.cycles
825
826        col = layout.column(heading="Include", align=True)
827        col.prop(view_layer, "use_pass_combined")
828        col.prop(view_layer, "use_pass_z")
829        col.prop(view_layer, "use_pass_mist")
830        col.prop(view_layer, "use_pass_normal")
831        sub = col.column()
832        sub.active = not rd.use_motion_blur
833        sub.prop(view_layer, "use_pass_vector")
834        col.prop(view_layer, "use_pass_uv")
835
836        col.prop(cycles_view_layer, "denoising_store_passes", text="Denoising Data")
837
838        col = layout.column(heading="Indexes", align=True)
839        col.prop(view_layer, "use_pass_object_index")
840        col.prop(view_layer, "use_pass_material_index")
841
842        col = layout.column(heading="Debug", align=True)
843        col.prop(cycles_view_layer, "pass_debug_render_time", text="Render Time")
844        col.prop(cycles_view_layer, "pass_debug_sample_count", text="Sample Count")
845
846        layout.prop(view_layer, "pass_alpha_threshold")
847
848
849class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel):
850    bl_label = "Light"
851    bl_context = "view_layer"
852    bl_parent_id = "CYCLES_RENDER_PT_passes"
853
854    def draw(self, context):
855        layout = self.layout
856        layout.use_property_split = True
857        layout.use_property_decorate = False
858
859        view_layer = context.view_layer
860        cycles_view_layer = view_layer.cycles
861
862        col = layout.column(heading="Diffuse", align=True)
863        col.prop(view_layer, "use_pass_diffuse_direct", text="Direct")
864        col.prop(view_layer, "use_pass_diffuse_indirect", text="Indirect")
865        col.prop(view_layer, "use_pass_diffuse_color", text="Color")
866
867        col = layout.column(heading="Glossy", align=True)
868        col.prop(view_layer, "use_pass_glossy_direct", text="Direct")
869        col.prop(view_layer, "use_pass_glossy_indirect", text="Indirect")
870        col.prop(view_layer, "use_pass_glossy_color", text="Color")
871
872        col = layout.column(heading="Transmission", align=True)
873        col.prop(view_layer, "use_pass_transmission_direct", text="Direct")
874        col.prop(view_layer, "use_pass_transmission_indirect", text="Indirect")
875        col.prop(view_layer, "use_pass_transmission_color", text="Color")
876
877        col = layout.column(heading="Volume", align=True)
878        col.prop(cycles_view_layer, "use_pass_volume_direct", text="Direct")
879        col.prop(cycles_view_layer, "use_pass_volume_indirect", text="Indirect")
880
881        col = layout.column(heading="Other", align=True)
882        col.prop(view_layer, "use_pass_emit", text="Emission")
883        col.prop(view_layer, "use_pass_environment")
884        col.prop(view_layer, "use_pass_shadow")
885        col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
886
887
888class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, Panel):
889    bl_label = "Cryptomatte"
890    bl_context = "view_layer"
891    bl_parent_id = "CYCLES_RENDER_PT_passes"
892
893    def draw(self, context):
894        import _cycles
895
896        layout = self.layout
897        layout.use_property_split = True
898        layout.use_property_decorate = False
899
900        cycles_view_layer = context.view_layer.cycles
901
902        col = layout.column(heading="Include", align=True)
903        col.prop(cycles_view_layer, "use_pass_crypto_object", text="Object")
904        col.prop(cycles_view_layer, "use_pass_crypto_material", text="Material")
905        col.prop(cycles_view_layer, "use_pass_crypto_asset", text="Asset")
906
907        layout.prop(cycles_view_layer, "pass_crypto_depth", text="Levels")
908
909        row = layout.row(align=True)
910        row.active = use_cpu(context)
911        row.prop(cycles_view_layer, "pass_crypto_accurate", text="Accurate Mode")
912
913
914class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel):
915    bl_label = "Debug"
916    bl_context = "view_layer"
917    bl_parent_id = "CYCLES_RENDER_PT_passes"
918
919    @classmethod
920    def poll(cls, context):
921        import _cycles
922        return _cycles.with_cycles_debug
923
924    def draw(self, context):
925        layout = self.layout
926        layout.use_property_split = True
927        layout.use_property_decorate = False
928
929        cycles_view_layer = context.view_layer.cycles
930
931        layout.prop(cycles_view_layer, "pass_debug_bvh_traversed_nodes")
932        layout.prop(cycles_view_layer, "pass_debug_bvh_traversed_instances")
933        layout.prop(cycles_view_layer, "pass_debug_bvh_intersections")
934        layout.prop(cycles_view_layer, "pass_debug_ray_bounces")
935
936
937class CYCLES_RENDER_UL_aov(bpy.types.UIList):
938    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
939        row = layout.row()
940        split = row.split(factor=0.65)
941        icon = 'ERROR' if item.conflict else 'NONE'
942        split.row().prop(item, "name", text="", icon=icon, emboss=False)
943        split.row().prop(item, "type", text="", emboss=False)
944
945
946class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, Panel):
947    bl_label = "Shader AOV"
948    bl_context = "view_layer"
949    bl_parent_id = "CYCLES_RENDER_PT_passes"
950
951    def draw(self, context):
952        layout = self.layout
953        layout.use_property_split = True
954        layout.use_property_decorate = False
955
956        cycles_view_layer = context.view_layer.cycles
957
958        row = layout.row()
959        col = row.column()
960        col.template_list(
961            "CYCLES_RENDER_UL_aov",
962            "aovs",
963            cycles_view_layer,
964            "aovs",
965            cycles_view_layer,
966            "active_aov",
967            rows=2,
968        )
969
970        col = row.column()
971        sub = col.column(align=True)
972        sub.operator("cycles.add_aov", icon='ADD', text="")
973        sub.operator("cycles.remove_aov", icon='REMOVE', text="")
974
975        if cycles_view_layer.active_aov < len(cycles_view_layer.aovs):
976            active_aov = cycles_view_layer.aovs[cycles_view_layer.active_aov]
977            if active_aov.conflict:
978                layout.label(text=active_aov.conflict, icon='ERROR')
979
980
981class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
982    bl_label = "Denoising"
983    bl_context = "view_layer"
984    bl_options = {'DEFAULT_CLOSED'}
985
986    @classmethod
987    def poll(cls, context):
988        cscene = context.scene.cycles
989        return CyclesButtonsPanel.poll(context) and cscene.use_denoising
990
991    def draw_header(self, context):
992        scene = context.scene
993        view_layer = context.view_layer
994        cycles_view_layer = view_layer.cycles
995
996        layout = self.layout
997        layout.prop(cycles_view_layer, "use_denoising", text="")
998
999    def draw(self, context):
1000        layout = self.layout
1001        layout.use_property_split = True
1002        layout.use_property_decorate = False
1003
1004        scene = context.scene
1005        view_layer = context.view_layer
1006        cycles_view_layer = view_layer.cycles
1007        denoiser = scene.cycles.denoiser
1008
1009        layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising
1010
1011        col = layout.column()
1012
1013        if denoiser == 'OPTIX':
1014            col.prop(cycles_view_layer, "denoising_optix_input_passes")
1015            return
1016        elif denoiser == 'OPENIMAGEDENOISE':
1017            col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes")
1018            return
1019
1020        col.prop(cycles_view_layer, "denoising_radius", text="Radius")
1021
1022        col = layout.column()
1023        col.prop(cycles_view_layer, "denoising_strength", slider=True, text="Strength")
1024        col.prop(cycles_view_layer, "denoising_feature_strength", slider=True, text="Feature Strength")
1025        col.prop(cycles_view_layer, "denoising_relative_pca")
1026
1027        layout.separator()
1028
1029        col = layout.column()
1030        col.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
1031
1032        row = col.row(heading="Diffuse", align=True)
1033        row.prop(cycles_view_layer, "denoising_diffuse_direct", text="Direct", toggle=True)
1034        row.prop(cycles_view_layer, "denoising_diffuse_indirect", text="Indirect", toggle=True)
1035
1036        row = col.row(heading="Glossy", align=True)
1037        row.prop(cycles_view_layer, "denoising_glossy_direct", text="Direct", toggle=True)
1038        row.prop(cycles_view_layer, "denoising_glossy_indirect", text="Indirect", toggle=True)
1039
1040        row = col.row(heading="Transmission", align=True)
1041        row.prop(cycles_view_layer, "denoising_transmission_direct", text="Direct", toggle=True)
1042        row.prop(cycles_view_layer, "denoising_transmission_indirect", text="Indirect", toggle=True)
1043
1044
1045class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
1046    bl_label = "Post Processing"
1047    bl_options = {'DEFAULT_CLOSED'}
1048    bl_context = "output"
1049
1050    def draw(self, context):
1051        layout = self.layout
1052        layout.use_property_split = True
1053        layout.use_property_decorate = False
1054
1055        rd = context.scene.render
1056
1057        col = layout.column(align=True, heading="Pipeline")
1058        col.prop(rd, "use_compositing")
1059        col.prop(rd, "use_sequencer")
1060
1061        layout.prop(rd, "dither_intensity", text="Dither", slider=True)
1062
1063
1064class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel):
1065    bl_label = "Depth of Field"
1066    bl_context = "data"
1067
1068    @classmethod
1069    def poll(cls, context):
1070        return context.camera and CyclesButtonsPanel.poll(context)
1071
1072    def draw_header(self, context):
1073        cam = context.camera
1074        dof = cam.dof
1075        self.layout.prop(dof, "use_dof", text="")
1076
1077    def draw(self, context):
1078        layout = self.layout
1079        layout.use_property_split = True
1080
1081        cam = context.camera
1082        dof = cam.dof
1083        layout.active = dof.use_dof
1084
1085        split = layout.split()
1086
1087        col = split.column()
1088        col.prop(dof, "focus_object", text="Focus Object")
1089
1090        sub = col.row()
1091        sub.active = dof.focus_object is None
1092        sub.prop(dof, "focus_distance", text="Distance")
1093
1094
1095class CYCLES_CAMERA_PT_dof_aperture(CyclesButtonsPanel, Panel):
1096    bl_label = "Aperture"
1097    bl_parent_id = "CYCLES_CAMERA_PT_dof"
1098
1099    @classmethod
1100    def poll(cls, context):
1101        return context.camera and CyclesButtonsPanel.poll(context)
1102
1103    def draw(self, context):
1104        layout = self.layout
1105        layout.use_property_split = True
1106
1107        cam = context.camera
1108        dof = cam.dof
1109        layout.active = dof.use_dof
1110        flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
1111
1112        col = flow.column()
1113        col.prop(dof, "aperture_fstop")
1114        col.prop(dof, "aperture_blades")
1115        col.prop(dof, "aperture_rotation")
1116        col.prop(dof, "aperture_ratio")
1117
1118
1119class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
1120    bl_label = ""
1121    bl_context = "material"
1122    bl_options = {'HIDE_HEADER'}
1123
1124    @classmethod
1125    def poll(cls, context):
1126        if context.active_object and context.active_object.type == 'GPENCIL':
1127            return False
1128        else:
1129            return (context.material or context.object) and CyclesButtonsPanel.poll(context)
1130
1131    def draw(self, context):
1132        layout = self.layout
1133
1134        mat = context.material
1135        ob = context.object
1136        slot = context.material_slot
1137        space = context.space_data
1138
1139        if ob:
1140            is_sortable = len(ob.material_slots) > 1
1141            rows = 1
1142            if (is_sortable):
1143                rows = 4
1144
1145            row = layout.row()
1146
1147            row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
1148
1149            col = row.column(align=True)
1150            col.operator("object.material_slot_add", icon='ADD', text="")
1151            col.operator("object.material_slot_remove", icon='REMOVE', text="")
1152
1153            col.menu("MATERIAL_MT_context_menu", icon='DOWNARROW_HLT', text="")
1154
1155            if is_sortable:
1156                col.separator()
1157
1158                col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
1159                col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
1160
1161            if ob.mode == 'EDIT':
1162                row = layout.row(align=True)
1163                row.operator("object.material_slot_assign", text="Assign")
1164                row.operator("object.material_slot_select", text="Select")
1165                row.operator("object.material_slot_deselect", text="Deselect")
1166
1167        split = layout.split(factor=0.65)
1168
1169        if ob:
1170            split.template_ID(ob, "active_material", new="material.new")
1171            row = split.row()
1172
1173            if slot:
1174                row.prop(slot, "link", text="")
1175            else:
1176                row.label()
1177        elif mat:
1178            split.template_ID(space, "pin_id")
1179            split.separator()
1180
1181
1182class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
1183    bl_label = "Motion Blur"
1184    bl_context = "object"
1185    bl_options = {'DEFAULT_CLOSED'}
1186
1187    @classmethod
1188    def poll(cls, context):
1189        ob = context.object
1190        if CyclesButtonsPanel.poll(context) and ob:
1191            if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA'}:
1192                return True
1193            if ob.instance_type == 'COLLECTION' and ob.instance_collection:
1194                return True
1195            # TODO(sergey): More duplicator types here?
1196        return False
1197
1198    def draw_header(self, context):
1199        layout = self.layout
1200
1201        rd = context.scene.render
1202        # scene = context.scene
1203
1204        layout.active = rd.use_motion_blur
1205
1206        ob = context.object
1207        cob = ob.cycles
1208
1209        layout.prop(cob, "use_motion_blur", text="")
1210
1211    def draw(self, context):
1212        layout = self.layout
1213        layout.use_property_split = True
1214
1215        rd = context.scene.render
1216        # scene = context.scene
1217
1218        ob = context.object
1219        cob = ob.cycles
1220
1221        layout.active = (rd.use_motion_blur and cob.use_motion_blur)
1222
1223        col = layout.column()
1224        col.prop(cob, "motion_steps", text="Steps")
1225        if ob.type != 'CAMERA':
1226            col.prop(cob, "use_deform_motion", text="Deformation")
1227
1228
1229def has_geometry_visibility(ob):
1230    return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT'}) or
1231                   (ob.instance_type == 'COLLECTION' and ob.instance_collection))
1232
1233
1234class CYCLES_OBJECT_PT_shading(CyclesButtonsPanel, Panel):
1235    bl_label = "Shading"
1236    bl_context = "object"
1237    bl_options = {'DEFAULT_CLOSED'}
1238
1239    @classmethod
1240    def poll(cls, context):
1241        return CyclesButtonsPanel.poll(context) and (context.object)
1242
1243    def draw(self, context):
1244        layout = self.layout
1245        layout.use_property_split = True
1246
1247        flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1248        layout = self.layout
1249        ob = context.object
1250        cob = ob.cycles
1251
1252        if has_geometry_visibility(ob):
1253            col = flow.column()
1254            col.prop(cob, "shadow_terminator_offset")
1255
1256
1257class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
1258    bl_label = "Visibility"
1259    bl_context = "object"
1260    bl_options = {'DEFAULT_CLOSED'}
1261
1262    @classmethod
1263    def poll(cls, context):
1264        return CyclesButtonsPanel.poll(context) and (context.object)
1265
1266    def draw(self, context):
1267        layout = self.layout
1268        layout.use_property_split = True
1269
1270        ob = context.object
1271
1272        layout.prop(ob, "hide_select", text="Selectable", invert_checkbox=True, toggle=False)
1273
1274        col = layout.column(heading="Show in")
1275        col.prop(ob, "hide_viewport", text="Viewports", invert_checkbox=True, toggle=False)
1276        col.prop(ob, "hide_render", text="Renders", invert_checkbox=True, toggle=False)
1277
1278        if has_geometry_visibility(ob):
1279            cob = ob.cycles
1280            col = layout.column(heading="Mask")
1281            col.prop(cob, "is_shadow_catcher")
1282            col.prop(cob, "is_holdout")
1283
1284
1285class CYCLES_OBJECT_PT_visibility_ray_visibility(CyclesButtonsPanel, Panel):
1286    bl_label = "Ray Visibility"
1287    bl_parent_id = "CYCLES_OBJECT_PT_visibility"
1288    bl_context = "object"
1289
1290    @classmethod
1291    def poll(cls, context):
1292        ob = context.object
1293        return CyclesButtonsPanel.poll(context) and has_geometry_visibility(ob)
1294
1295    def draw(self, context):
1296        layout = self.layout
1297        layout.use_property_split = True
1298        layout.use_property_decorate = False
1299
1300        scene = context.scene
1301        ob = context.object
1302        cob = ob.cycles
1303        visibility = ob.cycles_visibility
1304
1305        col = layout.column()
1306        col.prop(visibility, "camera")
1307        col.prop(visibility, "diffuse")
1308        col.prop(visibility, "glossy")
1309        col.prop(visibility, "transmission")
1310        col.prop(visibility, "scatter")
1311
1312        if ob.type != 'LIGHT':
1313            sub = col.column()
1314            sub.prop(visibility, "shadow")
1315
1316
1317class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
1318    bl_label = "Culling"
1319    bl_parent_id = "CYCLES_OBJECT_PT_visibility"
1320    bl_context = "object"
1321
1322    @classmethod
1323    def poll(cls, context):
1324        ob = context.object
1325        return CyclesButtonsPanel.poll(context) and has_geometry_visibility(ob)
1326
1327    def draw(self, context):
1328        layout = self.layout
1329        layout.use_property_split = True
1330        layout.use_property_decorate = False
1331
1332        scene = context.scene
1333        cscene = scene.cycles
1334        ob = context.object
1335        cob = ob.cycles
1336
1337        row = layout.row()
1338        row.active = scene.render.use_simplify and cscene.use_camera_cull
1339        row.prop(cob, "use_camera_cull")
1340
1341        row = layout.row()
1342        row.active = scene.render.use_simplify and cscene.use_distance_cull
1343        row.prop(cob, "use_distance_cull")
1344
1345
1346def panel_node_draw(layout, id_data, output_type, input_name):
1347    if not id_data.use_nodes:
1348        layout.operator("cycles.use_shading_nodes", icon='NODETREE')
1349        return False
1350
1351    ntree = id_data.node_tree
1352
1353    node = ntree.get_output_node('CYCLES')
1354    if node:
1355        input = find_node_input(node, input_name)
1356        if input:
1357            layout.template_node_view(ntree, node, input)
1358        else:
1359            layout.label(text="Incompatible output node")
1360    else:
1361        layout.label(text="No output node")
1362
1363    return True
1364
1365
1366class CYCLES_LIGHT_PT_preview(CyclesButtonsPanel, Panel):
1367    bl_label = "Preview"
1368    bl_context = "data"
1369    bl_options = {'DEFAULT_CLOSED'}
1370
1371    @classmethod
1372    def poll(cls, context):
1373        return (
1374            context.light and
1375            not (
1376                context.light.type == 'AREA' and
1377                context.light.cycles.is_portal
1378            ) and
1379            CyclesButtonsPanel.poll(context)
1380        )
1381
1382    def draw(self, context):
1383        self.layout.template_preview(context.light)
1384
1385
1386class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
1387    bl_label = "Light"
1388    bl_context = "data"
1389
1390    @classmethod
1391    def poll(cls, context):
1392        return context.light and CyclesButtonsPanel.poll(context)
1393
1394    def draw(self, context):
1395        layout = self.layout
1396
1397        light = context.light
1398        clamp = light.cycles
1399
1400        if self.bl_space_type == 'PROPERTIES':
1401            layout.row().prop(light, "type", expand=True)
1402            layout.use_property_split = True
1403        else:
1404            layout.use_property_split = True
1405            layout.row().prop(light, "type")
1406
1407        col = layout.column()
1408
1409        col.prop(light, "color")
1410        col.prop(light, "energy")
1411        col.separator()
1412
1413        if light.type in {'POINT', 'SPOT'}:
1414            col.prop(light, "shadow_soft_size", text="Radius")
1415        elif light.type == 'SUN':
1416            col.prop(light, "angle")
1417        elif light.type == 'AREA':
1418            col.prop(light, "shape", text="Shape")
1419            sub = col.column(align=True)
1420
1421            if light.shape in {'SQUARE', 'DISK'}:
1422                sub.prop(light, "size")
1423            elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
1424                sub.prop(light, "size", text="Size X")
1425                sub.prop(light, "size_y", text="Y")
1426
1427        if not (light.type == 'AREA' and clamp.is_portal):
1428            sub = col.column()
1429            if use_branched_path(context):
1430                subsub = sub.row(align=True)
1431                subsub.active = use_sample_all_lights(context)
1432                subsub.prop(clamp, "samples")
1433            sub.prop(clamp, "max_bounces")
1434
1435        sub = col.column(align=True)
1436        sub.active = not (light.type == 'AREA' and clamp.is_portal)
1437        sub.prop(clamp, "cast_shadow")
1438        sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
1439
1440        if light.type == 'AREA':
1441            col.prop(clamp, "is_portal", text="Portal")
1442
1443
1444class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
1445    bl_label = "Nodes"
1446    bl_context = "data"
1447
1448    @classmethod
1449    def poll(cls, context):
1450        return context.light and not (context.light.type == 'AREA' and
1451                                      context.light.cycles.is_portal) and \
1452            CyclesButtonsPanel.poll(context)
1453
1454    def draw(self, context):
1455        layout = self.layout
1456
1457        layout.use_property_split = True
1458
1459        light = context.light
1460        panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
1461
1462
1463class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
1464    bl_label = "Spot Shape"
1465    bl_context = "data"
1466
1467    @classmethod
1468    def poll(cls, context):
1469        light = context.light
1470        return (light and light.type == 'SPOT') and CyclesButtonsPanel.poll(context)
1471
1472    def draw(self, context):
1473        layout = self.layout
1474        light = context.light
1475        layout.use_property_split = True
1476        layout.use_property_decorate = False
1477
1478        col = layout.column()
1479        col.prop(light, "spot_size", text="Size")
1480        col.prop(light, "spot_blend", text="Blend", slider=True)
1481        col.prop(light, "show_cone")
1482
1483
1484class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel):
1485    bl_label = "Preview"
1486    bl_context = "world"
1487    bl_options = {'DEFAULT_CLOSED'}
1488
1489    @classmethod
1490    def poll(cls, context):
1491        return context.world and CyclesButtonsPanel.poll(context)
1492
1493    def draw(self, context):
1494        self.layout.template_preview(context.world)
1495
1496
1497class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel):
1498    bl_label = "Surface"
1499    bl_context = "world"
1500
1501    @classmethod
1502    def poll(cls, context):
1503        return context.world and CyclesButtonsPanel.poll(context)
1504
1505    def draw(self, context):
1506        layout = self.layout
1507
1508        layout.use_property_split = True
1509
1510        world = context.world
1511
1512        if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
1513            layout.prop(world, "color")
1514
1515
1516class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
1517    bl_label = "Volume"
1518    bl_context = "world"
1519    bl_options = {'DEFAULT_CLOSED'}
1520
1521    @classmethod
1522    def poll(cls, context):
1523        world = context.world
1524        return world and world.node_tree and CyclesButtonsPanel.poll(context)
1525
1526    def draw(self, context):
1527        layout = self.layout
1528
1529        layout.use_property_split = True
1530
1531        world = context.world
1532        panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
1533
1534
1535class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
1536    bl_label = "Ambient Occlusion"
1537    bl_context = "world"
1538    bl_options = {'DEFAULT_CLOSED'}
1539
1540    @classmethod
1541    def poll(cls, context):
1542        return context.world and CyclesButtonsPanel.poll(context)
1543
1544    def draw_header(self, context):
1545        light = context.world.light_settings
1546        self.layout.prop(light, "use_ambient_occlusion", text="")
1547
1548    def draw(self, context):
1549        layout = self.layout
1550        layout.use_property_split = True
1551        layout.use_property_decorate = False
1552
1553        light = context.world.light_settings
1554        scene = context.scene
1555
1556        col = layout.column()
1557        sub = col.column()
1558        sub.active = light.use_ambient_occlusion or scene.render.use_simplify
1559        sub.prop(light, "ao_factor", text="Factor")
1560        col.prop(light, "distance", text="Distance")
1561
1562
1563class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel):
1564    bl_label = "Mist Pass"
1565    bl_context = "world"
1566    bl_options = {'DEFAULT_CLOSED'}
1567
1568    @classmethod
1569    def poll(cls, context):
1570        if CyclesButtonsPanel.poll(context):
1571            if context.world:
1572                for view_layer in context.scene.view_layers:
1573                    if view_layer.use_pass_mist:
1574                        return True
1575
1576        return False
1577
1578    def draw(self, context):
1579        layout = self.layout
1580        layout.use_property_split = True
1581
1582        world = context.world
1583
1584        col = layout.column(align=True)
1585        col.prop(world.mist_settings, "start")
1586        col.prop(world.mist_settings, "depth")
1587
1588        col = layout.column()
1589        col.prop(world.mist_settings, "falloff")
1590
1591
1592class CYCLES_WORLD_PT_ray_visibility(CyclesButtonsPanel, Panel):
1593    bl_label = "Ray Visibility"
1594    bl_context = "world"
1595    bl_options = {'DEFAULT_CLOSED'}
1596
1597    @classmethod
1598    def poll(cls, context):
1599        return CyclesButtonsPanel.poll(context) and context.world
1600
1601    def draw(self, context):
1602        layout = self.layout
1603        layout.use_property_split = True
1604        layout.use_property_decorate = False
1605
1606        world = context.world
1607        visibility = world.cycles_visibility
1608
1609        col = layout.column()
1610        col.prop(visibility, "camera")
1611        col.prop(visibility, "diffuse")
1612        col.prop(visibility, "glossy")
1613        col.prop(visibility, "transmission")
1614        col.prop(visibility, "scatter")
1615
1616
1617class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel):
1618    bl_label = "Settings"
1619    bl_context = "world"
1620    bl_options = {'DEFAULT_CLOSED'}
1621
1622    @classmethod
1623    def poll(cls, context):
1624        return context.world and CyclesButtonsPanel.poll(context)
1625
1626    def draw(self, context):
1627        layout = self.layout
1628        layout.use_property_split = True
1629        layout.use_property_decorate = False
1630
1631        layout.column()
1632
1633
1634class CYCLES_WORLD_PT_settings_surface(CyclesButtonsPanel, Panel):
1635    bl_label = "Surface"
1636    bl_parent_id = "CYCLES_WORLD_PT_settings"
1637    bl_context = "world"
1638
1639    @classmethod
1640    def poll(cls, context):
1641        return context.world and CyclesButtonsPanel.poll(context)
1642
1643    def draw(self, context):
1644        layout = self.layout
1645        layout.use_property_split = True
1646        layout.use_property_decorate = False
1647
1648        world = context.world
1649        cworld = world.cycles
1650
1651        col = layout.column()
1652        col.prop(cworld, "sampling_method", text="Sampling")
1653
1654        sub = col.column()
1655        sub.active = cworld.sampling_method != 'NONE'
1656        subsub = sub.row(align=True)
1657        subsub.active = cworld.sampling_method == 'MANUAL'
1658        subsub.prop(cworld, "sample_map_resolution")
1659        if use_branched_path(context):
1660            subsub = sub.column(align=True)
1661            subsub.active = use_sample_all_lights(context)
1662            subsub.prop(cworld, "samples")
1663        sub.prop(cworld, "max_bounces")
1664
1665
1666class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel):
1667    bl_label = "Volume"
1668    bl_parent_id = "CYCLES_WORLD_PT_settings"
1669    bl_context = "world"
1670
1671    @classmethod
1672    def poll(cls, context):
1673        return context.world and CyclesButtonsPanel.poll(context)
1674
1675    def draw(self, context):
1676        layout = self.layout
1677        layout.use_property_split = True
1678        layout.use_property_decorate = False
1679
1680        world = context.world
1681        cworld = world.cycles
1682
1683        col = layout.column()
1684
1685        sub = col.column()
1686        sub.active = use_cpu(context)
1687        sub.prop(cworld, "volume_sampling", text="Sampling")
1688        col.prop(cworld, "volume_interpolation", text="Interpolation")
1689        col.prop(cworld, "homogeneous_volume", text="Homogeneous")
1690        sub = col.column()
1691        sub.active = not cworld.homogeneous_volume
1692        sub.prop(cworld, "volume_step_size")
1693
1694
1695class CYCLES_MATERIAL_PT_preview(CyclesButtonsPanel, Panel):
1696    bl_label = "Preview"
1697    bl_context = "material"
1698    bl_options = {'DEFAULT_CLOSED'}
1699
1700    @classmethod
1701    def poll(cls, context):
1702        mat = context.material
1703        return mat and (not mat.grease_pencil) and CyclesButtonsPanel.poll(context)
1704
1705    def draw(self, context):
1706        self.layout.template_preview(context.material)
1707
1708
1709class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel):
1710    bl_label = "Surface"
1711    bl_context = "material"
1712
1713    @classmethod
1714    def poll(cls, context):
1715        mat = context.material
1716        return mat and (not mat.grease_pencil) and CyclesButtonsPanel.poll(context)
1717
1718    def draw(self, context):
1719        layout = self.layout
1720
1721        layout.use_property_split = True
1722
1723        mat = context.material
1724        if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
1725            layout.prop(mat, "diffuse_color")
1726
1727
1728class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel):
1729    bl_label = "Volume"
1730    bl_context = "material"
1731    bl_options = {'DEFAULT_CLOSED'}
1732
1733    @classmethod
1734    def poll(cls, context):
1735        mat = context.material
1736        return mat and (not mat.grease_pencil) and mat.node_tree and CyclesButtonsPanel.poll(context)
1737
1738    def draw(self, context):
1739        layout = self.layout
1740
1741        layout.use_property_split = True
1742
1743        mat = context.material
1744        # cmat = mat.cycles
1745
1746        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
1747
1748
1749class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel):
1750    bl_label = "Displacement"
1751    bl_context = "material"
1752
1753    @classmethod
1754    def poll(cls, context):
1755        mat = context.material
1756        return mat and (not mat.grease_pencil) and mat.node_tree and CyclesButtonsPanel.poll(context)
1757
1758    def draw(self, context):
1759        layout = self.layout
1760
1761        layout.use_property_split = True
1762
1763        mat = context.material
1764        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
1765
1766
1767class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel):
1768    bl_label = "Settings"
1769    bl_context = "material"
1770    bl_options = {'DEFAULT_CLOSED'}
1771
1772    @classmethod
1773    def poll(cls, context):
1774        mat = context.material
1775        return mat and (not mat.grease_pencil) and CyclesButtonsPanel.poll(context)
1776
1777    @staticmethod
1778    def draw_shared(self, mat):
1779        layout = self.layout
1780        layout.use_property_split = True
1781        layout.use_property_decorate = False
1782
1783        layout.prop(mat, "pass_index")
1784
1785    def draw(self, context):
1786        self.draw_shared(self, context.material)
1787
1788
1789class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel):
1790    bl_label = "Surface"
1791    bl_parent_id = "CYCLES_MATERIAL_PT_settings"
1792    bl_context = "material"
1793
1794    @staticmethod
1795    def draw_shared(self, mat):
1796        layout = self.layout
1797        layout.use_property_split = True
1798        layout.use_property_decorate = False
1799
1800        cmat = mat.cycles
1801
1802        col = layout.column()
1803        col.prop(cmat, "sample_as_light", text="Multiple Importance")
1804        col.prop(cmat, "use_transparent_shadow")
1805        col.prop(cmat, "displacement_method", text="Displacement")
1806
1807    def draw(self, context):
1808        self.draw_shared(self, context.material)
1809
1810
1811class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel):
1812    bl_label = "Volume"
1813    bl_parent_id = "CYCLES_MATERIAL_PT_settings"
1814    bl_context = "material"
1815
1816    @staticmethod
1817    def draw_shared(self, context, mat):
1818        layout = self.layout
1819        layout.use_property_split = True
1820        layout.use_property_decorate = False
1821
1822        cmat = mat.cycles
1823
1824        col = layout.column()
1825        sub = col.column()
1826        sub.active = use_cpu(context)
1827        sub.prop(cmat, "volume_sampling", text="Sampling")
1828        col.prop(cmat, "volume_interpolation", text="Interpolation")
1829        col.prop(cmat, "homogeneous_volume", text="Homogeneous")
1830        sub = col.column()
1831        sub.active = not cmat.homogeneous_volume
1832        sub.prop(cmat, "volume_step_rate")
1833
1834    def draw(self, context):
1835        self.draw_shared(self, context, context.material)
1836
1837
1838class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
1839    bl_label = "Bake"
1840    bl_context = "render"
1841    bl_options = {'DEFAULT_CLOSED'}
1842    COMPAT_ENGINES = {'CYCLES'}
1843
1844    @classmethod
1845    def poll(cls, context):
1846        return CyclesButtonsPanel.poll(context) and not use_optix(context)
1847
1848    def draw(self, context):
1849        layout = self.layout
1850        layout.use_property_split = True
1851        layout.use_property_decorate = False  # No animation.
1852
1853        scene = context.scene
1854        cscene = scene.cycles
1855        cbk = scene.render.bake
1856        rd = scene.render
1857
1858        if rd.use_bake_multires:
1859            layout.operator("object.bake_image", icon='RENDER_STILL')
1860            layout.prop(rd, "use_bake_multires")
1861            layout.prop(rd, "bake_type")
1862
1863        else:
1864            layout.operator("object.bake", icon='RENDER_STILL').type = cscene.bake_type
1865            layout.prop(rd, "use_bake_multires")
1866            layout.prop(cscene, "bake_type")
1867
1868
1869class CYCLES_RENDER_PT_bake_influence(CyclesButtonsPanel, Panel):
1870    bl_label = "Influence"
1871    bl_context = "render"
1872    bl_parent_id = "CYCLES_RENDER_PT_bake"
1873    COMPAT_ENGINES = {'CYCLES'}
1874
1875    @classmethod
1876    def poll(cls, context):
1877        scene = context.scene
1878        cscene = scene.cycles
1879        rd = scene.render
1880        if rd.use_bake_multires == False and cscene.bake_type in {
1881                'NORMAL', 'COMBINED', 'DIFFUSE', 'GLOSSY', 'TRANSMISSION'}:
1882            return True
1883
1884    def draw(self, context):
1885        layout = self.layout
1886        layout.use_property_split = True
1887        layout.use_property_decorate = False  # No animation.
1888
1889        scene = context.scene
1890        cscene = scene.cycles
1891        cbk = scene.render.bake
1892        rd = scene.render
1893
1894        col = layout.column()
1895
1896        if cscene.bake_type == 'NORMAL':
1897            col.prop(cbk, "normal_space", text="Space")
1898
1899            sub = col.column(align=True)
1900            sub.prop(cbk, "normal_r", text="Swizzle R")
1901            sub.prop(cbk, "normal_g", text="G")
1902            sub.prop(cbk, "normal_b", text="B")
1903
1904        elif cscene.bake_type == 'COMBINED':
1905
1906            col = layout.column(heading="Lighting", align=True)
1907            col.prop(cbk, "use_pass_direct")
1908            col.prop(cbk, "use_pass_indirect")
1909
1910            col = layout.column(heading="Contributions", align=True)
1911            col.active = cbk.use_pass_direct or cbk.use_pass_indirect
1912            col.prop(cbk, "use_pass_diffuse")
1913            col.prop(cbk, "use_pass_glossy")
1914            col.prop(cbk, "use_pass_transmission")
1915            col.prop(cbk, "use_pass_ambient_occlusion")
1916            col.prop(cbk, "use_pass_emit")
1917
1918        elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION'}:
1919            col = layout.column(heading="Contributions", align=True)
1920            col.prop(cbk, "use_pass_direct")
1921            col.prop(cbk, "use_pass_indirect")
1922            col.prop(cbk, "use_pass_color")
1923
1924
1925class CYCLES_RENDER_PT_bake_selected_to_active(CyclesButtonsPanel, Panel):
1926    bl_label = "Selected to Active"
1927    bl_context = "render"
1928    bl_parent_id = "CYCLES_RENDER_PT_bake"
1929    bl_options = {'DEFAULT_CLOSED'}
1930    COMPAT_ENGINES = {'CYCLES'}
1931
1932    @classmethod
1933    def poll(cls, context):
1934        scene = context.scene
1935        rd = scene.render
1936        return rd.use_bake_multires == False
1937
1938    def draw_header(self, context):
1939        scene = context.scene
1940        cbk = scene.render.bake
1941        self.layout.prop(cbk, "use_selected_to_active", text="")
1942
1943    def draw(self, context):
1944        layout = self.layout
1945        layout.use_property_split = True
1946        layout.use_property_decorate = False  # No animation.
1947
1948        scene = context.scene
1949        cscene = scene.cycles
1950        cbk = scene.render.bake
1951        rd = scene.render
1952
1953        layout.active = cbk.use_selected_to_active
1954        col = layout.column()
1955
1956        col.prop(cbk, "use_cage", text="Cage")
1957        if cbk.use_cage:
1958            col.prop(cbk, "cage_object")
1959            col = layout.column()
1960            col.prop(cbk, "cage_extrusion")
1961            col.active = cbk.cage_object is None
1962        else:
1963            col.prop(cbk, "cage_extrusion", text="Extrusion")
1964
1965        col = layout.column()
1966        col.prop(cbk, "max_ray_distance")
1967
1968
1969class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
1970    bl_label = "Output"
1971    bl_context = "render"
1972    bl_parent_id = "CYCLES_RENDER_PT_bake"
1973    COMPAT_ENGINES = {'CYCLES'}
1974
1975    def draw(self, context):
1976        layout = self.layout
1977        layout.use_property_split = True
1978        layout.use_property_decorate = False  # No animation.
1979
1980        scene = context.scene
1981        cscene = scene.cycles
1982        cbk = scene.render.bake
1983        rd = scene.render
1984
1985        if rd.use_bake_multires:
1986            layout.prop(rd, "bake_margin")
1987            layout.prop(rd, "use_bake_clear", text="Clear Image")
1988
1989            if rd.bake_type == 'DISPLACEMENT':
1990                layout.prop(rd, "use_bake_lores_mesh")
1991        else:
1992
1993            layout.prop(cbk, "margin")
1994            layout.prop(cbk, "use_clear", text="Clear Image")
1995
1996
1997class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
1998    bl_label = "Debug"
1999    bl_context = "render"
2000    bl_options = {'DEFAULT_CLOSED'}
2001    COMPAT_ENGINES = {'CYCLES'}
2002
2003    @classmethod
2004    def poll(cls, context):
2005        prefs = bpy.context.preferences
2006        return (CyclesButtonsPanel.poll(context)
2007                and prefs.experimental.use_cycles_debug
2008                and prefs.view.show_developer_ui)
2009
2010    def draw(self, context):
2011        layout = self.layout
2012
2013        scene = context.scene
2014        cscene = scene.cycles
2015
2016        col = layout.column()
2017
2018        col.label(text="CPU Flags:")
2019        row = col.row(align=True)
2020        row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
2021        row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
2022        row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
2023        row.prop(cscene, "debug_use_cpu_avx", toggle=True)
2024        row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
2025        col.prop(cscene, "debug_bvh_layout")
2026        col.prop(cscene, "debug_use_cpu_split_kernel")
2027
2028        col.separator()
2029
2030        col = layout.column()
2031        col.label(text="CUDA Flags:")
2032        col.prop(cscene, "debug_use_cuda_adaptive_compile")
2033        col.prop(cscene, "debug_use_cuda_split_kernel")
2034
2035        col.separator()
2036
2037        col = layout.column()
2038        col.label(text="OptiX Flags:")
2039        col.prop(cscene, "debug_optix_cuda_streams")
2040        col.prop(cscene, "debug_optix_curves_api")
2041
2042        col.separator()
2043
2044        col = layout.column()
2045        col.label(text="OpenCL Flags:")
2046        col.prop(cscene, "debug_opencl_device_type", text="Device")
2047        col.prop(cscene, "debug_use_opencl_debug", text="Debug")
2048        col.prop(cscene, "debug_opencl_mem_limit")
2049
2050        col.separator()
2051
2052        col = layout.column()
2053        col.prop(cscene, "debug_bvh_type")
2054
2055
2056class CYCLES_RENDER_PT_simplify(CyclesButtonsPanel, Panel):
2057    bl_label = "Simplify"
2058    bl_context = "render"
2059    bl_options = {'DEFAULT_CLOSED'}
2060    COMPAT_ENGINES = {'CYCLES'}
2061
2062    def draw_header(self, context):
2063        rd = context.scene.render
2064        self.layout.prop(rd, "use_simplify", text="")
2065
2066    def draw(self, context):
2067        pass
2068
2069
2070class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
2071    bl_label = "Viewport"
2072    bl_context = "render"
2073    bl_parent_id = "CYCLES_RENDER_PT_simplify"
2074    COMPAT_ENGINES = {'CYCLES'}
2075
2076    def draw(self, context):
2077        layout = self.layout
2078        layout.use_property_split = True
2079        layout.use_property_decorate = False
2080
2081        scene = context.scene
2082        rd = scene.render
2083        cscene = scene.cycles
2084
2085        layout.active = rd.use_simplify
2086
2087        col = layout.column()
2088        col.prop(rd, "simplify_subdivision", text="Max Subdivision")
2089        col.prop(rd, "simplify_child_particles", text="Child Particles")
2090        col.prop(cscene, "texture_limit", text="Texture Limit")
2091        col.prop(cscene, "ao_bounces", text="AO Bounces")
2092        col.prop(rd, "simplify_volumes", text="Volume Resolution")
2093
2094
2095class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):
2096    bl_label = "Render"
2097    bl_context = "render"
2098    bl_parent_id = "CYCLES_RENDER_PT_simplify"
2099    COMPAT_ENGINES = {'CYCLES'}
2100
2101    def draw(self, context):
2102        layout = self.layout
2103        layout.use_property_split = True
2104        layout.use_property_decorate = False
2105
2106        scene = context.scene
2107        rd = scene.render
2108        cscene = scene.cycles
2109
2110        layout.active = rd.use_simplify
2111
2112        col = layout.column()
2113
2114        col.prop(rd, "simplify_subdivision_render", text="Max Subdivision")
2115        col.prop(rd, "simplify_child_particles_render", text="Child Particles")
2116        col.prop(cscene, "texture_limit_render", text="Texture Limit")
2117        col.prop(cscene, "ao_bounces_render", text="AO Bounces")
2118
2119
2120class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
2121    bl_label = "Culling"
2122    bl_context = "render"
2123    bl_parent_id = "CYCLES_RENDER_PT_simplify"
2124    bl_options = {'DEFAULT_CLOSED'}
2125    COMPAT_ENGINES = {'CYCLES'}
2126
2127    def draw(self, context):
2128        layout = self.layout
2129        layout.use_property_split = True
2130        layout.use_property_decorate = False
2131
2132        scene = context.scene
2133        rd = scene.render
2134        cscene = scene.cycles
2135
2136        layout.active = rd.use_simplify
2137
2138        row = layout.row(heading="Camera Culling")
2139        row.prop(cscene, "use_camera_cull", text="")
2140        sub = row.column()
2141        sub.active = cscene.use_camera_cull
2142        sub.prop(cscene, "camera_cull_margin", text="")
2143
2144        row = layout.row(heading="Distance Culling")
2145        row.prop(cscene, "use_distance_cull", text="")
2146        sub = row.column()
2147        sub.active = cscene.use_distance_cull
2148        sub.prop(cscene, "distance_cull_margin", text="")
2149
2150
2151class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
2152    bl_space_type = 'VIEW_3D'
2153    bl_region_type = 'HEADER'
2154    bl_label = "Render Pass"
2155    bl_parent_id = 'VIEW3D_PT_shading'
2156    COMPAT_ENGINES = {'CYCLES'}
2157
2158    @classmethod
2159    def poll(cls, context):
2160        return (
2161            context.engine in cls.COMPAT_ENGINES and
2162            context.space_data.shading.type == 'RENDERED'
2163        )
2164
2165    def draw(self, context):
2166        shading = context.space_data.shading
2167
2168        layout = self.layout
2169        layout.prop(shading.cycles, "render_pass", text="")
2170
2171
2172class CYCLES_VIEW3D_PT_shading_lighting(Panel):
2173    bl_space_type = 'VIEW_3D'
2174    bl_region_type = 'HEADER'
2175    bl_label = "Lighting"
2176    bl_parent_id = 'VIEW3D_PT_shading'
2177    COMPAT_ENGINES = {'CYCLES'}
2178
2179    @classmethod
2180    def poll(cls, context):
2181        return (
2182            context.engine in cls.COMPAT_ENGINES and
2183            context.space_data.shading.type == 'RENDERED'
2184        )
2185
2186    def draw(self, context):
2187        layout = self.layout
2188        col = layout.column()
2189        split = col.split(factor=0.9)
2190
2191        shading = context.space_data.shading
2192        col.prop(shading, "use_scene_lights_render")
2193        col.prop(shading, "use_scene_world_render")
2194
2195        if not shading.use_scene_world_render:
2196            col = layout.column()
2197            split = col.split(factor=0.9)
2198
2199            col = split.column()
2200            sub = col.row()
2201            sub.scale_y = 0.6
2202            sub.template_icon_view(shading, "studio_light", scale_popup=3)
2203
2204            col = split.column()
2205            col.operator("preferences.studiolight_show", emboss=False, text="", icon='PREFERENCES')
2206
2207            split = layout.split(factor=0.9)
2208            col = split.column()
2209            col.prop(shading, "studiolight_rotate_z", text="Rotation")
2210            col.prop(shading, "studiolight_intensity")
2211            col.prop(shading, "studiolight_background_alpha")
2212
2213
2214class CYCLES_VIEW3D_PT_simplify_greasepencil(CyclesButtonsPanel, Panel, GreasePencilSimplifyPanel):
2215    bl_label = "Grease Pencil"
2216    bl_parent_id = "CYCLES_RENDER_PT_simplify"
2217    COMPAT_ENGINES = {'CYCLES'}
2218    bl_options = {'DEFAULT_CLOSED'}
2219
2220
2221def draw_device(self, context):
2222    scene = context.scene
2223    layout = self.layout
2224    layout.use_property_split = True
2225    layout.use_property_decorate = False
2226
2227    if context.engine == 'CYCLES':
2228        from . import engine
2229        cscene = scene.cycles
2230
2231        col = layout.column()
2232        col.prop(cscene, "feature_set")
2233
2234        col = layout.column()
2235        col.active = show_device_active(context)
2236        col.prop(cscene, "device")
2237
2238        from . import engine
2239        if engine.with_osl() and use_cpu(context):
2240            col.prop(cscene, "shading_system")
2241
2242
2243def draw_pause(self, context):
2244    layout = self.layout
2245    scene = context.scene
2246
2247    if context.engine == "CYCLES":
2248        view = context.space_data
2249
2250        if view.shading.type == 'RENDERED':
2251            cscene = scene.cycles
2252            layout.prop(cscene, "preview_pause", icon='PLAY' if cscene.preview_pause else 'PAUSE', text="")
2253
2254
2255def get_panels():
2256    exclude_panels = {
2257        'DATA_PT_area',
2258        'DATA_PT_camera_dof',
2259        'DATA_PT_falloff_curve',
2260        'DATA_PT_light',
2261        'DATA_PT_preview',
2262        'DATA_PT_spot',
2263        'MATERIAL_PT_context_material',
2264        'MATERIAL_PT_preview',
2265        'NODE_DATA_PT_light',
2266        'NODE_DATA_PT_spot',
2267        'OBJECT_PT_visibility',
2268        'VIEWLAYER_PT_filter',
2269        'VIEWLAYER_PT_layer_passes',
2270        'RENDER_PT_post_processing',
2271        'RENDER_PT_simplify',
2272    }
2273
2274    panels = []
2275    for panel in bpy.types.Panel.__subclasses__():
2276        if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
2277            if panel.__name__ not in exclude_panels:
2278                panels.append(panel)
2279
2280    return panels
2281
2282
2283classes = (
2284    CYCLES_PT_sampling_presets,
2285    CYCLES_PT_integrator_presets,
2286    CYCLES_RENDER_PT_sampling,
2287    CYCLES_RENDER_PT_sampling_sub_samples,
2288    CYCLES_RENDER_PT_sampling_adaptive,
2289    CYCLES_RENDER_PT_sampling_denoising,
2290    CYCLES_RENDER_PT_sampling_advanced,
2291    CYCLES_RENDER_PT_light_paths,
2292    CYCLES_RENDER_PT_light_paths_max_bounces,
2293    CYCLES_RENDER_PT_light_paths_clamping,
2294    CYCLES_RENDER_PT_light_paths_caustics,
2295    CYCLES_RENDER_PT_volumes,
2296    CYCLES_RENDER_PT_subdivision,
2297    CYCLES_RENDER_PT_hair,
2298    CYCLES_RENDER_PT_simplify,
2299    CYCLES_RENDER_PT_simplify_viewport,
2300    CYCLES_RENDER_PT_simplify_render,
2301    CYCLES_RENDER_PT_simplify_culling,
2302    CYCLES_VIEW3D_PT_simplify_greasepencil,
2303    CYCLES_VIEW3D_PT_shading_lighting,
2304    CYCLES_VIEW3D_PT_shading_render_pass,
2305    CYCLES_RENDER_PT_motion_blur,
2306    CYCLES_RENDER_PT_motion_blur_curve,
2307    CYCLES_RENDER_PT_film,
2308    CYCLES_RENDER_PT_film_pixel_filter,
2309    CYCLES_RENDER_PT_film_transparency,
2310    CYCLES_RENDER_PT_performance,
2311    CYCLES_RENDER_PT_performance_threads,
2312    CYCLES_RENDER_PT_performance_tiles,
2313    CYCLES_RENDER_PT_performance_acceleration_structure,
2314    CYCLES_RENDER_PT_performance_final_render,
2315    CYCLES_RENDER_PT_performance_viewport,
2316    CYCLES_RENDER_PT_passes,
2317    CYCLES_RENDER_PT_passes_data,
2318    CYCLES_RENDER_PT_passes_light,
2319    CYCLES_RENDER_PT_passes_crypto,
2320    CYCLES_RENDER_PT_passes_debug,
2321    CYCLES_RENDER_UL_aov,
2322    CYCLES_RENDER_PT_passes_aov,
2323    CYCLES_RENDER_PT_filter,
2324    CYCLES_RENDER_PT_override,
2325    CYCLES_RENDER_PT_denoising,
2326    CYCLES_PT_post_processing,
2327    CYCLES_CAMERA_PT_dof,
2328    CYCLES_CAMERA_PT_dof_aperture,
2329    CYCLES_PT_context_material,
2330    CYCLES_OBJECT_PT_motion_blur,
2331    CYCLES_OBJECT_PT_shading,
2332    CYCLES_OBJECT_PT_visibility,
2333    CYCLES_OBJECT_PT_visibility_ray_visibility,
2334    CYCLES_OBJECT_PT_visibility_culling,
2335    CYCLES_LIGHT_PT_preview,
2336    CYCLES_LIGHT_PT_light,
2337    CYCLES_LIGHT_PT_nodes,
2338    CYCLES_LIGHT_PT_spot,
2339    CYCLES_WORLD_PT_preview,
2340    CYCLES_WORLD_PT_surface,
2341    CYCLES_WORLD_PT_volume,
2342    CYCLES_WORLD_PT_ambient_occlusion,
2343    CYCLES_WORLD_PT_mist,
2344    CYCLES_WORLD_PT_ray_visibility,
2345    CYCLES_WORLD_PT_settings,
2346    CYCLES_WORLD_PT_settings_surface,
2347    CYCLES_WORLD_PT_settings_volume,
2348    CYCLES_MATERIAL_PT_preview,
2349    CYCLES_MATERIAL_PT_surface,
2350    CYCLES_MATERIAL_PT_volume,
2351    CYCLES_MATERIAL_PT_displacement,
2352    CYCLES_MATERIAL_PT_settings,
2353    CYCLES_MATERIAL_PT_settings_surface,
2354    CYCLES_MATERIAL_PT_settings_volume,
2355    CYCLES_RENDER_PT_bake,
2356    CYCLES_RENDER_PT_bake_influence,
2357    CYCLES_RENDER_PT_bake_selected_to_active,
2358    CYCLES_RENDER_PT_bake_output,
2359    CYCLES_RENDER_PT_debug,
2360    node_panel(CYCLES_MATERIAL_PT_settings),
2361    node_panel(CYCLES_MATERIAL_PT_settings_surface),
2362    node_panel(CYCLES_MATERIAL_PT_settings_volume),
2363    node_panel(CYCLES_WORLD_PT_ray_visibility),
2364    node_panel(CYCLES_WORLD_PT_settings),
2365    node_panel(CYCLES_WORLD_PT_settings_surface),
2366    node_panel(CYCLES_WORLD_PT_settings_volume),
2367    node_panel(CYCLES_LIGHT_PT_light),
2368    node_panel(CYCLES_LIGHT_PT_spot),
2369)
2370
2371
2372def register():
2373    from bpy.utils import register_class
2374
2375    bpy.types.RENDER_PT_context.append(draw_device)
2376    bpy.types.VIEW3D_HT_header.append(draw_pause)
2377
2378    for panel in get_panels():
2379        panel.COMPAT_ENGINES.add('CYCLES')
2380
2381    for cls in classes:
2382        register_class(cls)
2383
2384
2385def unregister():
2386    from bpy.utils import unregister_class
2387
2388    bpy.types.RENDER_PT_context.remove(draw_device)
2389    bpy.types.VIEW3D_HT_header.remove(draw_pause)
2390
2391    for panel in get_panels():
2392        if 'CYCLES' in panel.COMPAT_ENGINES:
2393            panel.COMPAT_ENGINES.remove('CYCLES')
2394
2395    for cls in classes:
2396        unregister_class(cls)
2397