1 # SPDX-License-Identifier: GPL-2.0-or-later
4 from mathutils
import Vector
5 from amaranth
.utils
import cycles_exists
8 # FEATURE: Add Meshlight
9 class AMTH_OBJECT_OT_meshlight_add(bpy
.types
.Operator
):
11 """Add a light emitting mesh"""
12 bl_idname
= "object.meshlight_add"
13 bl_label
= "Add Meshlight"
14 bl_options
= {'REGISTER', 'UNDO'}
16 single_sided
: bpy
.props
.BoolProperty(
19 description
="Only emit light on one side",
22 is_constant
: bpy
.props
.BoolProperty(
23 name
="Constant Falloff",
25 description
="Energy is constant (i.e. the Sun), "
26 "independent of how close to the source you are",
29 visible
: bpy
.props
.BoolProperty(
30 name
="Visible on Camera",
32 description
="Whether to show the meshlight source on Camera",
35 size
: bpy
.props
.FloatProperty(
37 description
="Meshlight size. Lower is sharper shadows, higher is softer",
42 strength
: bpy
.props
.FloatProperty(
44 min=0.01, max=100000.0,
49 temperature
: bpy
.props
.FloatProperty(
54 description
="Temperature in Kelvin. Lower is warmer, higher is colder",
57 rotation
: bpy
.props
.FloatVectorProperty(
62 def execute(self
, context
):
67 for obs
in bpy
.data
.objects
:
68 if obs
.name
.startswith("light_meshlight"):
71 meshlight_name
= 'light_meshlight_%.2d' % number
73 bpy
.ops
.mesh
.primitive_grid_add(
74 x_subdivisions
=4, y_subdivisions
=4,
75 rotation
=self
.rotation
, size
=self
.size
)
77 bpy
.context
.object.name
= meshlight_name
78 meshlight
= scene
.objects
[meshlight_name
]
79 meshlight
.show_wire
= True
80 meshlight
.show_all_edges
= True
82 material
= bpy
.data
.materials
.get(meshlight_name
)
85 material
= bpy
.data
.materials
.new(meshlight_name
)
87 bpy
.ops
.object.material_slot_add()
88 meshlight
.active_material
= material
90 material
.use_nodes
= True
91 material
.diffuse_color
= (1, 0.5, 0, 1)
92 nodes
= material
.node_tree
.nodes
93 links
= material
.node_tree
.links
95 # clear default nodes to start nice fresh
100 geometry
= nodes
.new(type="ShaderNodeNewGeometry")
102 transparency
= nodes
.new(type="ShaderNodeBsdfTransparent")
103 transparency
.inputs
[0].default_value
= (1, 1, 1, 1)
104 transparency
.location
= geometry
.location
105 transparency
.location
+= Vector((0.0, -55.0))
107 emission
= nodes
.new(type="ShaderNodeEmission")
108 emission
.inputs
['Strength'].default_value
= self
.strength
109 emission
.location
= transparency
.location
110 emission
.location
+= Vector((0.0, -80.0))
112 blackbody
= nodes
.new(type="ShaderNodeBlackbody")
113 blackbody
.inputs
['Temperature'].default_value
= self
.temperature
114 blackbody
.location
= emission
.location
115 blackbody
.location
+= Vector((-180.0, 0.0))
116 blackbody
.label
= 'Temperature'
118 mix
= nodes
.new(type="ShaderNodeMixShader")
119 mix
.location
= geometry
.location
120 mix
.location
+= Vector((180.0, 0.0))
121 mix
.inputs
[2].show_expanded
= True
123 output
= nodes
.new(type="ShaderNodeOutputMaterial")
124 output
.inputs
[1].hide
= True
125 output
.inputs
[2].hide
= True
126 output
.location
= mix
.location
127 output
.location
+= Vector((180.0, 0.0))
130 links
.new(geometry
.outputs
['Backfacing'], mix
.inputs
[0])
131 links
.new(transparency
.outputs
['BSDF'], mix
.inputs
[1])
132 links
.new(emission
.outputs
['Emission'], mix
.inputs
[2])
133 links
.new(blackbody
.outputs
['Color'], emission
.inputs
['Color'])
134 links
.new(mix
.outputs
['Shader'], output
.inputs
['Surface'])
136 for sockets
in geometry
.outputs
:
139 emission
= nodes
.new(type="ShaderNodeEmission")
140 emission
.inputs
['Strength'].default_value
= self
.strength
142 blackbody
= nodes
.new(type="ShaderNodeBlackbody")
143 blackbody
.inputs
['Temperature'].default_value
= self
.temperature
144 blackbody
.location
= emission
.location
145 blackbody
.location
+= Vector((-180.0, 0.0))
146 blackbody
.label
= 'Temperature'
148 output
= nodes
.new(type="ShaderNodeOutputMaterial")
149 output
.inputs
[1].hide
= True
150 output
.inputs
[2].hide
= True
151 output
.location
= emission
.location
152 output
.location
+= Vector((180.0, 0.0))
154 links
.new(blackbody
.outputs
['Color'], emission
.inputs
['Color'])
155 links
.new(emission
.outputs
['Emission'], output
.inputs
['Surface'])
158 falloff
= nodes
.new(type="ShaderNodeLightFalloff")
159 falloff
.inputs
['Strength'].default_value
= self
.strength
160 falloff
.location
= emission
.location
161 falloff
.location
+= Vector((-180.0, -80.0))
163 links
.new(falloff
.outputs
['Constant'], emission
.inputs
['Strength'])
165 for sockets
in falloff
.outputs
:
168 # so it shows slider on properties editor
169 for sockets
in emission
.inputs
:
170 sockets
.show_expanded
= True
172 material
.cycles
.sample_as_light
= True
173 meshlight
.visible_shadow
= False
174 meshlight
.visible_camera
= self
.visible
179 def ui_menu_lamps_add(self
, context
):
180 if cycles_exists() and context
.scene
.render
.engine
== 'CYCLES':
181 self
.layout
.separator()
182 self
.layout
.operator(
183 AMTH_OBJECT_OT_meshlight_add
.bl_idname
,
184 icon
="LIGHT_AREA", text
="Meshlight")
186 # //FEATURE: Add Meshlight: Single Sided
190 bpy
.utils
.register_class(AMTH_OBJECT_OT_meshlight_add
)
191 bpy
.types
.VIEW3D_MT_light_add
.append(ui_menu_lamps_add
)
195 bpy
.utils
.unregister_class(AMTH_OBJECT_OT_meshlight_add
)
196 bpy
.types
.VIEW3D_MT_light_add
.remove(ui_menu_lamps_add
)