mesh_tools/mesh_relax: pass in smooth factor
[blender-addons.git] / lighting_tri_lights.py
blob44a9c8e66357030b61e5e8b5392ec07b5cf09011
1 # gpl: author Daniel Schalla, maintained by meta-androcto
3 bl_info = {
4 "name": "Tri-lighting",
5 "author": "Daniel Schalla",
6 "version": (0, 1, 4),
7 "blender": (2, 80, 0),
8 "location": "View3D > Add > Lights",
9 "description": "Add 3 Point Lighting to Selected / Active Object",
10 "warning": "",
11 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
12 "category": "Lighting",
13 "wiki_url": "https://docs.blender.org/manual/en/dev/addons/"
14 "lighting/trilighting.html",
17 import bpy
18 from bpy.types import Operator
19 from bpy.props import (
20 EnumProperty,
21 FloatProperty,
22 IntProperty,
24 from math import (
25 sin, cos,
26 radians,
27 sqrt,
31 class OBJECT_OT_TriLighting(Operator):
32 bl_idname = "object.trilighting"
33 bl_label = "Tri-Lighting Creator"
34 bl_description = ("Add 3 Point Lighting to Selected / Active Object\n"
35 "Needs an existing Active Object")
36 bl_options = {'REGISTER', 'UNDO'}
37 COMPAT_ENGINES = {'CYCLES', 'EEVEE'}
39 height: FloatProperty(
40 name="Height",
41 default=5
43 distance: FloatProperty(
44 name="Distance",
45 default=5,
46 min=0.1,
47 subtype="DISTANCE"
49 energy: IntProperty(
50 name="Base Energy",
51 default=3,
52 min=1
54 contrast: IntProperty(
55 name="Contrast",
56 default=50,
57 min=-100, max=100,
58 subtype="PERCENTAGE"
60 leftangle: IntProperty(
61 name="Left Angle",
62 default=26,
63 min=1, max=90,
64 subtype="ANGLE"
66 rightangle: IntProperty(
67 name="Right Angle",
68 default=45,
69 min=1, max=90,
70 subtype="ANGLE"
72 backangle: IntProperty(
73 name="Back Angle",
74 default=235,
75 min=90, max=270,
76 subtype="ANGLE"
78 Light_Type_List = [
79 ('POINT', "Point", "Point Light"),
80 ('SUN', "Sun", "Sun Light"),
81 ('SPOT', "Spot", "Spot Light"),
82 ('AREA', "Area", "Area Light")
84 primarytype: EnumProperty(
85 attr='tl_type',
86 name="Key Type",
87 description="Choose the types of Key Lights you would like",
88 items=Light_Type_List,
89 default='AREA'
91 secondarytype: EnumProperty(
92 attr='tl_type',
93 name="Fill + Back Type",
94 description="Choose the types of secondary Lights you would like",
95 items=Light_Type_List,
96 default="AREA"
99 @classmethod
100 def poll(cls, context):
101 return context.active_object is not None
103 def draw(self, context):
104 layout = self.layout
106 layout.label(text="Position:")
107 col = layout.column(align=True)
108 col.prop(self, "height")
109 col.prop(self, "distance")
111 layout.label(text="Light:")
112 col = layout.column(align=True)
113 col.prop(self, "energy")
114 col.prop(self, "contrast")
116 layout.label(text="Orientation:")
117 col = layout.column(align=True)
118 col.prop(self, "leftangle")
119 col.prop(self, "rightangle")
120 col.prop(self, "backangle")
122 col = layout.column()
123 col.label(text="Key Light Type:")
124 col.prop(self, "primarytype", text="")
125 col.label(text="Fill + Back Type:")
126 col.prop(self, "secondarytype", text="")
129 def execute(self, context):
130 try:
131 collection = context.collection
132 scene = context.scene
133 view = context.space_data
134 if view.type == 'VIEW_3D':
135 camera = view.camera
136 else:
137 camera = scene.camera
139 if (camera is None):
140 cam_data = bpy.data.cameras.new(name='Camera')
141 cam_obj = bpy.data.objects.new(name='Camera', object_data=cam_data)
142 collection.objects.link(cam_obj)
143 scene.camera = cam_obj
144 bpy.ops.view3d.camera_to_view()
145 camera = cam_obj
146 bpy.ops.view3d.view_axis(type='TOP')
148 obj = bpy.context.view_layer.objects.active
150 # Calculate Energy for each Lamp
151 if(self.contrast > 0):
152 keyEnergy = self.energy
153 backEnergy = (self.energy / 100) * abs(self.contrast)
154 fillEnergy = (self.energy / 100) * abs(self.contrast)
155 else:
156 keyEnergy = (self.energy / 100) * abs(self.contrast)
157 backEnergy = self.energy
158 fillEnergy = self.energy
160 # Calculate Direction for each Lamp
162 # Calculate current Distance and get Delta
163 obj_position = obj.location
164 cam_position = camera.location
166 delta_position = cam_position - obj_position
167 vector_length = sqrt(
168 (pow(delta_position.x, 2) +
169 pow(delta_position.y, 2) +
170 pow(delta_position.z, 2))
172 if not vector_length:
173 # division by zero most likely
174 self.report({'WARNING'},
175 "Operation Cancelled. No viable object in the scene")
177 return {'CANCELLED'}
179 single_vector = (1 / vector_length) * delta_position
181 # Calc back position
182 singleback_vector = single_vector.copy()
183 singleback_vector.x = cos(radians(self.backangle)) * single_vector.x + \
184 (-sin(radians(self.backangle)) * single_vector.y)
186 singleback_vector.y = sin(radians(self.backangle)) * single_vector.x + \
187 (cos(radians(self.backangle)) * single_vector.y)
189 backx = obj_position.x + self.distance * singleback_vector.x
190 backy = obj_position.y + self.distance * singleback_vector.y
192 backData = bpy.data.lights.new(name="TriLamp-Back", type=self.secondarytype)
193 backData.energy = backEnergy
195 backLamp = bpy.data.objects.new(name="TriLamp-Back", object_data=backData)
196 collection.objects.link(backLamp)
197 backLamp.location = (backx, backy, self.height)
199 trackToBack = backLamp.constraints.new(type="TRACK_TO")
200 trackToBack.target = obj
201 trackToBack.track_axis = "TRACK_NEGATIVE_Z"
202 trackToBack.up_axis = "UP_Y"
204 # Calc right position
205 singleright_vector = single_vector.copy()
206 singleright_vector.x = cos(radians(self.rightangle)) * single_vector.x + \
207 (-sin(radians(self.rightangle)) * single_vector.y)
209 singleright_vector.y = sin(radians(self.rightangle)) * single_vector.x + \
210 (cos(radians(self.rightangle)) * single_vector.y)
212 rightx = obj_position.x + self.distance * singleright_vector.x
213 righty = obj_position.y + self.distance * singleright_vector.y
215 rightData = bpy.data.lights.new(name="TriLamp-Fill", type=self.secondarytype)
216 rightData.energy = fillEnergy
217 rightLamp = bpy.data.objects.new(name="TriLamp-Fill", object_data=rightData)
218 collection.objects.link(rightLamp)
219 rightLamp.location = (rightx, righty, self.height)
220 trackToRight = rightLamp.constraints.new(type="TRACK_TO")
221 trackToRight.target = obj
222 trackToRight.track_axis = "TRACK_NEGATIVE_Z"
223 trackToRight.up_axis = "UP_Y"
225 # Calc left position
226 singleleft_vector = single_vector.copy()
227 singleleft_vector.x = cos(radians(-self.leftangle)) * single_vector.x + \
228 (-sin(radians(-self.leftangle)) * single_vector.y)
229 singleleft_vector.y = sin(radians(-self.leftangle)) * single_vector.x + \
230 (cos(radians(-self.leftangle)) * single_vector.y)
231 leftx = obj_position.x + self.distance * singleleft_vector.x
232 lefty = obj_position.y + self.distance * singleleft_vector.y
234 leftData = bpy.data.lights.new(name="TriLamp-Key", type=self.primarytype)
235 leftData.energy = keyEnergy
237 leftLamp = bpy.data.objects.new(name="TriLamp-Key", object_data=leftData)
238 collection.objects.link(leftLamp)
239 leftLamp.location = (leftx, lefty, self.height)
240 trackToLeft = leftLamp.constraints.new(type="TRACK_TO")
241 trackToLeft.target = obj
242 trackToLeft.track_axis = "TRACK_NEGATIVE_Z"
243 trackToLeft.up_axis = "UP_Y"
245 except Exception as e:
246 self.report({'WARNING'},
247 "Some operations could not be performed (See Console for more info)")
249 print("\n[Add Advanced Objects]\nOperator: "
250 "object.trilighting\nError: {}".format(e))
252 return {'CANCELLED'}
254 return {'FINISHED'}
256 def menu_func(self, context):
257 self.layout.operator(OBJECT_OT_TriLighting.bl_idname, text="3 Point Lights", icon='LIGHT')
261 # Register all operators and menu
262 def register():
263 bpy.utils.register_class(OBJECT_OT_TriLighting)
264 bpy.types.VIEW3D_MT_light_add.append(menu_func)
266 def unregister():
267 bpy.utils.unregister_class(OBJECT_OT_TriLighting)
268 bpy.types.VIEW3D_MT_light_add.remove(menu_func)
270 if __name__ == "__main__":
271 register()