動作確認済み環境
- Windows 11
- Blender 3.6.14
何をするのか
PLATEAUの3DモデルからBlenderで河口付近の川や海を削除します。
(以下画像の左から右へ)
手順
Unityで、PLATEAU SDKを使って、3D都市モデルをFBX化し、
それをBlenderにインポートした状態から始めます。
(本件では福山市芦田川流域を例にします)
単純に考えると海抜が低いところが、川か海だろうから、 Y座標が1.0以下の頂点を削除してもらうスクリプトをChatGPTに作ってもらいました。
import bpy
import bmesh
# 現在のオブジェクトを取得
obj = bpy.context.active_object
# オブジェクトがメッシュであることを確認
if obj.type != 'MESH':
raise TypeError("Active object is not a mesh")
# 編集モードに切り替え
bpy.ops.object.mode_set(mode='EDIT')
# BMeshの作成
bm = bmesh.from_edit_mesh(obj.data)
# Y座標が1.0以下の頂点を削除するためのリストを設定
verts_to_remove = [v for v in bm.verts if v.co.y <= 1.0]
# 取り出した頂点を削除
bmesh.ops.delete(bm, geom=verts_to_remove, context='VERTS')
# 編集モードの変更をBlenderに反映
bmesh.update_edit_mesh(obj.data)
# オブジェクトモードに戻す
bpy.ops.object.mode_set(mode='OBJECT')
このコードをBlenderで動かすには、
Blender の以下画像部分の
1の「スクリプト作成」をクリック
2の場所に以下のコードを入れます。
海や川以外に、一部低い陸地も削除されました。
川の方が高い場所があることを考慮に入れてませんでした。
川より低い陸地問題を解決するには、
ある程度範囲をしぼって、
その範囲の中から、
Yが1以下の頂点を削除したらいいのではないか?と考え、
以下スクリプトをChatGPTに作ってもらいました。
import bpy
import bmesh
# オブジェクトを編集モードに変更
bpy.ops.object.mode_set(mode='EDIT')
# BMeshの取得
mesh = bmesh.from_edit_mesh(bpy.context.object.data)
# 削除する頂点をリスト化
verts_to_delete = [vert for vert in mesh.verts if vert.select and vert.co.y <= 1]
# 頂点の削除
bmesh.ops.delete(mesh, geom=verts_to_delete, context='VERTS')
# メッシュの更新
bmesh.update_edit_mesh(bpy.context.object.data)
編集モードで、
削除したい範囲を選択して、
先ほどののスクリププトを実行します。
お、いい感じに海と川が削除できました。
あとは手動で微調整します。
ただ、これだとちょっと上流が難しいです。
それで、以下の方法をとりました。
手動でだいたい高さのあたりをつけます。
これだと、どこなのかよく分からないので、ここをクリックして、テクスチャを重ねます。
適当に川の部分や近くの陸の部分のYのサイズを測ります。
いろいろ測ってみて、
Y座標が1.7以上2.7以下が川部分と思われます。
以下ChatGPTに 選択した場所について、Y座標が1.7以上2.7以下のものを削除するスクリプトを作ってもらいました。
import bpy
import bmesh
# オブジェクトを編集モードに変更
bpy.ops.object.mode_set(mode='EDIT')
# BMeshの取得
mesh = bmesh.from_edit_mesh(bpy.context.object.data)
# 削除する頂点をリスト化(Y座標が1.7以上2.7以下のもの)
verts_to_delete = [vert for vert in mesh.verts if vert.select and 1.7 <= vert.co.y <= 2.7]
# 頂点の削除
bmesh.ops.delete(mesh, geom=verts_to_delete, context='VERTS')
# メッシュの更新
bmesh.update_edit_mesh(bpy.context.object.data)
実行
だいたい削除されました。
あとは、手動で削除します。
なんだ、結局手動?
と思うかもしれませんが、
ある程度あたりがつけられるので、私には楽ちんでした。
最終的にできたのがこれです。
もっと細かくやればよかったと後悔してますが、
とりあえずは以上です。