格子状に整理されたデータをBlenderで可視化する

2次元の格子に高さのデータを持たせたデータ,すなわち
2次元スカラー場からグリッドオブジェクトを作成するスクリプトです.
2次元スカラー場に該当する構造を持つデータの例としては,単一バントの
画像データ(ラスタデータ)や,
デジタル標高モデル(DEMデータ)等が挙げられます.
テキストファイルの準備
まずは,
2次元スカラー場のデータを用意しましょう.本ページのスクリプトをそのまま使いたい場合は,
以下のようなテキストファイルを作成して任意の場所に保存してください.

i,
jはグリッド内頂点の位置を示すインデックス値(整数)です.
ELEVには各頂点の高さにあたる値が入ります.

このテキストファイル自体はなんとかして作ってください.Excelでも保存時にCSV出力することでカンマ区切りのテキストを吐き出せます.
データ数が多いときはPythonやRuby等(言語は何でもいい)で整形したテキストを作成します.
スクリプト
2次元スカラー場のテキストファイルをインポートするためのPythonスクリプトは以下の通りです.条件に合わせて
赤字部分を書き換えて使用してください.
Blender Python初心者の方は
こちらを参考にしてみてもいいと思います.
#Blender 2.81
#2次元スカラー場からグリッドオブジェクトを作成するスクリプト
#実行時は必ずオブジェクトモードにしておく
import bpy
#テキストファイルを指定
TextFilePath = 'C:/tmp/DEMData.txt'
#グリッド分割数を指定
i_max = 10
j_max = 10
#出力オブジェクトの大きさを指定
ObjectSize = 2
#オブジェクト作成
bpy.ops.mesh.primitive_grid_add(x_subdivisions = i_max, y_subdivisions = j_max, size = ObjectSize)
ObjName = bpy.context.object.name
Obj = bpy.data.objects[ObjName].data
#頂点の移動
count = 0
fp = open(TextFilePath)
line = fp.readline().replace('\n', '')
while line:
dat = line.split(',')
i = int(dat[0])
j = int(dat[1])
ELEV = float(dat[2])
index = i + j * i_max
Obj.vertices[index].co.z = ELEV
line = fp.readline().replace('\n', '')
if count % 10000 == 0:
print(count)
count += 1
fp.close()
print('Finished')
使用方法
- Blenderを起動します(新規作成)
- テキストエディタを開きます
(画面分割で3Dビューが一緒に見える状態がいいでしょう)
- 本ページのスクリプトをコピーしてBlender内のテキストエディタに貼り付けます
- スクリプト8行目をテキストファイルが保存されているファイルパスに書き換えます
フォルダの区切り文字は"\"ではなく"/"で入力します
- グリッドの分割数を指定します(スクリプト11,12行目)
- 出力オブジェクトの大きさを指定します(スクリプト15行目)

- スクリプトを実行する前にシステムコンソールを表示しておきます
- オブジェクトモードになっていることを確認します
- スクリプトを実行します
([テキストエディタ]上にマウスカーソルを乗せた状態で[Alt]+[P])

スクリプトで直接2次元スカラー場を指定する方法
もしかしてこっちの方が需要あるのでは?ってことで追記.
テキストファイルを用意せずに,スクリプト内で直接
2次元スカラー場を定義してグリッドオブジェクトを作成する方法です.使用方法は上記と同じなのでスクリプトの例だけ載せておきます.
#Blender 2.81
#2次元スカラー場からグリッドオブジェクトを作成するスクリプト
#実行時は必ずオブジェクトモードにしておく
import bpy
import math
#グリッド分割数を指定
i_max = 100
j_max = 100
#出力オブジェクトの大きさを指定
ObjectSize = 2
#オブジェクト作成
bpy.ops.mesh.primitive_grid_add(x_subdivisions = i_max, y_subdivisions = j_max, size = ObjectSize)
ObjName = bpy.context.object.name
Obj = bpy.data.objects[ObjName].data
#頂点の移動
count = 0
for i in range(i_max):
for j in range(j_max):
#任意の関数
ELEV = math.sin(i * j / 200) / 10.0
index = i + j * i_max
Obj.vertices[index].co.z = ELEV
if count % 10000 == 0:
print(count)
count += 1
print('Finished')
きれいだねぇ

そしてここまで作って気づく.これ,標準機能としてどっかに搭載されてたよなあ(終).