Skip to content
Snippets Groups Projects
Commit 5417a6c0 authored by lijenstina's avatar lijenstina
Browse files

Dynamic Sky: Cleanup, Fixes

Bumped version to 1.0.2
Pep8 cleanup
add several checks to prevent crashes
add a scene prop to store the world name
avoid hardcoding the name
add some warnings in the Panel
parent 36ba3f82
Branches
Tags
No related merge requests found
# Dynamic Sky.py (c) 2015 Pratik Solanki (Draguu)
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# ***** END GPL LICENCE BLOCK *****
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "Dynamic Sky",
"author": "Pratik Solanki",
"version": (1, 0, 1),
"version": (1, 0, 2),
"blender": (2, 78, 0),
"location": "View3D > Tools",
"description": "Creates Dynamic Sky for Cycles",
......@@ -27,29 +29,59 @@ bl_info = {
"wiki_url": "http://www.dragoneex.com/downloads/dynamic-skyadd-on",
"category": "Lighting",
}
import bpy
class dsky(bpy.types.Operator):
import bpy
from bpy.props import StringProperty
from bpy.types import (
Operator,
Panel,
)
# Handle error notifications
def error_handlers(self, error, reports="ERROR"):
if self and reports:
self.report({'WARNING'}, reports + " (See Console for more info)")
print("\n[Dynamic Sky]\nError: {}\n".format(error))
def check_world_name(name_id="Dynamic"):
# check if the new name pattern is in world data
name_list = []
suffix = 1
try:
name_list = [world.name for world in bpy.data.worlds if name_id in world.name]
new_name = "{}_{}".format(name_id, len(name_list) + suffix)
if new_name in name_list:
# KISS failed - numbering is not sequential
# try harvesting numbers in world names, find the rightmost ones
test_num = []
from re import findall
for words in name_list:
test_num.append(findall("\d+", words))
suffix += max([int(l[-1]) for l in test_num])
new_name = "{}_{}".format(name_id, suffix)
return new_name
except Exception as e:
error_handlers(False, e)
pass
return name_id
class dsky(Operator):
bl_idname = "sky.dyn"
bl_label = "Make a Procidural sky"
bl_label = "Make a Procedural sky"
bl_description = "Make a Procedural Sky"
def execute(self, context):
try:
get_name = check_world_name()
context.scene.dynamic_sky_name = get_name
bpy.context.scene.render.engine = 'CYCLES'
def clean_node_tree(node_tree):
nodes = node_tree.nodes
for node in nodes:
if not node.type == 'OUTPUT_WORLD':
nodes.remove(node)
return node_tree.nodes[0]
bpy.context.scene.render.engine = 'CYCLES'
def dynamic():
world = bpy.data.worlds.new('Dynamic')
world = bpy.data.worlds.new(get_name)
world.cycles.sample_as_light = True
world.cycles.sample_map_resolution = 2048
world.use_nodes = True
......@@ -66,110 +98,110 @@ class dsky(bpy.types.Operator):
nor = nt.nodes.new(type="ShaderNodeNormal")
cr1 = nt.nodes.new(type ="ShaderNodeValToRGB")
cr1 = nt.nodes.new(type="ShaderNodeValToRGB")
cr1.color_ramp.elements[0].position = 0.969
cr1.color_ramp.interpolation = 'EASE'
cr2 = nt.nodes.new(type ="ShaderNodeValToRGB")
cr2 = nt.nodes.new(type="ShaderNodeValToRGB")
cr2.color_ramp.elements[0].position = 0.991
cr2.color_ramp.elements[1].position = 1
cr2.color_ramp.interpolation = 'EASE'
cr3 = nt.nodes.new(type ="ShaderNodeValToRGB")
cr3 = nt.nodes.new(type="ShaderNodeValToRGB")
cr3.color_ramp.elements[0].position = 0.779
cr3.color_ramp.elements[1].position = 1
cr3.color_ramp.interpolation = 'EASE'
mat1 = nt.nodes.new(type ="ShaderNodeMath")
mat1 = nt.nodes.new(type="ShaderNodeMath")
mat1.operation = 'MULTIPLY'
mat1.inputs[1].default_value = 0.2
mat2 = nt.nodes.new(type ="ShaderNodeMath")
mat2 = nt.nodes.new(type="ShaderNodeMath")
mat2.operation = 'MULTIPLY'
mat2.inputs[1].default_value = 2
mat3 = nt.nodes.new(type ="ShaderNodeMath")
mat3 = nt.nodes.new(type="ShaderNodeMath")
mat3.operation = 'MULTIPLY'
mat3.inputs[1].default_value = 40.9
mat4 = nt.nodes.new(type ="ShaderNodeMath")
mat4 = nt.nodes.new(type="ShaderNodeMath")
mat4.operation = 'SUBTRACT'
mat4.inputs[1].default_value = 1
ntl(mat2.inputs[0],mat1.outputs[0])
ntl(mat4.inputs[0],mat3.outputs[0])
ntl(mat1.inputs[0],cr3.outputs[0])
ntl(mat3.inputs[0],cr2.outputs[0])
ntl(mat2.inputs[0], mat1.outputs[0])
ntl(mat4.inputs[0], mat3.outputs[0])
ntl(mat1.inputs[0], cr3.outputs[0])
ntl(mat3.inputs[0], cr2.outputs[0])
soft = nt.nodes.new(type = "ShaderNodeMixRGB")
soft_1 = nt.nodes.new(type = "ShaderNodeMixRGB")
soft = nt.nodes.new(type="ShaderNodeMixRGB")
soft_1 = nt.nodes.new(type="ShaderNodeMixRGB")
soft.inputs[0].default_value = 1
soft_1.inputs[0].default_value = 0.466
ntl(soft.inputs[1],mat2.outputs[0])
ntl(soft.inputs[2],mat4.outputs[0])
ntl(soft_1.inputs[1],mat2.outputs[0])
ntl(soft_1.inputs[2],cr2.outputs[0])
ntl(soft.inputs[1], mat2.outputs[0])
ntl(soft.inputs[2], mat4.outputs[0])
ntl(soft_1.inputs[1], mat2.outputs[0])
ntl(soft_1.inputs[2], cr2.outputs[0])
mix1 = nt.nodes.new(type = "ShaderNodeMixRGB")
mix1 = nt.nodes.new(type="ShaderNodeMixRGB")
mix1.blend_type = 'MULTIPLY'
mix1.inputs[0].default_value = 1
mix1_1 = nt.nodes.new(type = "ShaderNodeMixRGB")
mix1_1 = nt.nodes.new(type="ShaderNodeMixRGB")
mix1_1.blend_type = 'MULTIPLY'
mix1_1.inputs[0].default_value = 1
mix2 = nt.nodes.new(type = "ShaderNodeMixRGB")
mix2_1 = nt.nodes.new(type = "ShaderNodeMixRGB")
mix2 = nt.nodes.new(type="ShaderNodeMixRGB")
mix2_1 = nt.nodes.new(type="ShaderNodeMixRGB")
mix2.inputs[1].default_value = (0, 0, 0, 1)
mix2.inputs[2].default_value = (32, 22, 14, 200)
mix2_1.inputs[1].default_value = (0, 0, 0, 1)
mix2_1.inputs[2].default_value = (1, 0.820, 0.650,1)
mix2_1.inputs[2].default_value = (1, 0.820, 0.650, 1)
ntl(mix1.inputs[1],soft.outputs[0])
ntl(mix1_1.inputs[1],soft_1.outputs[0])
ntl(mix2.inputs[0],mix1.outputs[0])
ntl(mix2_1.inputs[0],mix1_1.outputs[0])
ntl(mix1.inputs[1], soft.outputs[0])
ntl(mix1_1.inputs[1], soft_1.outputs[0])
ntl(mix2.inputs[0], mix1.outputs[0])
ntl(mix2_1.inputs[0], mix1_1.outputs[0])
gam = nt.nodes.new(type = "ShaderNodeGamma")
gam = nt.nodes.new(type="ShaderNodeGamma")
gam.inputs[1].default_value = 2.3
gam2 = nt.nodes.new(type = "ShaderNodeGamma")
gam2 = nt.nodes.new(type="ShaderNodeGamma")
gam2.inputs[1].default_value = 1
gam3 = nt.nodes.new(type = "ShaderNodeGamma")
gam3 = nt.nodes.new(type="ShaderNodeGamma")
gam3.inputs[1].default_value = 1
sunopa = nt.nodes.new(type = "ShaderNodeMixRGB")
sunopa = nt.nodes.new(type="ShaderNodeMixRGB")
sunopa.blend_type = 'ADD'
sunopa.inputs[0].default_value = 1
sunopa_1 = nt.nodes.new(type = "ShaderNodeMixRGB")
sunopa_1 = nt.nodes.new(type="ShaderNodeMixRGB")
sunopa_1.blend_type = 'ADD'
sunopa_1.inputs[0].default_value = 1
combine = nt.nodes.new(type = "ShaderNodeMixRGB")
ntl(combine.inputs[1],sunopa.outputs[0])
ntl(combine.inputs[2],sunopa_1.outputs[0])
lp = nt.nodes.new(type = "ShaderNodeLightPath")
ntl(combine.inputs[0],lp.outputs[0])
combine = nt.nodes.new(type="ShaderNodeMixRGB")
ntl(combine.inputs[1], sunopa.outputs[0])
ntl(combine.inputs[2], sunopa_1.outputs[0])
lp = nt.nodes.new(type="ShaderNodeLightPath")
ntl(combine.inputs[0], lp.outputs[0])
ntl(gam2.inputs[0],gam.outputs[0])
ntl(gam.inputs[0],mix2.outputs[0])
ntl(bg.inputs[0],combine.outputs[0])
ntl(gam2.inputs[0], gam.outputs[0])
ntl(gam.inputs[0], mix2.outputs[0])
ntl(bg.inputs[0], combine.outputs[0])
map2 = nt.nodes.new(type = "ShaderNodeMapping")
map2 = nt.nodes.new(type="ShaderNodeMapping")
map2.scale[2] = 6.00
map2.scale[0] = 1.5
map2.scale[1] = 1.5
n1 = nt.nodes.new(type = "ShaderNodeTexNoise")
n1 = nt.nodes.new(type="ShaderNodeTexNoise")
n1.inputs[1].default_value = 3.8
n1.inputs[2].default_value = 2.4
n1.inputs[3].default_value = 0.5
n2 = nt.nodes.new(type = "ShaderNodeTexNoise")
n2 = nt.nodes.new(type="ShaderNodeTexNoise")
n2.inputs[1].default_value = 2.0
n2.inputs[2].default_value = 10
n2.inputs[3].default_value = 0.2
ntl(n2.inputs[0],map2.outputs[0])
ntl(n1.inputs[0],map2.outputs[0])
ntl(n2.inputs[0], map2.outputs[0])
ntl(n1.inputs[0], map2.outputs[0])
sc1 = nt.nodes.new(type = "ShaderNodeValToRGB")
sc2 = nt.nodes.new(type = "ShaderNodeValToRGB")
sc3 = nt.nodes.new(type = "ShaderNodeValToRGB")
sc3_1 = nt.nodes.new(type = "ShaderNodeValToRGB")
sc4 = nt.nodes.new(type = "ShaderNodeValToRGB")
sc1 = nt.nodes.new(type="ShaderNodeValToRGB")
sc2 = nt.nodes.new(type="ShaderNodeValToRGB")
sc3 = nt.nodes.new(type="ShaderNodeValToRGB")
sc3_1 = nt.nodes.new(type="ShaderNodeValToRGB")
sc4 = nt.nodes.new(type="ShaderNodeValToRGB")
sc1.color_ramp.elements[1].position = 0.649
sc1.color_ramp.elements[0].position = 0.408
......@@ -200,12 +232,12 @@ class dsky(bpy.types.Operator):
sc3_1.color_ramp.elements[0].color = (0, 0, 0, 0)
sc3_1.color_ramp.elements[0].position = 0.0
smix1 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix2 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix2_1 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix3 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix4 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix5 = nt.nodes.new(type = "ShaderNodeMixRGB")
smix1 = nt.nodes.new(type="ShaderNodeMixRGB")
smix2 = nt.nodes.new(type="ShaderNodeMixRGB")
smix2_1 = nt.nodes.new(type="ShaderNodeMixRGB")
smix3 = nt.nodes.new(type="ShaderNodeMixRGB")
smix4 = nt.nodes.new(type="ShaderNodeMixRGB")
smix5 = nt.nodes.new(type="ShaderNodeMixRGB")
smix1.inputs[1].default_value = (1, 1, 1, 1)
smix1.inputs[2].default_value = (0, 0, 0, 1)
......@@ -221,65 +253,124 @@ class dsky(bpy.types.Operator):
smix5.blend_type = 'SCREEN'
smix5.inputs[0].default_value = 1
srgb = nt.nodes.new(type = "ShaderNodeSeparateRGB")
aniadd = nt.nodes.new(type = "ShaderNodeMath")
crgb = nt.nodes.new(type = "ShaderNodeCombineRGB")
sunrgb = nt.nodes.new(type = "ShaderNodeMixRGB")
srgb = nt.nodes.new(type="ShaderNodeSeparateRGB")
aniadd = nt.nodes.new(type="ShaderNodeMath")
crgb = nt.nodes.new(type="ShaderNodeCombineRGB")
sunrgb = nt.nodes.new(type="ShaderNodeMixRGB")
sunrgb.blend_type = 'MULTIPLY'
sunrgb.inputs[2].default_value = (32, 30, 30, 200)
sunrgb.inputs[0].default_value = 1
ntl(mix2.inputs[2],sunrgb.outputs[0])
ntl(smix1.inputs[0],sc2.outputs[0])
ntl(smix2.inputs[1],smix1.outputs[0])
ntl(smix2.inputs[2],sc1.outputs[0])
ntl(smix2_1.inputs[2],sc3_1.outputs[0])
ntl(smix3.inputs[0],sc4.outputs[0])
ntl(smix4.inputs[2],smix3.outputs[0])
ntl(smix4.inputs[1],sc3.outputs[0])
ntl(smix5.inputs[1],smix4.outputs[0])
ntl(smix2_1.inputs[1],smix2.outputs[0])
ntl(smix5.inputs[2],smix2_1.outputs[0])
ntl(sunopa.inputs[1],gam3.outputs[0])
ntl(gam3.inputs[0],smix5.outputs[0])
ntl(mix1.inputs[2],sc3.outputs[0])
ntl(sunopa.inputs[2],gam2.outputs[0])
ntl(sc1.inputs[0],n1.outputs[0])
ntl(sc2.inputs[0],n2.outputs[0])
skynor = nt.nodes.new(type = "ShaderNodeNormal")
ntl(sc3.inputs[0],skynor.outputs[1])
ntl(sc4.inputs[0],skynor.outputs[1])
ntl(sc3_1.inputs[0],skynor.outputs[1])
ntl(map2.inputs[0],crgb.outputs[0])
ntl(skynor.inputs[0],tcor.outputs[0])
ntl(mix1_1.inputs[2],sc3.outputs[0])
ntl(srgb.inputs[0],tcor.outputs[0])
ntl(crgb.inputs[1],srgb.outputs[1])
ntl(crgb.inputs[2],srgb.outputs[2])
ntl(aniadd.inputs[1],srgb.outputs[0])
ntl(crgb.inputs[0],aniadd.outputs[0])
#-------------
ntl(cr1.inputs[0],nor.outputs[1])
ntl(cr2.inputs[0],cr1.outputs[0])
ntl(cr3.inputs[0],nor.outputs[1])
ntl(nor.inputs[0],map.outputs[0])
ntl(map.inputs[0],tcor.outputs[0])
ntl(sunopa_1.inputs[1],smix5.outputs[0])
ntl(sunopa_1.inputs[2],mix2_1.outputs[0])
dynamic()
ntl(mix2.inputs[2], sunrgb.outputs[0])
ntl(smix1.inputs[0], sc2.outputs[0])
ntl(smix2.inputs[1], smix1.outputs[0])
ntl(smix2.inputs[2], sc1.outputs[0])
ntl(smix2_1.inputs[2], sc3_1.outputs[0])
ntl(smix3.inputs[0], sc4.outputs[0])
ntl(smix4.inputs[2], smix3.outputs[0])
ntl(smix4.inputs[1], sc3.outputs[0])
ntl(smix5.inputs[1], smix4.outputs[0])
ntl(smix2_1.inputs[1], smix2.outputs[0])
ntl(smix5.inputs[2], smix2_1.outputs[0])
ntl(sunopa.inputs[1], gam3.outputs[0])
ntl(gam3.inputs[0], smix5.outputs[0])
ntl(mix1.inputs[2], sc3.outputs[0])
ntl(sunopa.inputs[2], gam2.outputs[0])
ntl(sc1.inputs[0], n1.outputs[0])
ntl(sc2.inputs[0], n2.outputs[0])
skynor = nt.nodes.new(type="ShaderNodeNormal")
ntl(sc3.inputs[0], skynor.outputs[1])
ntl(sc4.inputs[0], skynor.outputs[1])
ntl(sc3_1.inputs[0], skynor.outputs[1])
ntl(map2.inputs[0], crgb.outputs[0])
ntl(skynor.inputs[0], tcor.outputs[0])
ntl(mix1_1.inputs[2], sc3.outputs[0])
ntl(srgb.inputs[0], tcor.outputs[0])
ntl(crgb.inputs[1], srgb.outputs[1])
ntl(crgb.inputs[2], srgb.outputs[2])
ntl(aniadd.inputs[1], srgb.outputs[0])
ntl(crgb.inputs[0], aniadd.outputs[0])
ntl(cr1.inputs[0], nor.outputs[1])
ntl(cr2.inputs[0], cr1.outputs[0])
ntl(cr3.inputs[0], nor.outputs[1])
ntl(nor.inputs[0], map.outputs[0])
ntl(map.inputs[0], tcor.outputs[0])
ntl(sunopa_1.inputs[1], smix5.outputs[0])
ntl(sunopa_1.inputs[2], mix2_1.outputs[0])
except Exception as e:
error_handlers(self, e, "Make a Procedural sky has failed")
return {"CANCELLED"}
return {'FINISHED'}
class Dynapanel(bpy.types.Panel):
def draw_world_settings(col, context):
get_world = context.scene.world
stored_name = context.scene.dynamic_sky_name
get_world_keys = bpy.data.worlds.keys()
if stored_name not in get_world_keys or len(get_world_keys) < 1:
col.label(text="The {} World could not".format(stored_name),
icon="INFO")
col.label(text="be found in the Worlds' Data", icon="BLANK1")
return
elif not (get_world and get_world.name == stored_name):
col.label(text="Please select the World", icon="INFO")
col.label(text="named {}".format(stored_name), icon="BLANK1")
col.label(text="from the Properties > World", icon="BLANK1")
return
pick_world = bpy.data.worlds[stored_name]
try:
m = pick_world.node_tree.nodes[28]
m = pick_world.node_tree.nodes['Mix.012'].inputs[1]
n = pick_world.node_tree.nodes['Mix.012'].inputs[2]
o = pick_world.node_tree.nodes['Mix.014'].inputs[0]
d = pick_world.node_tree.nodes['Mix.010'].inputs[0]
so = pick_world.node_tree.nodes['Gamma.001'].inputs[1]
so2 = pick_world.node_tree.nodes['Gamma.002'].inputs[1]
# sc = pick_world.node_tree.nodes['Mix.004'].inputs[2]
no = pick_world.node_tree.nodes['Normal'].outputs[0]
sof = pick_world.node_tree.nodes['Mix'].inputs[0]
bgp = pick_world.node_tree.nodes['Background'].inputs[1]
suc = pick_world.node_tree.nodes['Mix.015'].inputs[1]
except:
col.label(text="Please Create a new World", icon="INFO")
col.label(text="seems that there was already", icon="BLANK1")
col.label(text="one called {}".format(stored_name), icon="BLANK1")
return
col.label("World: %s" % stored_name)
col.separator()
col.label("Scene Control")
col.prop(bgp, "default_value", text="Brightness")
col.prop(so2, "default_value", text="Shadow color saturation")
col.label("Sky Control")
col.prop(m, "default_value", text="Cloud color")
col.prop(n, "default_value", text="Horizon Color")
col.prop(o, "default_value", text="Cloud opacity")
col.prop(d, "default_value", text="Cloud density")
col.label("Sun Control")
col.prop(suc, "default_value", text="")
col.prop(so, "default_value", text="Sun value")
col.prop(sof, "default_value", text="Soft hard")
col.prop(no, "default_value", text="")
class Dynapanel(Panel):
bl_label = "Dynamic sky"
bl_idname = "SCENE_PT_layout"
bl_space_type = 'VIEW_3D'
......@@ -289,60 +380,26 @@ class Dynapanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
scene = context.scene
layout.operator("sky.dyn", text="Create", icon='MAT_SPHERE_SKY')
layout.operator("sky.dyn", text = "Create", icon='MAT_SPHERE_SKY')
if bpy.data.worlds['Dynamic']:
col = layout.column()
m = bpy.data.worlds['Dynamic'].node_tree.nodes[28]
m = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.012'].inputs[1]
n = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.012'].inputs[2]
o = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.014'].inputs[0]
d = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.010'].inputs[0]
so = bpy.data.worlds['Dynamic'].node_tree.nodes['Gamma.001'].inputs[1]
so2 = bpy.data.worlds['Dynamic'].node_tree.nodes['Gamma.002'].inputs[1]
sc = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.004'].inputs[2]
no = bpy.data.worlds['Dynamic'].node_tree.nodes['Normal'].outputs[0]
sof = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix'].inputs[0]
bgp = bpy.data.worlds['Dynamic'].node_tree.nodes['Background'].inputs[1]
suc = bpy.data.worlds['Dynamic'].node_tree.nodes['Mix.015'].inputs[1]
col.label("Scene Control")
col.prop(bgp, "default_value", text="Brightness")
col.prop(so2, "default_value", text="Shadow color saturation")
col.label("---------------------------------------------------------")
col.label("Sky Control")
col.prop(m,"default_value", text="Cloud color")
col.prop(n, "default_value", text="Horizon Color")
col.prop(o, "default_value", text="Cloud opacity")
col.prop(d, "default_value", text="Cloud density")
col.label("---------------------------------------------------------")
col.label("Sun Control")
col.prop(suc, "default_value", text="")
col.prop(so, "default_value", text="Sun value")
col.prop(sof, "default_value", text="Soft hard")
col.prop(no, "default_value", text="")
else:
col = layout.column()
col.label("---------------------------------------------------------")
col = layout.column()
draw_world_settings(col, context)
def register():
bpy.utils.register_class(Dynapanel)
bpy.utils.register_class(dsky)
bpy.types.Scene.dynamic_sky_name = StringProperty(
name="",
default="Dynamic"
)
def unregister():
bpy.utils.unregister_class(Dynapanel)
bpy.utils.unregister_class(dsky)
del bpy.types.Scene.dynamic_sky_name
if __name__ == "__main__":
register()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment