Godot入門:CSGBox3Dの使い方と活用法

はじめに

3Dレベルデザインやプロトタイプ開発で、複雑な形状を素早く作る必要があることがあります。「この部分を切り取りたい」「2つの形を組み合わせたい」——こうした要望を簡単に実現するのがCSGBox3Dです。CSG(Constructive Solid Geometry)という手法でメッシュを組み合わせることで、複雑な3D形状を効率的に設計できます。

本記事では、CSGBox3Dとその仲間たち、そしてCSGの本質を、実装パターンを交えて解説します。

CSGBox3Dとは?

CSGBox3Dは、ブーリアン演算を用いて立方体型の3Dオブジェクトを作成・結合するノードです。他のCSGプリミティブと組み合わせることで、複雑な形状を簡単に設計できます。

継承ツリー:

CSGBox3D → CSGPrimitive3D → CSGShape3D → GeometryInstance3D → VisualInstance3D → Node3D → Node → Object

CSGの「構築的立体幾何」とは、単純な形(立方体、球体、円柱)を組み合わせ、加算・減算・交差といった演算を用いて複雑な形を作る手法です。ゲーム開発では、プロトタイプやレベルデザインの高速化に欠かせません。

このノードを使うべき場面

活躍する場面:

  • ゲームプロトタイプの素早い環境構築
  • レベルデザインの初期段階(調整が多い場合)
  • 建築物やダンジョンの型抜き(ドア・窓の形状)
  • 複雑な壁配置や障害物の配置
  • ゲームジャムなど時間が限定された開発

使わない場面:

  • 本番ゲーム(パフォーマンス最適化後は MeshInstance3D に置き換え)
  • 高度にディテールが必要なアセット(モデリングソフトで作成)
  • 頻繁に動く複雑な形状(負荷が高い)

主なプロパティと機能

CSGBox3Dの基本的なプロパティを表にまとめました:

プロパティ 説明 デフォルト値
size Vector3 立方体のサイズ(X, Y, Z) Vector3(2, 2, 2)
material Material 表面のマテリアル null
use_collision bool 衝突判定を有効にするか false
collision_layer int 所属するコリジョンレイヤー 1
collision_mask int 検出するコリジョンレイヤー 1
operation enum ブーリアン演算の種類 OPERATION_UNION

基本的な使用例:


extends Node3D

@onready var csg_box = $CSGBox3D

func _ready():
	# シンプルな立方体
	csg_box.size = Vector3(2, 2, 2)
	csg_box.material = StandardMaterial3D.new()
	csg_box.material.albedo_color = Color.GRAY

	# 衝突判定を有効化
	csg_box.use_collision = true
	csg_box.collision_layer = 1
	csg_box.collision_mask = 1

	print("CSGBox3D が作成されました: サイズ", csg_box.size)




CSGのブーリアン演算(UNION, INTERSECTION, SUBTRACTION)
CSGのブーリアン演算により、複雑な形状を簡単に作成できます

ドア・窓の型抜き実装例:


extends Node3D

func _ready():
	# 壁となるCSGBox3D(親)
	var wall = CSGBox3D.new()
	wall.size = Vector3(10, 5, 1)
	wall.material = StandardMaterial3D.new()
	wall.material.albedo_color = Color(0.8, 0.7, 0.6)  # 土色
	wall.use_collision = true
	add_child(wall)

	# ドアの穴をくり抜く(CSGBox3D)
	var door_hole = CSGBox3D.new()
	door_hole.size = Vector3(2, 3, 1.5)
	door_hole.position = Vector3(3, 1, 0)  # 壁の右上に配置
	door_hole.operation = CSGShape3D.OPERATION_SUBTRACTION  # 減算演算
	wall.add_child(door_hole)

	# 窓の穴をくり抜く(CSGBox3D)
	var window_hole = CSGBox3D.new()
	window_hole.size = Vector3(2, 1.5, 1.5)
	window_hole.position = Vector3(-3, 3, 0)  # 壁の左上に配置
	window_hole.operation = CSGShape3D.OPERATION_SUBTRACTION  # 減算演算
	wall.add_child(window_hole)

	print("壁にドアと窓がくり抜かれました")

CSGの仲間たち

CSGBox3D だけでなく、複数のプリミティブが用意されています:

CSGノード 形状 主要プロパティ 用途例
CSGBox3D 立方体 size 壁、床、建築物
CSGSphere3D 球体 radius, radial_segments, rings 爆発範囲、丸い装飾
CSGCylinder3D 円柱 radius, height 柱、パイプ、筒状オブジェクト
CSGMesh3D 任意のメッシュ mesh 複雑な形状の加工
CSGCombiner3D 複合形状の親 なし(コンテナ) 複数のCSGを統合

CSGCombiner3D を使った複合形状の作り方

複数のCSGノードを組み合わせる場合、CSGCombiner3D を親として使うと整理しやすくなります:


extends Node3D

