teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

頂点法線の計算方法、頂点インデックス方式の書き方

2017/11/13 00:32

投稿

masaya_ohashi
masaya_ohashi

スコア9210

answer CHANGED
@@ -13,4 +13,76 @@
13
13
  という具合です。
14
14
  各面の面法線が求められていて、頂点を共有する面のリストアップさえできてしまえば、
15
15
  後は、各面の面法線を足しあわせて規格化するだけなので、
16
- たいして難しいことはないです。
16
+ たいして難しいことはないです。
17
+
18
+ 共有する面のリストアップについては、「そもそもバラバラの頂点を3つ使ってポリゴンを作っている」という時点で難しいです。例えば以下のように、xy各座標が1の四角形があったとします。
19
+ ```C++
20
+ // 左上の三角
21
+ float v0_0[3] = {0, 0, 0}; // 左上
22
+ float v0_1[3] = {1, 0, 0}; // 右上
23
+ float v0_2[3] = {0, 1, 0}; // 左下
24
+ // 右下の三角
25
+ float v1_0[3] = {1, 0, 0}; // 右上
26
+ float v1_1[3] = {1, 1, 0}; // 右下
27
+ float v1_2[3] = {0, 1, 0}; // 左下
28
+ ```
29
+ このとき、頂点を共有しているのは同じ**右上**である`v0_1`と`v1_0`、および**左下**である`v0_2`と`v1_2`ですね?しかし、これでは同一性が**座標を見比べること**でしかわかりません。これではリストアップとは言えません。
30
+
31
+ このようなすべてのポリゴンごとに頂点がバラバラに定義されているデータと違い、もっときれいに「共有している頂点」を書く方法として**頂点インデックス方式**というものがあります。この方法であれば**頂点法線**の計算もわかりやすくなります。例えば先程の例の四角形を頂点インデックス方式で書いてみましょう。
32
+ ```C++
33
+ float v[4][3] = {
34
+ {0, 0, 0}, // 左上
35
+ {1, 0, 0}, // 右上
36
+ {0, 1, 0}, // 左下
37
+ {1, 1, 0}, // 右下
38
+ };
39
+ int index[2][3] = {
40
+ {0, 1, 2}, // 左上の三角
41
+ {1, 3, 2}, // 右下の三角
42
+ };
43
+ for(int i=0;i<2;i++) {
44
+ glBegin(GL_TRIANGLES);
45
+ glVertex3fv(v[index[i][0]]);
46
+ glVertex3fv(v[index[i][1]]);
47
+ glVertex3fv(v[index[i][2]]);
48
+ glEnd();
49
+ }
50
+ ```
51
+ `index`という変数は`v`の「何番目」の頂点を使うかという数値が入っています。これを使うことで**同じ座標にある頂点**を再利用しているわけです。
52
+ あとは計算ですが、頂点インデックスがあるなら話は簡単です。
53
+ ```C++
54
+ float n[4][3] = {0}; // 頂点の数だけ頂点法線用変数を用意
55
+
56
+ for(int i=0;i<2;i++) {
57
+ float temp[3] = {0, 0, 0}; // ここは本来面法線の計算結果
58
+
59
+ // 頂点法線用変数に面法線を加算
60
+ n[index[i]][0] += temp[0];
61
+ n[index[i]][1] += temp[1];
62
+ n[index[i]][2] += temp[2];
63
+ }
64
+
65
+ // 頂点法線の正規化
66
+ for(int i=0;i<4;i++) {
67
+ float length = sqrtf((n[i][0] * n[i][0]) + (n[i][1] * n[i][1]) + (n[i][2] * n[i][2]));
68
+ n[i][0] /= length;
69
+ n[i][1] /= length;
70
+ n[i][2] /= length;
71
+ }
72
+ ```
73
+ ```C++
74
+ for(int i=0;i<2;i++) {
75
+ glBegin(GL_TRIANGLES);
76
+
77
+ // 頂点ごとに法線も設定する
78
+ glNormal3fv(n[index[i][0]]);
79
+ glVertex3fv(v[index[i][0]]);
80
+
81
+ glNormal3fv(n[index[i][1]]);
82
+ glVertex3fv(v[index[i][1]]);
83
+
84
+ glNormal3fv(n[index[i][2]]);
85
+ glVertex3fv(v[index[i][2]]);
86
+ glEnd();
87
+ }
88
+ ```