Pose Library: update for rename of asset_library to asset_library_ref
[blender-addons.git] / lighting_tri_lights.py
blobf86972ed5b8a192081f083ceedb3d9f3ebdd27db
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 "doc_url": "{BLENDER_MANUAL_URL}/addons/lighting/trilighting.html",
13 "category": "Lighting",
16 import bpy
17 from bpy.types import Operator
18 from bpy.props import (
19 EnumProperty,
20 FloatProperty,
21 IntProperty,
23 from math import (
24 sin, cos,
25 radians,
26 sqrt,
30 class OBJECT_OT_TriLighting(Operator):
31 bl_idname = "object.trilighting"
32 bl_label = "Tri-Lighting Creator"
33 bl_description = ("Add 3 Point Lighting to Selected / Active Object\n"
34 "Needs an existing Active Object")
35 bl_options = {'REGISTER', 'UNDO'}
36 COMPAT_ENGINES = {'CYCLES', 'EEVEE'}
38 height: FloatProperty(
39 name="Height",
40 default=5
42 distance: FloatProperty(
43 name="Distance",
44 default=5,
45 min=0.1,
46 subtype="DISTANCE"
48 energy: IntProperty(
49 name="Base Energy",
50 default=3,
51 min=1
53 contrast: IntProperty(
54 name="Contrast",
55 default=50,
56 min=-100, max=100,
57 subtype="PERCENTAGE"
59 leftangle: IntProperty(
60 name="Left Angle",
61 default=26,
62 min=1, max=90,
63 subtype="ANGLE"
65 rightangle: IntProperty(
66 name="Right Angle",
67 default=45,
68 min=1, max=90,
69 subtype="ANGLE"
71 backangle: IntProperty(
72 name="Back Angle",
73 default=235,
74 min=90, max=270,
75 subtype="ANGLE"
77 Light_Type_List = [
78 ('POINT', "Point", "Point Light"),
79 ('SUN', "Sun", "Sun Light"),
80 ('SPOT', "Spot", "Spot Light"),
81 ('AREA', "Area", "Area Light")
83 primarytype: EnumProperty(
84 attr='tl_type',
85 name="Key Type",
86 description="Choose the types of Key Lights you would like",
87 items=Light_Type_List,
88 default='AREA'
90 secondarytype: EnumProperty(
91 attr='tl_type',
92 name="Fill + Back Type",
93 description="Choose the types of secondary Lights you would like",
94 items=Light_Type_List,
95 default="AREA"
98 @classmethod
99 def poll(cls, context):
100 return context.active_object is not None
102 def draw(self, context):
103 layout = self.layout
105 layout.label(text="Position:")
106 col = layout.column(align=True)
107 col.prop(self, "height")
108 col.prop(self, "distance")
110 layout.label(text="Light:")
111 col = layout.column(align=True)
112 col.prop(self, "energy")
113 col.prop(self, "contrast")
115 layout.label(text="Orientation:")
116 col = layout.column(align=True)
117 col.prop(self, "leftangle")
118 col.prop(self, "rightangle")
119 col.prop(self, "backangle")
121 col = layout.column()
122 col.label(text="Key Light Type:")
123 col.prop(self, "primarytype", text="")
124 col.label(text="Fill + Back Type:")
125 col.prop(self, "secondarytype", text="")
128 def execute(self, context):
129 try:
130 collection = context.collection
131 scene = context.scene
132 view = context.space_data
133 if view.type == 'VIEW_3D':
134 camera = view.camera
135 else:
136 camera = scene.camera
138 if (camera is None):
139 cam_data = bpy.data.cameras.new(name='Camera')
140 cam_obj = bpy.data.objects.new(name='Camera', object_data=cam_data)
141 collection.objects.link(cam_obj)
142 scene.camera = cam_obj
143 bpy.ops.view3d.camera_to_view()
144 camera = cam_obj
145 # Leave camera view again, otherwise redo does not work correctly.
146 bpy.ops.view3d.view_camera()
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()