0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コーネルボックスのBlenderスクリプト

Posted at

a.png

はじめに

Blenderが5.0になりました。
とりあえずなにかレンダリングしたいと思ったときに、このスクリプトを実行すれば、コーネルボックスのシーンが完成し、レンダリングできます。

ガラス球は3つ同位置にあるので、不要な2つは削除してください。

  • ポリゴン球
  • NURBS球
  • Metaball球

時間計測

Render Deviceの違い

MacBookPro M1Pro
CPU: P 8 Core + E 2 Core
GPU: 16 core

image.png

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だとどのぐらい速いのかな?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?