blenderのbpyで、オブジェクトにキーフレームを打つ（スクリプトでリスト作成、もしくは、csv読み込みで）

###はじめに
物理シミュレーションの結果をblender上で表示させるやり方を示す。
前提として、blenderを使ったことがあり、プリミティブオブジェクトについての簡単な操作ができるレベルを前提としている。

###プリミティブオブジェクトとして、ICO球を追加しておいて、スクリプト内でリストを作成し、それを元にオブジェクトにキーフレームを打つスクリプト
下記の通りに実行すると、ICO球がｘｙ平面上に楕円を描く

```python

import bpy
from math import pi,sin,cos

ob2 = bpy.data.objects['Icosphere']

ob2.animation_data_clear() #スクリプトを再度実行する場合を考慮して、アニメーションデータをクリア

def key_loc_set(list,obj):#リストと対象となるメッシュを受け取って、キーフレームを打つ
    for i in list:
        bpy.context.scene.frame_set(i[0])
        obj.location = i[1]
        obj.keyframe_insert(data_path = "location",index = -1)

key_loc_list2 = []

for i in range(136):
        t = i
        p = -3.7*sin(2 * pi * (i / 136)),5.5*cos(2 * pi * (i / 136)) + 4.5,0
        t_p = t,p
        key_loc_list2.append(t_p)

key_loc_set(key_loc_list2,ob2)

bpy.context.scene.frame_set(1)

```