func _ready():
	# CSGCombiner3D(複合体の親)
	var combiner = CSGCombiner3D.new()
	add_child(combiner)

	# 基盤(床)
	var base = CSGBox3D.new()
	base.size = Vector3(5, 0.5, 5)
	base.position = Vector3(0, 0, 0)
	base.operation = CSGShape3D.OPERATION_UNION
	combiner.add_child(base)

	# 塔(中央)
	var tower = CSGCylinder3D.new()
	tower.radius = 1.0
	tower.height = 4.0
	tower.position = Vector3(0, 2, 0)
	tower.operation = CSGShape3D.OPERATION_UNION
	combiner.add_child(tower)

	# 球の装飾(塔の頂上)
	var decoration = CSGSphere3D.new()
	decoration.radius = 0.7
	decoration.position = Vector3(0, 4.5, 0)
	decoration.operation = CSGShape3D.OPERATION_UNION
	combiner.add_child(decoration)

	# コアをくり抜く(塔の内部)
	var core = CSGCylinder3D.new()
	core.radius = 0.6
	core.height = 4.5
	core.position = Vector3(0, 2, 0)
	core.operation = CSGShape3D.OPERATION_SUBTRACTION
	combiner.add_child(core)

	print("複合形状が作成されました")




CSGCombiner3Dによる複合形状の階層構造
CSGCombiner3D を使い複数のプリミティブを統合することで、複雑な形状が実現できます

もっと使いこなす:カスタマイズできるパラメータ

まずは基本を動かしてみてから、余裕が出たら試してみてください。

パラメータ 設定値の例 効果
smoothing_enabled true/false スムーズシェーディング。true で滑らかな見た目
invert_faces true/false 面の向きを反転。内側を表示したい場合に使用
material StandardMaterial3D など 色・テクスチャなどの外観設定
collision_layer / mask 1 〜 32 複数のレイヤーで衝突判定を細かく制御
operation UNION / INTERSECTION / SUBTRACTION 他のCSGとの演算方式を指定

本番環境への置き換え:MeshInstance3D + CollisionShape3D

プロトタイプから本番環境への移行では、CSGを MeshInstance3D に置き換えることが推奨されます。理由はパフォーマンス最適化です:


# CSGを使った設計完了後、本番用に置き換える例

# 方法1: CSGから静的メッシュをエクスポート
# Godot Editor で、CSGShape3D を右クリック → "メッシュをエクスポート"

# 方法2: プログラムで置き換え
func convert_csg_to_mesh(csg_node: CSGShape3D):
	var mesh_instance = MeshInstance3D.new()
	mesh_instance.mesh = csg_node.get_meshes()[1]  # CSGのメッシュを取得
	mesh_instance.material_override = csg_node.material

	var collision_shape = CollisionShape3D.new()
	collision_shape.shape = csg_node.get_collision_shape()

	return [mesh_instance, collision_shape]




CSG設計から最終MeshInstance3Dへの置き換え
開発ではCSGで素早く設計、本番ではMeshInstance3Dで最適化

まとめ

CSGBox3D とそのCSGファミリーは、3D環境のプロトタイピングを劇的に高速化するノードです。ブーリアン演算を活用することで、複雑な形状も直感的に設計できます。ただし本番環境ではパフォーマンスのため MeshInstance3D への置き換えが推奨されます。

  • OPERATION_UNION(加算)・SUBTRACTION(減算)・INTERSECTION(交差)を使い分けることで、複雑な形状が簡単に作成できる
  • use_collision を有効化することで、CSG形状そのものが衝突判定として機能
  • CSGCombiner3D で複数のプリミティブを統合し、整理された階層構造を作る
  • 開発完了後は、パフォーマンス最適化のため MeshInstance3D への置き換えを検討

次回は GridMap について解説します。タイルベースの3D環境を効率的に構築するノードです。

この記事はGodot 4.xをもとに執筆しています。

シリーズ:Godot 4 ノード解説

001〜040:各種ノード

  • 041:Control
  • 042:Button
  • 043:Label
  • 044:TextEdit
  • 045:Panel
  • 046:VBoxContainer
  • 047:AnimationPlayer
  • 048:Timer
  • 049:Area3D
  • 050:RigidBody3D
  • 051:CharacterBody3D
  • 052:CollisionShape3D
  • 053:MeshInstance3D
  • 054:Node3D
  • 055:Camera3D
  • 056:Sprite3D
  • 057:DirectionalLight3D
  • 058:OmniLight3D
  • 059:ReflectionProbe
  • 060:VisibleOnScreenNotifier3D
  • 061:SpotLight3D
  • 062:WorldEnvironment
  • 063:AudioStreamPlayer3D
  • 064:GPUParticles3D
  • 065:CSGBox3D
  • 066:GridMap
  • 067:Decal
  • 068:OccluderInstance3D
  • 069:LightmapGI
  • 070:SubViewport

コメント