FBX IO: Vertex position access with attributes
[blender-addons.git] / lighting_dynamic_sky.py
blob0fffbf3870c9a42c8a0c5c3f43ee1b98b888ce88
1 # SPDX-FileCopyrightText: 2015 Pratik Solanki (Draguu)
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "Dynamic Sky",
7 "author": "Pratik Solanki",
8 "version": (1, 0, 6),
9 "blender": (2, 80, 0),
10 "location": "View3D > Sidebar > Create Tab",
11 "description": "Creates Dynamic Sky for Cycles",
12 "warning": "",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/lighting/dynamic_sky.html",
14 "category": "Lighting",
17 import bpy
18 from bpy.props import StringProperty
19 from bpy.types import (
20 Operator,
21 Panel,
25 # Handle error notifications
26 def error_handlers(self, error, reports="ERROR"):
27 if self and reports:
28 self.report({'WARNING'}, reports + " (See Console for more info)")
30 print("\n[Dynamic Sky]\nError: {}\n".format(error))
33 def check_world_name(name_id="Dynamic"):
34 # check if the new name pattern is in world data
35 name_list = []
36 suffix = 1
37 try:
38 name_list = [world.name for world in bpy.data.worlds if name_id in world.name]
39 new_name = "{}_{}".format(name_id, len(name_list) + suffix)
40 if new_name in name_list:
41 # KISS failed - numbering is not sequential
42 # try harvesting numbers in world names, find the rightmost ones
43 test_num = []
44 from re import findall
45 for words in name_list:
46 test_num.append(findall(r"\d+", words))
48 suffix += max([int(l[-1]) for l in test_num])
49 new_name = "{}_{}".format(name_id, suffix)
50 return new_name
51 except Exception as e:
52 error_handlers(False, e)
53 pass
54 return name_id
57 def check_cycles():
58 return ('cycles' in bpy.context.preferences.addons.keys())
61 class dsky(Operator):
62 bl_idname = "sky.dyn"
63 bl_label = "Make a Procedural sky"
64 bl_description = ("Make a Procedural Sky with parameters in the 3D View\n"
65 "Note: Available just for Cycles renderer\n"
66 "Only the last created Dynamic World can be accessed from this panel")
68 @classmethod
69 def poll(cls, context):
70 return check_cycles()
72 def get_node_types(self, node_tree, node_type):
73 for node in node_tree.nodes:
74 if node.type == node_type:
75 return node
76 return None
78 def execute(self, context):
79 try:
80 get_name = check_world_name()
81 context.scene.dynamic_sky_name = get_name
82 bpy.context.scene.render.engine = 'CYCLES'
84 world = bpy.data.worlds.new(get_name)
85 world.cycles.sample_as_light = True
86 world.cycles.sample_map_resolution = 2048
87 world.use_nodes = True
89 nt = world.node_tree
90 # Note: (see T52714) to avoid string localization problems, assign the name for
91 # nodes that will be exposed in the 3D view (pattern UI name with underscore)
92 bg = self.get_node_types(nt, "BACKGROUND")
93 bg.name = "Scene_Brightness"
94 bg.inputs[0].default_value[:3] = (0.5, .1, 0.6)
95 bg.inputs[1].default_value = 1
96 bg.location = (6708.3, 360)
98 ntl = nt.links.new
99 tcor = nt.nodes.new(type="ShaderNodeTexCoord")
100 tcor.location = (243.729, 1005)
102 map1 = nt.nodes.new(type="ShaderNodeMapping")
103 map1.vector_type = 'NORMAL'
104 map1.location = (786.54, 730)
106 nor = nt.nodes.new(type="ShaderNodeNormal")
107 nor.name = "Sky_normal"
108 nor.location = (1220.16, 685)
110 cr1 = nt.nodes.new(type="ShaderNodeValToRGB")
111 cr1.color_ramp.elements[0].position = 0.969
112 cr1.color_ramp.interpolation = 'EASE'
113 cr1.location = (1671.33, 415)
114 cr2 = nt.nodes.new(type="ShaderNodeValToRGB")
115 cr2.color_ramp.elements[0].position = 0.991
116 cr2.color_ramp.elements[1].position = 1
117 cr2.color_ramp.interpolation = 'EASE'
118 cr2.location = (2196.6, 415)
119 cr3 = nt.nodes.new(type="ShaderNodeValToRGB")
120 cr3.color_ramp.elements[0].position = 0.779
121 cr3.color_ramp.elements[1].position = 1
122 cr3.color_ramp.interpolation = 'EASE'
123 cr3.location = (2196.6, 415)
125 mat1 = nt.nodes.new(type="ShaderNodeMath")
126 mat1.operation = 'MULTIPLY'
127 mat1.inputs[1].default_value = 0.2
128 mat1.location = (2196.6, 685)
129 mat2 = nt.nodes.new(type="ShaderNodeMath")
130 mat2.operation = 'MULTIPLY'
131 mat2.inputs[1].default_value = 2
132 mat2.location = (3294, 685)
133 mat3 = nt.nodes.new(type="ShaderNodeMath")
134 mat3.operation = 'MULTIPLY'
135 mat3.inputs[1].default_value = 40.9
136 mat3.location = (2745.24, 415)
137 mat4 = nt.nodes.new(type="ShaderNodeMath")
138 mat4.operation = 'SUBTRACT'
139 mat4.inputs[1].default_value = 1
140 mat4.location = (3294, 415)
141 ntl(mat2.inputs[0], mat1.outputs[0])
142 ntl(mat4.inputs[0], mat3.outputs[0])
143 ntl(mat1.inputs[0], cr3.outputs[0])
144 ntl(mat3.inputs[0], cr2.outputs[0])
146 soft = nt.nodes.new(type="ShaderNodeMixRGB")
147 soft.name = "Soft_hard"
148 soft.location = (3819.3, 550)
149 soft_1 = nt.nodes.new(type="ShaderNodeMixRGB")
150 soft_1.location = (3819.3, 185)
151 soft.inputs[0].default_value = 1
152 soft_1.inputs[0].default_value = 0.466
153 ntl(soft.inputs[1], mat2.outputs[0])
154 ntl(soft.inputs[2], mat4.outputs[0])
155 ntl(soft_1.inputs[1], mat2.outputs[0])
156 ntl(soft_1.inputs[2], cr2.outputs[0])
158 mix1 = nt.nodes.new(type="ShaderNodeMixRGB")
159 mix1.blend_type = 'MULTIPLY'
160 mix1.inputs[0].default_value = 1
161 mix1.location = (4344.3, 630)
162 mix1_1 = nt.nodes.new(type="ShaderNodeMixRGB")
163 mix1_1.blend_type = 'MULTIPLY'
164 mix1_1.inputs[0].default_value = 1
165 mix1_1.location = (4344.3, 90)
167 mix2 = nt.nodes.new(type="ShaderNodeMixRGB")
168 mix2.location = (4782, 610)
169 mix2_1 = nt.nodes.new(type="ShaderNodeMixRGB")
170 mix2_1.location = (5131.8, 270)
171 mix2.inputs[1].default_value = (0, 0, 0, 1)
172 mix2.inputs[2].default_value = (32, 22, 14, 200)
173 mix2_1.inputs[1].default_value = (0, 0, 0, 1)
174 mix2_1.inputs[2].default_value = (1, 0.820, 0.650, 1)
176 ntl(mix1.inputs[1], soft.outputs[0])
177 ntl(mix1_1.inputs[1], soft_1.outputs[0])
178 ntl(mix2.inputs[0], mix1.outputs[0])
179 ntl(mix2_1.inputs[0], mix1_1.outputs[0])
181 gam = nt.nodes.new(type="ShaderNodeGamma")
182 gam.inputs[1].default_value = 2.3
183 gam.location = (5131.8, 610)
185 gam2 = nt.nodes.new(type="ShaderNodeGamma")
186 gam2.name = "Sun_value"
187 gam2.inputs[1].default_value = 1
188 gam2.location = (5524.5, 610)
190 gam3 = nt.nodes.new(type="ShaderNodeGamma")
191 gam3.name = "Shadow_color_saturation"
192 gam3.inputs[1].default_value = 1
193 gam3.location = (5524.5, 880)
195 sunopa = nt.nodes.new(type="ShaderNodeMixRGB")
196 sunopa.blend_type = 'ADD'
197 sunopa.inputs[0].default_value = 1
198 sunopa.location = (5940.6, 610)
199 sunopa_1 = nt.nodes.new(type="ShaderNodeMixRGB")
200 sunopa_1.blend_type = 'ADD'
201 sunopa_1.inputs[0].default_value = 1
202 sunopa_1.location = (5524.5, 340)
204 combine = nt.nodes.new(type="ShaderNodeMixRGB")
205 combine.location = (6313.8, 360)
206 ntl(combine.inputs[1], sunopa.outputs[0])
207 ntl(combine.inputs[2], sunopa_1.outputs[0])
208 lp = nt.nodes.new(type="ShaderNodeLightPath")
209 lp.location = (5940.6, 130)
210 ntl(combine.inputs[0], lp.outputs[0])
212 ntl(gam2.inputs[0], gam.outputs[0])
213 ntl(gam.inputs[0], mix2.outputs[0])
214 ntl(bg.inputs[0], combine.outputs[0])
216 map2 = nt.nodes.new(type="ShaderNodeMapping")
217 map2.inputs['Scale'].default_value[2] = 6.00
218 map2.inputs['Scale'].default_value[0] = 1.5
219 map2.inputs['Scale'].default_value[1] = 1.5
220 map2.location = (2196.6, 1510)
222 n1 = nt.nodes.new(type="ShaderNodeTexNoise")
223 n1.inputs['Scale'].default_value = 3.8
224 n1.inputs['Detail'].default_value = 2.4
225 n1.inputs['Distortion'].default_value = 0.5
226 n1.location = (2745.24, 1780)
228 n2 = nt.nodes.new(type="ShaderNodeTexNoise")
229 n2.inputs['Scale'].default_value = 2.0
230 n2.inputs['Detail'].default_value = 10
231 n2.inputs['Distortion'].default_value = 0.2
232 n2.location = (2745.24, 1510)
234 ntl(n2.inputs[0], map2.outputs[0])
235 ntl(n1.inputs[0], map2.outputs[0])
237 sc1 = nt.nodes.new(type="ShaderNodeValToRGB")
238 sc1.location = (3294, 1780)
239 sc2 = nt.nodes.new(type="ShaderNodeValToRGB")
240 sc2.location = (3294, 1510)
241 sc3 = nt.nodes.new(type="ShaderNodeValToRGB")
242 sc3.location = (3819.3, 820)
243 sc3_1 = nt.nodes.new(type="ShaderNodeValToRGB")
244 sc3_1.location = (4344.3, 1360)
245 sc4 = nt.nodes.new(type="ShaderNodeValToRGB")
246 sc4.location = (3819.3, 1090)
248 sc1.color_ramp.elements[1].position = 0.649
249 sc1.color_ramp.elements[0].position = 0.408
251 sc2.color_ramp.elements[1].position = 0.576
252 sc2.color_ramp.elements[0].position = 0.408
254 sc3.color_ramp.elements.new(0.5)
255 sc3.color_ramp.elements[2].position = 0.435
257 sc3.color_ramp.elements[1].position = 0.160
258 sc3.color_ramp.elements[0].position = 0.027
260 sc3.color_ramp.elements[1].color = (1, 1, 1, 1)
261 sc3.color_ramp.elements[0].color = (0.419, 0.419, 0.419, 0.419)
263 sc3.color_ramp.elements[0].position = 0.0
264 sc4.color_ramp.elements[0].position = 0.0
265 sc4.color_ramp.elements[1].position = 0.469
266 sc4.color_ramp.elements[1].color = (0, 0, 0, 1)
267 sc4.color_ramp.elements[0].color = (1, 1, 0.917412, 1)
269 sc3_1.color_ramp.elements.new(0.5)
270 sc3_1.color_ramp.elements[2].position = 0.435
272 sc3_1.color_ramp.elements[1].position = 0.187
273 sc3_1.color_ramp.elements[1].color = (1, 1, 1, 1)
274 sc3_1.color_ramp.elements[0].color = (0, 0, 0, 0)
275 sc3_1.color_ramp.elements[0].position = 0.0
277 smix1 = nt.nodes.new(type="ShaderNodeMixRGB")
278 smix1.location = (3819.3, 1550)
279 smix1.name = "Cloud_color"
280 smix2 = nt.nodes.new(type="ShaderNodeMixRGB")
281 smix2.location = (4344.3, 1630)
282 smix2.name = "Cloud_density"
283 smix2_1 = nt.nodes.new(type="ShaderNodeMixRGB")
284 smix2_1.location = (4782, 1360)
286 smix3 = nt.nodes.new(type="ShaderNodeMixRGB")
287 smix3.location = (4344.3, 1090)
288 smix3.name = "Sky_and_Horizon_colors"
290 smix4 = nt.nodes.new(type="ShaderNodeMixRGB")
291 smix4.location = (4782, 880)
293 smix5 = nt.nodes.new(type="ShaderNodeMixRGB")
294 smix5.name = "Cloud_opacity"
295 smix5.location = (5131.8, 880)
297 smix1.inputs[1].default_value = (1, 1, 1, 1)
298 smix1.inputs[2].default_value = (0, 0, 0, 1)
299 smix2.inputs[0].default_value = 0.267
300 smix2.blend_type = 'MULTIPLY'
301 smix2_1.inputs[0].default_value = 1
302 smix2_1.blend_type = 'MULTIPLY'
304 smix3.inputs[1].default_value = (0.434, 0.838, 1, 1)
305 smix3.inputs[2].default_value = (0.962, 0.822, 0.822, 1)
306 smix4.blend_type = 'MULTIPLY'
307 smix4.inputs[0].default_value = 1
308 smix5.blend_type = 'SCREEN'
309 smix5.inputs[0].default_value = 1
311 srgb = nt.nodes.new(type="ShaderNodeSeparateRGB")
312 srgb.location = (786.54, 1370)
313 aniadd = nt.nodes.new(type="ShaderNodeMath")
314 aniadd.location = (1220.16, 1235)
315 crgb = nt.nodes.new(type="ShaderNodeCombineRGB")
316 crgb.location = (1671.33, 1510)
317 sunrgb = nt.nodes.new(type="ShaderNodeMixRGB")
318 sunrgb.name = "Sun_color"
320 sunrgb.blend_type = 'MULTIPLY'
321 sunrgb.inputs[2].default_value = (32, 30, 30, 200)
322 sunrgb.inputs[0].default_value = 1
323 sunrgb.location = (4344.3, 360)
325 ntl(mix2.inputs[2], sunrgb.outputs[0])
327 ntl(smix1.inputs[0], sc2.outputs[0])
328 ntl(smix2.inputs[1], smix1.outputs[0])
329 ntl(smix2.inputs[2], sc1.outputs[0])
330 ntl(smix2_1.inputs[2], sc3_1.outputs[0])
331 ntl(smix3.inputs[0], sc4.outputs[0])
332 ntl(smix4.inputs[2], smix3.outputs[0])
333 ntl(smix4.inputs[1], sc3.outputs[0])
334 ntl(smix5.inputs[1], smix4.outputs[0])
335 ntl(smix2_1.inputs[1], smix2.outputs[0])
336 ntl(smix5.inputs[2], smix2_1.outputs[0])
337 ntl(sunopa.inputs[1], gam3.outputs[0])
338 ntl(gam3.inputs[0], smix5.outputs[0])
339 ntl(mix1.inputs[2], sc3.outputs[0])
340 ntl(sunopa.inputs[2], gam2.outputs[0])
342 ntl(sc1.inputs[0], n1.outputs['Fac'])
343 ntl(sc2.inputs[0], n2.outputs['Fac'])
345 skynor = nt.nodes.new(type="ShaderNodeNormal")
346 skynor.location = (3294, 1070)
348 ntl(sc3.inputs[0], skynor.outputs[1])
349 ntl(sc4.inputs[0], skynor.outputs[1])
350 ntl(sc3_1.inputs[0], skynor.outputs[1])
351 ntl(map2.inputs[0], crgb.outputs[0])
352 ntl(skynor.inputs[0], tcor.outputs[0])
353 ntl(mix1_1.inputs[2], sc3.outputs[0])
354 ntl(srgb.inputs[0], tcor.outputs[0])
355 ntl(crgb.inputs[1], srgb.outputs[1])
356 ntl(crgb.inputs[2], srgb.outputs[2])
357 ntl(aniadd.inputs[1], srgb.outputs[0])
358 ntl(crgb.inputs[0], aniadd.outputs[0])
360 ntl(cr1.inputs[0], nor.outputs[1])
361 ntl(cr2.inputs[0], cr1.outputs[0])
362 ntl(cr3.inputs[0], nor.outputs[1])
363 ntl(nor.inputs[0], map1.outputs[0])
364 ntl(map1.inputs[0], tcor.outputs[0])
365 ntl(sunopa_1.inputs[1], smix5.outputs[0])
366 ntl(sunopa_1.inputs[2], mix2_1.outputs[0])
368 world_out = self.get_node_types(nt, "OUTPUT_WORLD")
369 world_out.location = (7167.3, 360)
371 except Exception as e:
372 error_handlers(self, e, "Make a Procedural sky has failed")
374 return {"CANCELLED"}
376 return {'FINISHED'}
379 def draw_world_settings(col, context):
380 get_world = context.scene.world
381 stored_name = context.scene.dynamic_sky_name
382 get_world_keys = bpy.data.worlds.keys()
384 if stored_name not in get_world_keys or len(get_world_keys) < 1:
385 col.label(text="The {} World could not".format(stored_name),
386 icon="INFO")
387 col.label(text="be found in the Worlds' Data", icon="BLANK1")
388 return
390 elif not (get_world and get_world.name == stored_name):
391 col.label(text="Please select the World", icon="INFO")
392 col.label(text="named {}".format(stored_name), icon="BLANK1")
393 col.label(text="from the Properties > World", icon="BLANK1")
394 return
396 pick_world = bpy.data.worlds[stored_name]
397 try:
398 m = pick_world.node_tree.nodes[28]
400 m = pick_world.node_tree.nodes['Sky_and_Horizon_colors'].inputs[1]
401 n = pick_world.node_tree.nodes['Sky_and_Horizon_colors'].inputs[2]
402 c = pick_world.node_tree.nodes['Cloud_color'].inputs[1]
403 o = pick_world.node_tree.nodes['Cloud_opacity'].inputs[0]
404 d = pick_world.node_tree.nodes['Cloud_density'].inputs[0]
405 so = pick_world.node_tree.nodes['Sun_value'].inputs[1]
406 so2 = pick_world.node_tree.nodes['Shadow_color_saturation'].inputs[1]
407 no = pick_world.node_tree.nodes['Sky_normal'].outputs[0]
408 sof = pick_world.node_tree.nodes['Soft_hard'].inputs[0]
409 bgp = pick_world.node_tree.nodes['Scene_Brightness'].inputs[1]
411 suc = pick_world.node_tree.nodes['Sun_color'].inputs[1]
412 except:
413 col.label(text="Please Create a new World", icon="INFO")
414 col.label(text="seems that there was already", icon="BLANK1")
415 col.label(text="one called {}".format(stored_name), icon="BLANK1")
416 return
418 col.label(text="World: %s" % stored_name)
419 col.separator()
421 col.label(text="Scene Control")
422 col.prop(bgp, "default_value", text="Brightness")
423 col.prop(so2, "default_value", text="Shadow color saturation")
425 col.label(text="Sky Control")
426 col.prop(m, "default_value", text="Sky color")
427 col.prop(n, "default_value", text="Horizon Color")
428 col.prop(c, "default_value", text="Cloud color")
429 col.prop(o, "default_value", text="Cloud opacity")
430 col.prop(d, "default_value", text="Cloud density")
432 col.label(text="Sun Control")
433 col.prop(suc, "default_value", text="")
434 col.prop(so, "default_value", text="Sun value")
435 col.prop(sof, "default_value", text="Soft hard")
437 col.prop(no, "default_value", text="")
440 class Dynapanel(Panel):
441 bl_label = "Dynamic sky"
442 bl_idname = "DYNSKY_PT_tools"
443 bl_space_type = 'VIEW_3D'
444 bl_region_type = 'UI'
445 bl_context = "objectmode"
446 bl_category = "Create"
447 bl_options = {'DEFAULT_CLOSED'}
449 def draw(self, context):
450 layout = self.layout
451 layout.operator("sky.dyn", text="Create", icon='MAT_SPHERE_SKY')
453 col = layout.column()
454 draw_world_settings(col, context)
457 def register():
458 bpy.utils.register_class(Dynapanel)
459 bpy.utils.register_class(dsky)
460 bpy.types.Scene.dynamic_sky_name = StringProperty(
461 name="",
462 default="Dynamic"
466 def unregister():
467 bpy.utils.unregister_class(Dynapanel)
468 bpy.utils.unregister_class(dsky)
469 del bpy.types.Scene.dynamic_sky_name
472 if __name__ == "__main__":
473 register()