生成されるリストの構造は、
[(0, (-0.0, 10.0, 0)),
(1, (-0.1708787969892365, 9.994131361413048, 0)), ……
としている。for i in listを実行した際に、i[0]でキーフレームを、i[1]で位置を表す３次元ベクトルを得て、obj.locationへ渡せるようにしている。

##プリミティブオブジェクトとして、UV球を追加しておいて、外部からcsvファイルを読み、それを元にオブジェクトにキーフレームを打つスクリプト
下記の通りに実行すると、UV球がｘｙ平面上に楕円を描く。今回使用するcsvファイルは、スクリプトに続けて掲載する。

```python

import bpy
import csv

ob1 = bpy.data.objects['Sphere']

ob1.animation_data_clear()

def key_loc_set(list,obj):
    for i in list:
        bpy.context.scene.frame_set(i[0])
        obj.location = i[1]
        obj.keyframe_insert(data_path = "location",index = -1)


key_loc_list = []     

with open('d:/blender/planet.csv') as f:
    reader = csv.reader(f)
    for row in reader:
        t = int(row[0])
        p = row[1],row[2],row[3]
        p_float = [float(i) for i in p]
        t_p = t,p_float
        key_loc_list.append(t_p)


key_loc_set(key_loc_list,ob1)

bpy.context.scene.frame_set(1)
```
関数、key_loc_setは、さきほどと同じもの。
外部からcsvファイルを読み込む際に、str型になっているので、変換処理を行った上で、リストに渡している。リストの構造は、さきほどと同じ。
ここでは、読み込むcsvファイルは、blenderの実行ファイルと同じフォルダとしている。csvファイルは、４列となっており、１列目には、キーフレームを打つ位置、２～４列目には、ｘ、ｙ、ｚ座標の各々の値が入っている。
下記のデータは、
https://cattech-lab.com/science-tools/simulation-lecture-2-1/
【科学技術計算講座2-1】ルンゲ=クッタ法とは
を参考に作ったもので、惑星の楕円軌道を表している。

```csv
0,-0.005,9.99999,0
1,-0.10499,9.99779,0
2,-0.20494,9.99159,0
3,-0.30481,9.98139,0
4,-0.40456,9.96717,0
5,-0.50414,9.94894,0
6,-0.60352,9.92668,0
7,-0.70265,9.90039,0
8,-0.8015,9.87004,0
9,-0.90001,9.83563,0
10,-0.99815,9.79714,0
11,-1.09588,9.75454,0
12,-1.19314,9.70782,0
13,-1.28989,9.65694,0
14,-1.38608,9.60189,0
15,-1.48166,9.54263,0
16,-1.57659,9.47914,0
17,-1.6708,9.41137,0
18,-1.76425,9.33928,0
19,-1.85688,9.26285,0
20,-1.94863,9.18203,0
21,-2.03943,9.09676,0
22,-2.12923,9.007,0
23,-2.21795,8.91269,0
24,-2.30553,8.81379,0
25,-2.39188,8.71022,0
26,-2.47694,8.60192,0
27,-2.56062,8.48883,0
28,-2.64282,8.37086,0
29,-2.72347,8.24795,0
30,-2.80245,8.11999,0
31,-2.87966,7.98692,0
32,-2.95499,7.84862,0
33,-3.02831,7.705,0
34,-3.0995,7.55595,0
35,-3.16841,7.40135,0
36,-3.23489,7.24107,0
37,-3.29878,7.07499,0
38,-3.35989,6.90296,0
39,-3.41803,6.72482,0
40,-3.47298,6.54042,0
41,-3.52451,6.34957,0
42,-3.57236,6.1521,0
43,-3.61623,5.94778,0
44,-3.65582,5.73641,0
45,-3.69075,5.51775,0
46,-3.72063,5.29154,0
47,-3.74501,5.05751,0
48,-3.76337,4.81536,0
49,-3.77514,4.56477,0
50,-3.77962,4.3054,0
51,-3.77606,4.03686,0
52,-3.76354,3.75876,0
53,-3.741,3.47067,0
54,-3.70718,3.17213,0
55,-3.66057,2.86266,0
56,-3.59933,2.54178,0
57,-3.52121,2.20903,0
58,-3.42343,1.86398,0
59,-3.30244,1.50636,0
60,-3.15372,1.1362,0
61,-2.97135,0.75405,0
62,-2.74751,0.3616,0
63,-2.47173,-0.03731,0
64,-2.1302,-0.43457,0
65,-1.70564,-0.81364,0
66,-1.18097,-1.14247,0
67,-0.55343,-1.36698,0
68,0.13846,-1.42474,0
69,0.81297,-1.29482,0
70,1.40146,-1.02123,0
71,1.88486,-0.66732,0
72,2.27433,-0.27827,0
73,2.58794,0.12102,0
74,2.8417,0.51804,0
75,3.04803,0.90672,0
76,3.21627,1.28425,0
77,3.35339,1.64947,0
78,3.46471,2.00209,0
79,3.55432,2.34223,0
80,3.62546,2.67023,0
81,3.68066,2.98653,0
82,3.72201,3.29161,0
83,3.7512,3.58596,0
84,3.76963,3.87004,0
85,3.77849,4.14431,0
86,3.77876,4.40917,0
87,3.77131,4.66503,0
88,3.75686,4.91223,0
89,3.73605,5.15113,0
90,3.70943,5.38203,0
91,3.6775,5.60522,0
92,3.64068,5.82096,0
93,3.59935,6.02951,0
94,3.55387,6.23109,0
95,3.50453,6.42592,0
96,3.45162,6.6142,0
97,3.39538,6.7961,0
98,3.33604,6.9718,0
99,3.2738,7.14146,0
100,3.20887,7.30522,0
101,3.14141,7.46323,0
102,3.07158,7.61562,0
103,2.99953,7.76251,0
104,2.92539,7.90401,0
105,2.84931,8.04023,0
106,2.77138,8.17127,0
107,2.69173,8.29721,0
108,2.61046,8.41816,0
109,2.52766,8.53419,0
110,2.44342,8.64537,0
111,2.35784,8.75179,0
112,2.27099,8.8535,0
113,2.18295,8.95058,0
114,2.0938,9.04308,0
115,2.00359,9.13105,0
116,1.91241,9.21456,0
117,1.82031,9.29364,0
118,1.72735,9.36834,0
119,1.63359,9.43871,0
120,1.53908,9.50479,0
121,1.44389,9.5666,0
122,1.34806,9.62419,0
123,1.25164,9.67758,0
124,1.15468,9.72681,0
125,1.05724,9.7719,0
126,0.95934,9.81287,0
127,0.86105,9.84974,0
128,0.76239,9.88254,0
129,0.66343,9.91128,0
130,0.5642,9.93598,0
131,0.46473,9.95664,0
132,0.36508,9.97328,0
133,0.26528,9.98591,0
134,0.16537,9.99453,0
135,0.0654,9.99914,0
136,-0.0346,9.99976,0
```

以下は、上記２つのスクリプトをまとめたもの。
プリミティブオブジェクトとして、UV球とISO球を追加してから実行すると、惑星が動く楕円運動と、三角関数に基づく楕円表記(asin(θ),bcos(θ))での、楕円運動との違いが見てわかるようになっている。
なお、後者の楕円運動は、等速円運動と違って、速度は一律ではないのに注意。

```python
import bpy
import csv
from math import pi,sin,cos

ob1 = bpy.data.objects['Sphere']
ob2 = bpy.data.objects['Icosphere']

ob1.animation_data_clear()
ob2.animation_data_clear()

 
def key_loc_set(list,obj):
    for i in list:
        bpy.context.scene.frame_set(i[0])
        obj.location = i[1]
        obj.keyframe_insert(data_path = "location",index = -1)


key_loc_list = []     
 
with open('d:/blender/planet.csv') as f:
    reader = csv.reader(f)
    for row in reader:
        t = int(row[0])
        p = row[1],row[2],row[3]
        p_float = [float(i) for i in p]
        t_p = t,p_float
        key_loc_list.append(t_p)

key_loc_list2 = []

for i in range(136):
        t = i
        p = -3.7*sin(2 * pi * (i / 136)),5.5*cos(2 * pi * (i / 136)) + 4.5,0
        t_p = t,p
        key_loc_list2.append(t_p)

key_loc_set(key_loc_list,ob1)

key_loc_set(key_loc_list2,ob2)

bpy.context.scene.frame_set(1)
```