properties_data_light.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. import bpy
  20. from bpy.types import Panel
  21. from rna_prop_ui import PropertyPanel
  22. class DataButtonsPanel:
  23. bl_space_type = 'PROPERTIES'
  24. bl_region_type = 'WINDOW'
  25. bl_context = "data"
  26. @classmethod
  27. def poll(cls, context):
  28. engine = context.engine
  29. return context.light and (engine in cls.COMPAT_ENGINES)
  30. class DATA_PT_context_light(DataButtonsPanel, Panel):
  31. bl_label = ""
  32. bl_options = {'HIDE_HEADER'}
  33. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  34. def draw(self, context):
  35. layout = self.layout
  36. ob = context.object
  37. light = context.light
  38. space = context.space_data
  39. if ob:
  40. layout.template_ID(ob, "data")
  41. elif light:
  42. layout.template_ID(space, "pin_id")
  43. class DATA_PT_preview(DataButtonsPanel, Panel):
  44. bl_label = "Preview"
  45. bl_options = {'DEFAULT_CLOSED'}
  46. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  47. def draw(self, context):
  48. self.layout.template_preview(context.light)
  49. class DATA_PT_light(DataButtonsPanel, Panel):
  50. bl_label = "Light"
  51. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_WORKBENCH'}
  52. def draw(self, context):
  53. layout = self.layout
  54. light = context.light
  55. # Compact layout for node editor.
  56. if self.bl_space_type == 'PROPERTIES':
  57. layout.row().prop(light, "type", expand=True)
  58. layout.use_property_split = True
  59. else:
  60. layout.use_property_split = True
  61. layout.row().prop(light, "type")
  62. class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
  63. bl_label = "Light"
  64. COMPAT_ENGINES = {'BLENDER_EEVEE'}
  65. def draw(self, context):
  66. layout = self.layout
  67. light = context.light
  68. # Compact layout for node editor.
  69. if self.bl_space_type == 'PROPERTIES':
  70. layout.row().prop(light, "type", expand=True)
  71. layout.use_property_split = True
  72. else:
  73. layout.use_property_split = True
  74. layout.row().prop(light, "type")
  75. col = layout.column()
  76. col.prop(light, "color")
  77. col.prop(light, "energy")
  78. col.prop(light, "specular_factor", text="Specular")
  79. col.separator()
  80. if light.type in {'POINT', 'SPOT'}:
  81. col.prop(light, "shadow_soft_size", text="Radius")
  82. elif light.type == 'SUN':
  83. col.prop(light, "angle")
  84. elif light.type == 'AREA':
  85. col.prop(light, "shape")
  86. sub = col.column(align=True)
  87. if light.shape in {'SQUARE', 'DISK'}:
  88. sub.prop(light, "size")
  89. elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
  90. sub.prop(light, "size", text="Size X")
  91. sub.prop(light, "size_y", text="Y")
  92. class DATA_PT_EEVEE_light_distance(DataButtonsPanel, Panel):
  93. bl_label = "Custom Distance"
  94. bl_parent_id = "DATA_PT_EEVEE_light"
  95. bl_options = {'DEFAULT_CLOSED'}
  96. COMPAT_ENGINES = {'BLENDER_EEVEE'}
  97. @classmethod
  98. def poll(cls, context):
  99. light = context.light
  100. engine = context.engine
  101. return (light and light.type != 'SUN') and (engine in cls.COMPAT_ENGINES)
  102. def draw_header(self, context):
  103. light = context.light
  104. layout = self.layout
  105. layout.active = light.use_shadow
  106. layout.prop(light, "use_custom_distance", text="")
  107. def draw(self, context):
  108. layout = self.layout
  109. light = context.light
  110. layout.use_property_split = True
  111. col = layout.column()
  112. col.prop(light, "cutoff_distance", text="Distance")
  113. class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
  114. bl_label = "Shadow"
  115. bl_options = {'DEFAULT_CLOSED'}
  116. COMPAT_ENGINES = {'BLENDER_EEVEE'}
  117. @classmethod
  118. def poll(cls, context):
  119. light = context.light
  120. engine = context.engine
  121. return (
  122. (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and
  123. (engine in cls.COMPAT_ENGINES)
  124. )
  125. def draw_header(self, context):
  126. light = context.light
  127. self.layout.prop(light, "use_shadow", text="")
  128. def draw(self, context):
  129. layout = self.layout
  130. layout.use_property_split = True
  131. light = context.light
  132. layout.active = light.use_shadow
  133. col = layout.column()
  134. sub = col.column(align=True)
  135. sub.prop(light, "shadow_buffer_clip_start", text="Clip Start")
  136. if light.type == 'SUN':
  137. sub.prop(light, "shadow_buffer_clip_end", text="End")
  138. col.prop(light, "shadow_buffer_soft", text="Softness")
  139. col.separator()
  140. col.prop(light, "shadow_buffer_bias", text="Bias")
  141. col.prop(light, "shadow_buffer_exp", text="Exponent")
  142. col.prop(light, "shadow_buffer_bleed_bias", text="Bleed Bias")
  143. class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel):
  144. bl_label = "Cascaded Shadow Map"
  145. bl_parent_id = "DATA_PT_EEVEE_shadow"
  146. bl_options = {'DEFAULT_CLOSED'}
  147. COMPAT_ENGINES = {'BLENDER_EEVEE'}
  148. @classmethod
  149. def poll(cls, context):
  150. light = context.light
  151. engine = context.engine
  152. return (light and light.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
  153. def draw(self, context):
  154. layout = self.layout
  155. light = context.light
  156. layout.use_property_split = True
  157. col = layout.column()
  158. col.prop(light, "shadow_cascade_count", text="Count")
  159. col.prop(light, "shadow_cascade_fade", text="Fade")
  160. col.prop(light, "shadow_cascade_max_distance", text="Max Distance")
  161. col.prop(light, "shadow_cascade_exponent", text="Distribution")
  162. class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel):
  163. bl_label = "Contact Shadows"
  164. bl_parent_id = "DATA_PT_EEVEE_shadow"
  165. COMPAT_ENGINES = {'BLENDER_EEVEE'}
  166. @classmethod
  167. def poll(cls, context):
  168. light = context.light
  169. engine = context.engine
  170. return (
  171. (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and
  172. (engine in cls.COMPAT_ENGINES)
  173. )
  174. def draw_header(self, context):
  175. light = context.light
  176. layout = self.layout
  177. layout.active = light.use_shadow
  178. layout.prop(light, "use_contact_shadow", text="")
  179. def draw(self, context):
  180. layout = self.layout
  181. light = context.light
  182. layout.use_property_split = True
  183. col = layout.column()
  184. col.active = light.use_shadow and light.use_contact_shadow
  185. col.prop(light, "contact_shadow_distance", text="Distance")
  186. col.prop(light, "contact_shadow_soft_size", text="Softness")
  187. col.prop(light, "contact_shadow_bias", text="Bias")
  188. col.prop(light, "contact_shadow_thickness", text="Thickness")
  189. class DATA_PT_area(DataButtonsPanel, Panel):
  190. bl_label = "Area Shape"
  191. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_WORKBENCH'}
  192. @classmethod
  193. def poll(cls, context):
  194. light = context.light
  195. engine = context.engine
  196. return (light and light.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
  197. def draw(self, context):
  198. layout = self.layout
  199. light = context.light
  200. col = layout.column()
  201. col.row().prop(light, "shape", expand=True)
  202. sub = col.row(align=True)
  203. if light.shape in {'SQUARE', 'DISK'}:
  204. sub.prop(light, "size")
  205. elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
  206. sub.prop(light, "size", text="Size X")
  207. sub.prop(light, "size_y", text="Size Y")
  208. class DATA_PT_spot(DataButtonsPanel, Panel):
  209. bl_label = "Spot Shape"
  210. bl_parent_id = "DATA_PT_EEVEE_light"
  211. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  212. @classmethod
  213. def poll(cls, context):
  214. light = context.light
  215. engine = context.engine
  216. return (light and light.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
  217. def draw(self, context):
  218. layout = self.layout
  219. layout.use_property_split = True
  220. light = context.light
  221. col = layout.column()
  222. col.prop(light, "spot_size", text="Size")
  223. col.prop(light, "spot_blend", text="Blend", slider=True)
  224. col.prop(light, "show_cone")
  225. class DATA_PT_falloff_curve(DataButtonsPanel, Panel):
  226. bl_label = "Falloff Curve"
  227. bl_options = {'DEFAULT_CLOSED'}
  228. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  229. @classmethod
  230. def poll(cls, context):
  231. light = context.light
  232. engine = context.engine
  233. return (
  234. (light and light.type in {'POINT', 'SPOT'} and light.falloff_type == 'CUSTOM_CURVE') and
  235. (engine in cls.COMPAT_ENGINES)
  236. )
  237. def draw(self, context):
  238. light = context.light
  239. self.layout.template_curve_mapping(light, "falloff_curve", use_negative_slope=True)
  240. class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel):
  241. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  242. _context_path = "object.data"
  243. _property_type = bpy.types.Light
  244. classes = (
  245. DATA_PT_context_light,
  246. DATA_PT_preview,
  247. DATA_PT_light,
  248. DATA_PT_EEVEE_light,
  249. DATA_PT_EEVEE_light_distance,
  250. DATA_PT_EEVEE_shadow,
  251. DATA_PT_EEVEE_shadow_contact,
  252. DATA_PT_EEVEE_shadow_cascaded_shadow_map,
  253. DATA_PT_area,
  254. DATA_PT_spot,
  255. DATA_PT_falloff_curve,
  256. DATA_PT_custom_props_light,
  257. )
  258. if __name__ == "__main__": # only for live edit.
  259. from bpy.utils import register_class
  260. for cls in classes:
  261. register_class(cls)