blender-lighting について
Blenderで照明を設定するクリエイター向けのスキルです。シーンや被写体に応じたライト選び、三点照明、影の調整に加え、自発光する被写体や素材別の照明設定も扱います。
主な機能
- 015種類のライトの選択ガイド
- 02被写体に合わせた三点照明
- 03HDRIと屋内外の照明レシピ
- 04素材別の照明調整
- 05影と色温度の調整ガイド
活用シーン
- 01製品レンダリングのスタジオ照明
- 02窓光や実用光源を使った室内照明
- 03ガラスや木材の被写体に合わせた調整
- 04自発光オブジェクトの環境光と補助光の設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ roble3/ cc-blender-skill --skill blender-lightingインストール後、Claude Code で/blender-lightingを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/overview.md
詳細
Blender ライティング
プロのように、構成と意図を持ち、物理的に妥当な値でシーンをライティングします。
5 種類のライト
| 種類 | 動作 | 用途 |
|---|---|---|
| AREA | 長方形の面から光を照射します。柔らかな影が自動で得られます | 80%のケース。窓、ソフトボックス、蛍光灯パネル |
| SUN | 「無限遠」から平行光線を照射します | 太陽光、月光、遠方からの指向性ライト |
| POINT | 点から全方向に光を照射します | 電球、ろうそく、小型の全方向ライト |
| SPOT | 減衰する円錐状の光を照射します | ステージライト、ヘッドライト、集束光 |
| HDRI/World | 360°の環境画像です | リアルな環境光、屋外、製品写真 |
基本ルール:太陽以外は、ほとんどすべてに Area ライト を使います。柔らかな影が最初から得られます。
判断ツリー
What's the mood?
├── Studio / commercial → Three-point lighting (key+fill+rim) + HDRI fill 0.3
├── Outdoor / sunlit → Sun + HDRI sky environment
├── Indoor cinematic → Sun through window + HDRI low + practicals (lamps as Point)
├── Dramatic / noir → Single Spot at high angle, no fill
├── Stylized / cartoon → Three-point with high contrast + saturated key color
└── Unsure → Three-point with HDRI grounding (works for 90% of cases)
参照画像に合わせるための引き継ぎ
一般的に魅力的なレンダーを作るのではなく、元画像や参照画像に合わせることが目的の場合は、reference-look-calibration をチェーンロードします。色相・彩度・明度、オブジェクトの範囲、発光/オーラの色、変更前後の見た目の指標の測定を担当します。その後、このスキルで、調整済みの目標に沿って指定されたマテリアル/ライティング/レンダーの変更を適用します。
レシピ
ヘルパー:aim_at(light, target) — 被写体に応じたライティングに必須
以下のレシピ 1 では、固定されたワールド座標とハードコードされた回転を使ってライトを配置します。ワールド原点にある一般的な 1m の被写体なら問題ありません。それ以外のあらゆる被写体(小さなジュエリー、背の高い剣、広大な建物)では、被写体にライトを向ける必要があります。このヘルパーを使ってください。
from mathutils import Vector
def aim_at(light_obj, target):
"""Aim a light at a world-space target.
target may be a Vector or a tuple/list (x, y, z) or a Blender object.
"""
target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
direction = (target_pos - light_obj.location).normalized()
light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
ヘルパー:シーンに応じたライトの配置
from mathutils import Vector
def compute_scene_bbox_center(meshes):
"""Average bbox center over a list of mesh objects (world space)."""
import bpy
deps = bpy.context.evaluated_depsgraph_get()
all_verts = []
for o in meshes:
eval_obj = o.evaluated_get(deps)
em = eval_obj.to_mesh()
for v in em.vertices:
all_verts.append(o.matrix_world @ v.co)
eval_obj.to_mesh_clear()
xs = [v.x for v in all_verts]
ys = [v.y for v in all_verts]
zs = [v.z for v in all_verts]
center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
extent = max(max(xs)-min(xs), max(ys)-min(ys), max(zs)-min(zs))
return center, extent
レシピ 0a — 被写体のクラスに応じた三点照明(オーケストレーター E2E ではこちらを使用)
一般的な三点照明(以下のレシピ 0b)では、固定のエネルギー比でライトを配置します。不透明な被写体(椅子、剣)には適していますが、ガラスでは破綻します(リムライトでボリュームの色味が飛びます)。また、木材には冷たすぎます(温かみが失われます)。
subject_class のヒントを渡して、セットアップを調整します。
| クラス | キー:フィル:リムの比率 | キーの色温度 | 理由 |
|---|---|---|---|
'metal' | 4:1:2(デフォルト) | 暖色 3200K | 標準的な三点照明で金属らしさがよく表現されます |
'glass' | 3:1:1.2 | 中間色 5500K | リムを弱めます。強いリムライトはボリュームの色味を飛ばすためです。透過色が見えるよう、フィルを明るくします |
'wood' | 4:1:1.5 | 暖色 3000K | 温かみのあるキーライトで木の色調を引き立てます。木材にはシルエットの強調が不要なため、リムを弱めます |
'fabric' | 3:1:0.5 | 中間色 5500K | 柔らかくバランスの取れたライティングです。フィルライトによって光沢が表現されます |
'skin' | 4:1:1 | 暖色 3500K | 健康的な肌色を表現する暖色のキーライトです。顔の輪郭がきつくならないよう、リムは控えめにします |
'product' | 5:1:1.5 | 中間色 5000K | コントラストを高め、商業的でクリーンな見た目にします |
| (指定なし) | レシピ 0b(デフォルト)にフォールバック | 暖色 3200K |
import bpy, math
from mathutils import Vector
def aim_at(light_obj, target):
target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
direction = (target_pos - light_obj.location).normalized()
light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
def apply_three_point(subject_class='metal'):
"""Configure 3-point lighting with subject-class-aware ratios.
subject_class: 'metal' | 'glass' | 'wood' | 'fabric' | 'skin' | 'product' | 'metal' (default)
"""
profiles = {
'metal': dict(ratio=(4.0, 1.0, 2.0), key_color=(1.0, 0.95, 0.85), fill_color=(0.85, 0.9, 1.0), rim_color=(0.7, 0.85, 1.0)),
'glass': dict(ratio=(3.0, 1.0, 1.2), key_color=(1.0, 0.98, 0.95), fill_color=(0.95, 0.95, 1.0), rim_color=(0.95, 0.95, 1.0)),
'wood': dict(ratio=(4.0, 1.0, 1.5), key_color=(1.0, 0.92, 0.78), fill_color=(0.95, 0.95, 1.0), rim_color=(0.85, 0.92, 1.0)),
'fabric': dict(ratio=(3.0, 1.0, 0.5), key_color=(1.0, 0.97, 0.92), fill_color=(0.92, 0.95, 1.0), rim_color=(0.95, 0.95, 1.0)),
'skin': dict(ratio=(4.0, 1.0, 1.0), key_color=(1.0, 0.93, 0.82), fill_color=(0.95, 0.96, 1.0), rim_color=(0.92, 0.92, 1.0)),
'product': dict(ratio=(5.0, 1.0, 1.5), key_color=(1.0, 0.98, 0.95), fill_color=(0.98, 0.98, 1.0), rim_color=(0.98, 0.98, 1.0)),
}
p = profiles.get(subject_class, profiles['metal'])
# Compute scene bbox
subject_meshes = [o for o in bpy.data.objects if o.type == 'MESH' and o.name.startswith('GEO-')]
deps = bpy.context.evaluated_depsgraph_get()
all_verts = []
for o in subject_meshes:
eo = o.evaluated_get(deps); em = eo.to_mesh()
for v in em.vertices: all_verts.append(o.matrix_world @ v.co)
eo.to_mesh_clear()
xs = [v.x for v in all_verts]; ys = [v.y for v in all_verts]; zs = [v.z for v in all_verts]
center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
biggest = max(max(zs)-min(zs), max(xs)-min(xs))
light_dist = max(biggest * 1.5, 1.0)
# Energy scales with distance²
base_energy = 100 * (light_dist / 1.5) ** 2
key_e, fill_e, rim_e = (base_energy * r for r in p['ratio'])
# Remove existing lights
for o in list(bpy.data.objects):
if o.type == 'LIGHT' and (o.name.startswith('LGT-key') or o.name.startswith('LGT-fill') or o.name.startswith('LGT-rim')):
bpy.data.objects.remove(o, do_unlink=True)
# KEY (warm, front-right above)
key = bpy.data.objects.new('LGT-key', bpy.data.lights.new('LGT-key', type='AREA'))
key.data.energy = key_e; key.data.size = 0.5; key.data.color = p['key_color']
bpy.context.collection.objects.link(key)
key.location = (center.x + light_dist*0.7, center.y - light_dist*0.7, center.z + light_dist*0.5)
aim_at(key, center)
# FILL (cool, opposite, weaker)
fill = bpy.data.objects.new('LGT-fill', bpy.data.lights.new('LGT-fill', type='AREA'))
fill.data.energy = fill_e; fill.data.size = 1.0; fill.data.color = p['fill_color']
bpy.context.collection.objects.link(fill)
fill.location = (center.x - light_dist*0.7, center.y - light_dist*0.5, center.z + light_dist*0.3)
aim_at(fill, center)
# RIM
rim_type = 'AREA' if subject_class == 'glass' else 'SPOT'
rim = bpy.data.objects.new('LGT-rim', bpy.data.lights.new('LGT-rim', type=rim_type))
rim.data.energy = rim_e; rim.data.color = p['rim_color']
if rim_type == 'AREA':
rim.data.size = 1.5 # larger soft-source for glass
else:
rim.data.spot_size = math.radians(50)
bpy.context.collection.objects.link(rim)
rim.location = (center.x, center.y + light_dist, center.z + light_dist*0.5)
aim_at(rim, center)
print(f"lighting:{subject_class} key:fill:rim={p['ratio']} dist={light_dist:.2f}m")
# Usage:
# apply_three_point('glass') # for the wine bottle
# apply_three_point('wood') # for the chair
# apply_three_point('metal') # for the sword (or omit; 'metal' is default)
レシピ 0b — 被写体に向けた三点照明(汎用、クラスのヒントなし)
特定の被写体があり、クラスは考慮しなくてよい場合は、レシピ 1 の代わりにこちらを使います。ライトは、被写体の最も長い寸法に比例して配置されます。
import bpy, math
from mathutils import Vector
def aim_at(light_obj, target):
target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
direction = (target_pos - light_obj.location).normalized()
light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
# Determine subject and its scale
subject_meshes = [o for o in bpy.data.objects if o.type == 'MESH' and o.name.startswith('GEO-')]
deps = bpy.context.evaluated_depsgraph_get()
all_verts = []
for o in subject_meshes:
eo = o.evaluated_get(deps); em = eo.to_mesh()
for v in em.vertices:
all_verts.append(o.matrix_world @ v.co)
eo.to_mesh_clear()
xs = [v.x for v in all_verts]; ys = [v.y for v in all_verts]; zs = [v.z for v in all_verts]
center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
extent = max(max(xs)-min(xs), max(ys)-min(ys), max(zs)-min(zs))
light_dist = max(extent * 1.5, 1.0)
# Energy values scale roughly inversely with squared distance from subject — recipe targets
# physically reasonable values for a ~1m subject at ~1.5m light distance.
key_energy = 100 * (light_dist / 1.5) ** 2
fill_energy = key_energy * 0.3
rim_energy = key_energy * 0.8
# KEY (warm, front-right above)
key = bpy.data.objects.new('LGT-key', bpy.data.lights.new('LGT-key', type='AREA'))
key.data.energy = key_energy; key.data.size = 0.5; key.data.color = (1.0, 0.95, 0.85)
bpy.context.collection.objects.link(key)
key.location = (center.x + light_dist * 0.7, center.y - light_dist * 0.7, center.z + light_dist * 0.5)
aim_at(key, center)
# FILL (cool, opposite, weaker)
fill = bpy.data.objects.new('LGT-fill', bpy.data.lights.new('LGT-fill', type='AREA'))
fill.data.energy = fill_energy; fill.data.size = 1.0; fill.data.color = (0.85, 0.9, 1.0)
bpy.context.collection.objects.link(fill)
fill.location = (center.x - light_dist * 0.7, center.y - light_dist * 0.5, center.z + light_dist * 0.3)
aim_at(fill, center)
# RIM (cool, behind, separates subject from BG)
rim = bpy.data.objects.new('LGT-rim', bpy.data.lights.new('LGT-rim', type='SPOT'))
rim.data.energy = rim_energy; rim.data.color = (0.7, 0.85, 1.0); rim.data.spot_size = math.radians(50)
bpy.context.collection.objects.link(rim)
rim.location = (center.x, center.y + light_dist, center.z + light_dist * 0.5)
aim_at(rim, center)
print(f'lighting:three_point_aimed center={tuple(round(v,2) for v in center)} extent={extent:.2f}m dist={light_dist:.2f}m')
レシピ 0c — 実用照明(シーン内に発光源がある場合)
被写体そのものが光源である場合、または光源を含む場合(電球付きのデスクランプ、炎のあるろうそく、画面が光るモニター、ネオンサインなど)、シーンには別の設定が必要です。
- ワールド背景を暗くします(Strength 0.10–0.20)。そうしないと、電球の光が環境光に埋もれてしまいます。
- 標準の3点照明によるフィルライト/リムライトを弱めるか、取り除きます。実用照明を主役にします。
- 控えめな環境フィルを残します(カメラ方向からの8-15WのAreaライト)。ランプ本体を見えるようにするためです。実用照明だけのレンダリングでは、ランプの形状が影に沈んでしまいます。
- 小さなメッシュ発光体のEmission Strengthを高く設定します(
blender-materialsのレシピ11bを参照してください。球状の電球を本物の電球のように見せるにはStrength 800-3000が必要です)。 - 適切なシェード内部の照明には、Cyclesの
max_bouncesを16以上にします。電球の光がシェード内部で反射し、開口部から外へ出る必要があります。
import bpy
from mathutils import Vector
def aim_at(light_obj, target):
target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
direction = (target_pos - light_obj.location).normalized()
light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
# Dim world (let the practical dominate)
world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
for n in list(nodes): nodes.remove(n)
output = nodes.new('ShaderNodeOutputWorld')
bg = nodes.new('ShaderNodeBackground')
bg.inputs['Color'].default_value = (0.02, 0.02, 0.03, 1.0)
bg.inputs['Strength'].default_value = 0.15
world.node_tree.links.new(bg.outputs['Background'], output.inputs['Surface'])
# Single subtle ambient fill from camera direction
fill = bpy.data.objects.new('LGT-ambient_fill', bpy.data.lights.new('LGT-ambient_fill', type='AREA'))
fill.data.energy = 8; fill.data.size = 1.0; fill.data.color = (0.85, 0.9, 1.0)
bpy.context.collection.objects.link(fill)
fill.location = (0.5, -0.8, 0.5)
aim_at(fill, Vector((0, 0, 0.3)))
# Cycles bounces
scene = bpy.context.scene
scene.cycles.max_bounces = 16
print('lighting:practical_setup')
実用照明のEmissionシェーダー(メッシュ発光の電球/ろうそくの炎など)が残りを担います。シーンは、照明された被写体を撮影した実際の写真のように見えます。周囲は暗く、実用照明から暖色の光だまりが広がり、被写体のシルエットは柔らかく照らされます。
検証例:この設定で生成される画像は、text-to-blender/assets/v1.1.0-validation/desk_lamp_emission.webp を参照してください(電球の光が見えるデスクランプ、机の表面に広がる暖色の光だまり、暗いシーンの中で見えるランプ本体)。
レシピ 1 — 3点照明(基本のセットアップ)
import bpy, math
# KEY LIGHT (warm, front-right)
key_data = bpy.data.lights.new('LGT-key', type='AREA')
key_data.energy = 1000
key_data.size = 1.0
key_data.color = (1.0, 0.95, 0.85) # warm tungsten ~3200K
key = bpy.data.objects.new('LGT-key', key_data)
bpy.context.collection.objects.link(key)
key.location = (3, -3, 3.5)
key.rotation_euler = (math.radians(35), math.radians(45), 0)
# FILL LIGHT (cool, front-left, weaker)
fill_data = bpy.data.lights.new('LGT-fill', type='AREA')
fill_data.energy = 300
fill_data.size = 2.0
fill_data.color = (0.85, 0.9, 1.0) # cool sky ~6500K
fill = bpy.data.objects.new('LGT-fill', fill_data)
bpy.context.collection.objects.link(fill)
fill.location = (-3, -2, 2.5)
fill.rotation_euler = (math.radians(50), math.radians(-45), 0)
# BACK / RIM LIGHT (cool, behind subject)
rim_data = bpy.data.lights.new('LGT-rim', type='SPOT')
rim_data.energy = 600
rim_data.spot_size = math.radians(40)
rim_data.color = (0.7, 0.85, 1.0)
rim = bpy.data.objects.new('LGT-rim', rim_data)
bpy.context.collection.objects.link(rim)
rim.location = (0, 4, 3.0)
rim.rotation_euler = (math.radians(120), 0, math.radians(180))
print('lighting:three_point')
標準的な比率:
- ハイキー(商業写真):キー:フィル = 2:1
- ミディアム(ポートレート):4:1
- ローキー(ドラマチック):8:1以上
- リム:キーの50–100%
レシピ 2 — HDRI環境
import bpy
world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
links = world.node_tree.links
# Wipe existing world nodes
for n in list(nodes):
nodes.remove(n)
# Output → Background ← Environment Texture ← Mapping ← Texture Coordinate
output = nodes.new('ShaderNodeOutputWorld'); output.location = (300, 0)
bg = nodes.new('ShaderNodeBackground'); bg.location = (100, 0)
bg.inputs['Strength'].default_value = 1.0
env = nodes.new('ShaderNodeTexEnvironment'); env.location = (-100, 0)
env.image = bpy.data.images.load('/path/to/your.hdr') # ← user provides path
mapping = nodes.new('ShaderNodeMapping'); mapping.location = (-300, 0)
tex_coord = nodes.new('ShaderNodeTexCoord'); tex_coord.location = (-500, 0)
links.new(tex_coord.outputs['Generated'], mapping.inputs['Vector'])
links.new(mapping.outputs['Vector'], env.inputs['Vector'])
links.new(env.outputs['Color'], bg.inputs['Color'])
links.new(bg.outputs['Background'], output.inputs['Surface'])
print('lighting:hdri')
プロ向けの情報源:polyhaven.com/hdris に無料のHDRIがあります(CC0)。
レシピ 3 — 晴れた屋外
import bpy, math
sun_data = bpy.data.lights.new('LGT-sun', type='SUN')
sun_data.energy = 5.0
sun_data.color = (1.0, 0.95, 0.8) # golden hour
sun_data.angle = math.radians(0.5) # realistic sun size; bigger = softer
sun = bpy.data.objects.new('LGT-sun', sun_data)
bpy.context.collection.objects.link(sun)
sun.location = (0, 0, 10)
sun.rotation_euler = (math.radians(45), math.radians(15), 0)
print('lighting:outdoor_sun')
自然な環境フィルを得るには、HDRIの空環境(レシピ2)と組み合わせます。
レシピ 4 — 屋内の窓からの光
import bpy, math
# Sun coming through window — cool blue, sharp
sun_data = bpy.data.lights.new('LGT-window_sun', type='SUN')
sun_data.energy = 3.0
sun_data.color = (0.85, 0.9, 1.0)
sun_data.angle = math.radians(2.0) # softer than direct sun
sun = bpy.data.objects.new('LGT-window_sun', sun_data)
bpy.context.collection.objects.link(sun)
sun.location = (5, -3, 4)
sun.rotation_euler = (math.radians(60), math.radians(-30), 0)
# Practical lamp — warm point light
lamp_data = bpy.data.lights.new('LGT-lamp', type='POINT')
lamp_data.energy = 60
lamp_data.color = (1.0, 0.7, 0.4) # warm bulb
lamp = bpy.data.objects.new('LGT-lamp', lamp_data)
bpy.context.collection.objects.link(lamp)
lamp.location = (-1, 2, 1.5)
print('lighting:indoor_window')
レシピ 5 — ドラマチックな単一光源
import bpy, math
spot_data = bpy.data.lights.new('LGT-drama', type='SPOT')
spot_data.energy = 800
spot_data.spot_size = math.radians(30)
spot_data.spot_blend = 0.3
spot_data.color = (1.0, 0.95, 0.85)
spot = bpy.data.objects.new('LGT-drama', spot_data)
bpy.context.collection.objects.link(spot)
spot.location = (2, -2, 6)
spot.rotation_euler = (math.radians(60), 0, 0)
print('lighting:dramatic')
本格的なノワール表現にするには、強いボリューメトリクス(大気)と組み合わせます。ボリューメトリクスの設定については、references/overview.md を参照してください。
レシピ 6 — 色温度の早見表
| 光源 | RGB |
|---|---|
| ろうそく(1850K) | (1.0, 0.6, 0.3) |
| タングステン(3200K) | (1.0, 0.85, 0.6) |
| 暖色LED(3000K) | (1.0, 0.8, 0.6) |
| 夕焼け/ゴールデン(3500K) | (1.0, 0.85, 0.65) |
| 正午の昼光(5500K) | (1.0, 1.0, 1.0) |
| 曇り空(6500K) | (0.95, 0.95, 1.0) |
| ブルーアワー(8000K) | (0.8, 0.9, 1.0) |
プロ向けの組み合わせ:暖色のキーライト(タングステン)+寒色のフィルライト(昼光)=ハリウッド風の「ゴールド/ティール」表現です。
レシピ 7 — ソフトシャドウとハードシャドウの調整
import bpy, math
light_data = bpy.data.lights['LGT-key']
# Make shadows softer
light_data.size = 2.0 # Area: bigger size = softer shadow
# Or for Sun:
# light_data.angle = math.radians(5) # bigger angle = softer shadow
# Make shadows harder (crisp)
# light_data.size = 0.1
# Or:
# light_data.angle = math.radians(0.5)
命名規則
| 接頭辞 | 意味 |
|---|---|
LGT-key | メインライト/キーライト |
LGT-fill | フィルライト |
LGT-rim / LGT-back | リムライトまたはバックライト |
LGT-sun | サンライト |
LGT-{name} | 実用照明(ランプ、ろうそく、ネオンなど) |
よくある問題
| 症状 | 対処法 |
|---|---|
| モデルの半分が真っ黒になる | フィルライト(AreaライトまたはHDRI)を追加します |
| レンダリングが「平坦」に見える | キー:フィルの比率を上げ、リムライトを追加します |
| あらゆる場所に硬い影ができる | AreaライトのサイズまたはSunの角度を大きくします |
| 全体的に暗すぎる | View Transformの露出またはHDRIの強度を上げます |
| マテリアルに反射がない | 必ずワールド環境(HDRI)を設定します |
| オブジェクト内に光がある | ワールド座標を確認します。光源がカメラから見える必要があります |
| バックライトで被写体が白飛びする | リムライトのエネルギーをキーライトのエネルギー以下にします |
references/overview.md を読み込むタイミング
次の場合に読み込みます:
- レシピにない設定(ボリューメトリックのゴッドレイ、ライトグループ、ライトリンク)をユーザーが求めている
- HDRIの回転や強度をデフォルト値以上に調整する必要がある
- 複数のライトがあるシーン(ランプが5個以上)で整理が必要
- 色彩科学やカラー管理について具体的な設定が必要(AgX、Filmic)
このリファレンスでは、5種類すべてのライトの詳細、HDRIのワークフロー全体、コンポジターで再照明するためのライトグループ、製品/ポートレート/建築/キャラクター/アニメーション向けの表現レシピを扱っています。