├── .gitignore ├── README.md ├── eevee_blackbody.py └── run.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.blend 2 | *.blend1 3 | /demo video 4 | /__pycache__ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eevee blackbody 2 | A Blender addon that adds the blackbody support to Eevee 3 | 4 | ## Download and installation 5 | 6 | 1. Download latest `eevee_blackbody.py` from https://github.com/artempoletsky/blender_eevee_blackbody/releases 7 | 2. In Blender's preferencies install addon from the file 8 | 9 | ## Usage 10 | 11 | 1. Open the light settings. 12 | 2. Set `Use blackbody temperature` on. 13 | 3. Enter the blackbody temperature. 14 | 15 | You can't use this feature together with `Use nodes` option. 16 | 17 | The temperature to color algorythm is taken from Blender sources, so results should be like in cycles. 18 | 19 | ## Support 20 | You can support me directly via PayPal: https://www.paypal.me/apoletsky 21 | 22 | Or you can check out one of my paid addons: https://gumroad.com/artempoletsky 23 | -------------------------------------------------------------------------------- /eevee_blackbody.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | "name": "Eevee blackbody", 3 | "author": "Artem Poletsky", 4 | "version": (1, 0, 1), 5 | "blender": (2, 82, 0), 6 | "location": "Eevee -> light settings", 7 | "description": "Adds support of blackbody to eevee", 8 | "warning": "", 9 | "wiki_url": "", 10 | "category": "Lighting", 11 | } 12 | 13 | import bpy 14 | from bpy.app.handlers import persistent 15 | 16 | def driver_add(light): 17 | driver = light.driver_add('color') 18 | 19 | return 20 | 21 | def driver_remove(light): 22 | light.driver_remove('color') 23 | return 24 | 25 | def eevee_light_settings(self, context): 26 | layout = self.layout 27 | layout.separator() 28 | light = context.light 29 | 30 | layout.prop(light, "use_blackbody") 31 | if light.use_blackbody: 32 | layout.prop(light, "blackbody") 33 | 34 | blackbody_table_r = [ 35 | [2.52432244e+03, -1.06185848e-03, 3.11067539e+00], 36 | [3.37763626e+03, -4.34581697e-04, 1.64843306e+00], 37 | [4.10671449e+03, -8.61949938e-05, 6.41423749e-01], 38 | [4.66849800e+03, 2.85655028e-05, 1.29075375e-01], 39 | [4.60124770e+03, 2.89727618e-05, 1.48001316e-01], 40 | [3.78765709e+03, 9.36026367e-06, 3.98995841e-01], 41 | ]; 42 | 43 | blackbody_table_g = [ 44 | [-7.50343014e+02, 3.15679613e-04, 4.73464526e-01], 45 | [-1.00402363e+03, 1.29189794e-04, 9.08181524e-01], 46 | [-1.22075471e+03, 2.56245413e-05, 1.20753416e+00], 47 | [-1.42546105e+03, -4.01730887e-05, 1.44002695e+00], 48 | [-1.18134453e+03, -2.18913373e-05, 1.30656109e+00], 49 | [-5.00279505e+02, -4.59745390e-06, 1.09090465e+00], 50 | ]; 51 | 52 | blackbody_table_b = [ 53 | [0.0, 0.0, 0.0, 0.0], 54 | [0.0, 0.0, 0.0, 0.0], 55 | [0.0, 0.0, 0.0, 0.0], 56 | [-2.02524603e-11, 1.79435860e-07, -2.60561875e-04, -1.41761141e-02], 57 | [-2.22463426e-13, -1.55078698e-08, 3.81675160e-04, -7.30646033e-01], 58 | [6.72595954e-13, -2.73059993e-08, 4.24068546e-04, -7.52204323e-01], 59 | ]; 60 | 61 | def blackbody_temp_to_color(t): 62 | if t >= 12000.0: 63 | return [0.826270103, 0.994478524, 1.56626022]; 64 | if t < 965.0: 65 | return [4.70366907, 0.0, 0.0] 66 | 67 | i = 0 68 | if t >= 6365.0: 69 | i = 5 70 | elif t >= 3315.0: 71 | i = 4 72 | elif t >= 1902.0: 73 | i = 3 74 | elif t >= 1449.0: 75 | i = 2 76 | elif t >= 1167.0: 77 | i = 1 78 | else: 79 | i = 0 80 | 81 | r = blackbody_table_r[i] 82 | g = blackbody_table_g[i] 83 | b = blackbody_table_b[i] 84 | 85 | t_inv = 1 / t 86 | return [r[0] * t_inv + r[1] * t + r[2], 87 | g[0] * t_inv + g[1] * t + g[2], 88 | ((b[0] * t + b[1]) * t + b[2]) * t + b[3]] 89 | 90 | def update_light(light): 91 | if not light.use_blackbody: 92 | return 93 | 94 | light.use_nodes = False 95 | blackbody = light.blackbody 96 | light.color = blackbody_temp_to_color(blackbody) 97 | 98 | @persistent 99 | def on_update_scene(scene): 100 | lights = [o for o in scene.objects if o.type == 'LIGHT'] 101 | for l in lights: 102 | update_light(l.data) 103 | 104 | def register(): 105 | 106 | bpy.types.Light.blackbody = bpy.props.IntProperty(name="Blackbody temperature", default=1500) 107 | bpy.types.Light.use_blackbody = bpy.props.BoolProperty(name="Use blackbody temperature", default=False) 108 | bpy.types.DATA_PT_EEVEE_light.append(eevee_light_settings) 109 | bpy.types.CYCLES_LIGHT_PT_light.append(eevee_light_settings) 110 | bpy.app.handlers.depsgraph_update_post.append(on_update_scene) 111 | bpy.app.handlers.frame_change_post.append(on_update_scene) 112 | 113 | def unregister(): 114 | 115 | bpy.types.DATA_PT_EEVEE_light.remove(eevee_light_settings) 116 | bpy.app.handlers.depsgraph_update_post.remove(on_update_scene) 117 | bpy.types.CYCLES_LIGHT_PT_light.remove(eevee_light_settings) 118 | bpy.app.handlers.frame_change_post.remove(on_update_scene) 119 | 120 | if __name__ == "__main__": 121 | register() 122 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import bpy 4 | 5 | blend_dir = os.path.dirname(bpy.data.filepath) 6 | if blend_dir not in sys.path: 7 | sys.path.append(blend_dir) 8 | 9 | import eevee_blackbody 10 | import imp 11 | imp.reload(eevee_blackbody) 12 | eevee_blackbody.register() 13 | --------------------------------------------------------------------------------