はじめに
Blenderが5.0になりました。
とりあえずなにかレンダリングしたいと思ったときに、このスクリプトを実行すれば、コーネルボックスのシーンが完成し、レンダリングできます。
ガラス球は3つ同位置にあるので、不要な2つは削除してください。
- ポリゴン球
- NURBS球
- Metaball球
時間計測
Render Deviceの違い
MacBookPro M1Pro
CPU: P 8 Core + E 2 Core
GPU: 16 core
| Cycles Render Device | sec |
|---|---|
| GPU + CPU | 6.45 |
| GPU | 7.05 |
| CPU | 14.17 |
結果:内蔵GPUはCPUより2倍速い。
同時使用はちょい速。
ガラス球(データ構造)の違い
内蔵GPUのみでレンダリング
| Glass Sphere | sec |
|---|---|
| ポリゴン | 7.06 |
| NURBS | 7.06 |
| Metaball | 7.04 |
結果:誤差レベルな気もするが、metaballがほんの少し大きいことを考慮すると、metaballがほんの少し有利かも?
コード
cornelBox.bpy
import bpy
import math
from mathutils import Vector
# -----------------------------
# 0. シーン初期化
# -----------------------------
# 既存オブジェクト削除
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# ワールドをシンプルなホワイトに
if bpy.data.worlds:
world = bpy.data.worlds[0]
else:
world = bpy.data.worlds.new("World")
bpy.context.scene.world = world
world.use_nodes = True
# ワールドノードを作り直し
wnodes = world.node_tree.nodes
wlinks = world.node_tree.links
wnodes.clear()
bg = wnodes.new("ShaderNodeBackground")
bg.location = (0, 0)
wout = wnodes.new("ShaderNodeOutputWorld")
wout.location = (200, 0)
wlinks.new(bg.outputs["Background"], wout.inputs["Surface"])
bg.inputs[0].default_value = (1, 1, 1, 1)
bg.inputs[1].default_value = 0.1 # Strength ambient
# -----------------------------
# 1. Cycles / GPU / OptiX 設定
# -----------------------------
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
# Cycles を GPU に
scene.cycles.device = 'GPU'
# 可能なら OptiX を有効化(環境依存なので try)
try:
prefs = bpy.context.preferences.addons["cycles"].preferences
# 'CUDA', 'OPTIX', 'HIP', 'METAL' など
prefs.compute_device_type = 'OPTIX' # RTX 用
for dev in prefs.devices:
dev.use = True
except Exception as e:
print("GPU/OptiX 設定でエラー:", e)
print("Preferences > System で手動確認してください。")
# サンプリング設定
scene.cycles.samples = 256 # Render
scene.cycles.preview_samples = 64 # Viewport
scene.cycles.use_adaptive_sampling = True
# デノイズ(OptiX)
scene.cycles.use_denoising = True
# scene.cycles.denoiser = 'OPTIX'
# Light bounces
scene.cycles.max_bounces = 8
scene.cycles.diffuse_bounces = 4
scene.cycles.glossy_bounces = 4
scene.cycles.transmission_bounces = 4
# -----------------------------
# 2. マテリアルの作成
# -----------------------------
def make_diffuse_mat(name, color, rough=0.6):
mat = bpy.data.materials.new(name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# 既存ノードを消してから作り直す
nodes.clear()
bsdf = nodes.new("ShaderNodeBsdfPrincipled")
bsdf.location = (0, 0)
out = nodes.new("ShaderNodeOutputMaterial")
out.location = (200, 0)
links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])
bsdf.inputs["Base Color"].default_value = (*color, 1.0)
bsdf.inputs["Roughness"].default_value = rough
return mat
# 壁用
mat_white = make_diffuse_mat("White", (0.8, 0.8, 0.8))
mat_red = make_diffuse_mat("Red", (0.9, 0.0, 0.0))
mat_green = make_diffuse_mat("Green", (0.0, 0.9, 0.0))
# 中の箱用(金属)
mat_metal = bpy.data.materials.new("Metal")
mat_metal.use_nodes = True
nodes = mat_metal.node_tree.nodes
links = mat_metal.node_tree.links
nodes.clear()
metal_bsdf = nodes.new("ShaderNodeBsdfPrincipled")
metal_bsdf.location = (0, 0)
metal_out = nodes.new("ShaderNodeOutputMaterial")
metal_out.location = (200, 0)
links.new(metal_bsdf.outputs["BSDF"], metal_out.inputs["Surface"])
metal_bsdf.inputs["Base Color"].default_value = (0.9, 0.9, 0.9, 1.0)
metal_bsdf.inputs["Metallic"].default_value = 1.0
metal_bsdf.inputs["Roughness"].default_value = 0.15
# ガラス用マテリアル
mat_glass = bpy.data.materials.new("Glass")
mat_glass.use_nodes = True
gnodes = mat_glass.node_tree.nodes
glinks = mat_glass.node_tree.links
gnodes.clear()
glass_bsdf = gnodes.new("ShaderNodeBsdfGlass")
glass_bsdf.location = (0, 0)
glass_bsdf.inputs["IOR"].default_value = 1.45
glass_bsdf.inputs["Roughness"].default_value = 0.0
glass_out = gnodes.new("ShaderNodeOutputMaterial")
glass_out.location = (200, 0)
glinks.new(glass_bsdf.outputs["BSDF"], glass_out.inputs["Surface"])
# -----------------------------
# 3. コーネルボックスの壁を作る
# -----------------------------
def add_wall(name, size_x, size_y, loc, rot, mat):
bpy.ops.mesh.primitive_plane_add(size=1, location=loc, rotation=rot)
obj = bpy.context.active_object
obj.name = name
obj.scale.x = size_x
obj.scale.y = size_y
if mat:
if obj.data.materials:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
return obj
# 床
floor = add_wall("Floor", 2, 2, (0, 0, 0), (0, 0, 0), mat_white)
ceiling = add_wall("Ceiling", 2, 2, (0, 0, 2), (0, 0, 0), mat_white)
back = add_wall("Back", 2, 2, (0, 1, 1), (math.pi / 2, 0, 0), mat_white)
left = add_wall("Left", 2, 2,(-1, 0, 1), (0, math.pi / 2, 0), mat_red)
right = add_wall("Right", 2, 2, (1, 0, 1), (0, math.pi / 2, 0), mat_green)
# -----------------------------
# 4. 中の箱を2つ追加
# -----------------------------
def add_box(name, size, loc, rot=(0, 0, 0), mat=None):
bpy.ops.mesh.primitive_cube_add(size=1, location=loc, rotation=rot)
obj = bpy.context.active_object
obj.name = name
obj.scale = Vector(size)
if mat:
if obj.data.materials:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
return obj
# 手前の白い箱(低め)
box1 = add_box(
"Box1",
size=(0.6, 0.6, 0.6),
loc=( 0.4, -0.3, 0.3),
rot=(0, 0, math.radians(-30)),
mat=mat_white
)
# 奥の金属箱(高め)
box2 = add_box(
"Box2",
size=(0.6, 0.6, 1.2),
loc=(-0.3, 0.2, 0.6),
rot=(0, 0, math.radians(30)),
mat=mat_metal
)
# -----------------------------
# 5. 天井のエリアライト
# -----------------------------
bpy.ops.object.light_add(
type='AREA',
location=(0, 0, 1.999)
)
light = bpy.context.active_object
light.name = "CeilingLight"
light.data.size = 0.5
light.data.energy = 20.0
light.data.shape = 'SQUARE'
light.rotation_euler = (math.radians(180), 0, 0)
# -----------------------------
# 6. ガラス球を追加
# -----------------------------
bpy.ops.mesh.primitive_uv_sphere_add(
segments=64, # 横の分割数
ring_count=32, # 縦の分割数
radius=0.25,
location=(-0.26, -0.5, 0.3)
)
bpy.ops.object.shade_smooth()
sphere = bpy.context.active_object
sphere.name = "GlassSphere"
sphere.data.materials.append(mat_glass)
# -----------------------------
# ガラス球を NURBS で追加
# -----------------------------
bpy.ops.surface.primitive_nurbs_surface_sphere_add(
radius=0.25,
location=(-0.26, -0.5, 0.3)
)
sphere = bpy.context.active_object
sphere.name = "GlassSphere_NURBS"
# 解像度(滑らかさ)を少し上げる
for spl in sphere.data.splines:
spl.resolution_u = 8
spl.resolution_v = 8
# マテリアルをガラスに
if sphere.data.materials:
sphere.data.materials[0] = mat_glass
else:
sphere.data.materials.append(mat_glass)
# -----------------------------
# ガラス球をImplicit Surface(Metaball)で追加
# -----------------------------
bpy.ops.object.metaball_add(
type='BALL',
radius=0.5,
location=(-0.26, -0.5, 0.3)
)
sphere = bpy.context.active_object
sphere.name = "GlassSphere_Implicit"
sphere.data.resolution = 0.05 # ← 小さいほどツルツル(0.02〜0.1)
sphere.data.materials.append(mat_glass)
# -----------------------------
# 7. カメラの配置
# -----------------------------
cam = None
for obj in bpy.data.objects:
if obj.type == 'CAMERA':
cam = obj
break
if cam is None:
bpy.ops.object.camera_add()
cam = bpy.context.active_object
cam.name = "CornellCamera"
cam.location = (0, -3, 1)
target = Vector((0, 0, 1))
direction = target - cam.location
cam.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
cam.data.lens = 35 # mm
scene.camera = cam
# -----------------------------
# 8. 解像度などレンダ設定
# -----------------------------
scene.render.resolution_x = 512
scene.render.resolution_y = 512
scene.render.resolution_percentage = 100
print("コーネルボックスを生成。F12でレンダリング")
M5プロセッサGPUだとどのぐらい速いのかな?

