シェーダーで行う計算をCPUで普通に計算するテストコードを実装したいのですが予測通り最後で3次元目がよくわからない値に変わっているため画面に表示されない等の不具合が発生しているということを突き止めたのですがこれはなぜこんな値になっているのでしょうか?
追記 ロドリゲス回転行列がおかしいとの修正依頼を多数受けまして自分なりに修正しましたがもうどうしてもわかりません何をしたのか教えてくれますでしょうか?printf();でデバッグするとどうやらrotateの部分で値がおかしいためすべて狂ってるみたいです。
追記
参考サイト: http://marupeke296.sakura.ne.jp/DXG_No58_RotQuaternionTrans.html
② クォータニオン→回転行列変換より回転行列を使いかました。
下記サイトの163ページの透視射形変換行列の数式を移しました。
参考サイト: https://tokoik.github.io/GLFWdraft.pdf
GLSL
1#version 400 2//頂点シェーダー 3 4in vec3 position;//頂点座標 5 6uniform mat4 scale;//スケール行列 7uniform mat4 rotate;//回転行列 8uniform mat4 move;//平行移動行列 9 10uniform mat4 MP; 11 12out vec4 mt; 13 14void main() 15{ 16 vec4 t = vec4(position,1.0); 17 mat4 M = mat4(scale * rotate * move); 18 19 20 21 22 mt = vec4(MP * M * t); 23 24 25 26 27 gl_Position = MP * M * t; 28} 29 30
cpp
1#include "stdio.h" 2#include <iostream> 3 4//透視射形行列 5float mp[16]; 6 7//座標構造体 8struct position 9{ 10public: 11 float x; 12 float y; 13 float z; 14 15 float w; 16}; 17 18 19//頂点バッファー 20float Vertex[6][4] = 21{ 22 {-0.5, 0.5, 1.0,1.0}, 23 {-0.5, -0.5, 1.0,1.0}, 24 {0.5, -0.5, 1.0,1.0}, 25 26 {-0.5, 0.5, 1.0,1.0}, 27 {0.5, 0.5, 1.0,1.0 }, 28 {0.5, -0.5, 1.0,1.0} 29}; 30 31 32 33//透視投影変換行列を作る 34void create_matri_mp(float top, float bottom, float left, float right, 35 float near, float far, float result[16]) 36{ 37 result[0] = (2 * near) / (right - left); 38 result[5] = (2 * near) / (top - bottom); 39 40 result[8] = (right + left) / (right - left); 41 42 result[9] = (top + bottom) / (top - bottom); 43 44 result[10] = (far + near) / (far - near); 45 46 result[11] = -1; 47 result[14] = (2 * far * near) / (far - near); 48 49 50} 51 52//行列を表示 53void print_matrix(const char* str, float mp[4][4]) 54{ 55 printf("name: %s\n", str); 56 for (int i = 0; i < 4; i++) 57 { 58 for (int j = 0; j < 4; j++) 59 { 60 printf("[ %.2f ] , ", mp[i][j]); 61 } 62 printf("\n"); 63 } 64} 65 66 67//行列掛け算 68//void mul(float a[4][4], float b[4][4]) 69void mul(float a[16], float b[16], float result[16]) 70{ 71 result[0] = (a[0] * b[0]) + (a[4] * b[1]) + (a[8] * b[2]) + (a[12] * b[3]); 72 73 result[1] = (a[1] * b[0]) + (a[5] * b[1]) + (a[9] * b[2]) + (a[13] * b[3]); 74 75 result[2] = (a[2] * b[0]) + (a[6] * b[1]) + (a[10] * b[2]) + (a[14] * b[3]); 76 77 result[3] = (a[3] * b[0]) + (a[7] * b[1]) + (a[11] * b[2]) + (a[15] * b[3]); 78 79 ///////// 80 81 result[4] = (a[0] * b[4]) + (a[4] * b[5]) + (a[8] * b[6]) + (a[12] * b[7]); 82 83 result[5] = (a[1] * b[4]) + (a[5] * b[5]) + (a[9] * b[6]) + (a[13] * b[7]); 84 85 result[6] = (a[2] * b[4]) + (a[6] * b[5]) + (a[10] * b[6]) + (a[14] * b[7]); 86 87 result[7] = (a[3] * b[4]) + (a[7] * b[5]) + (a[11] * b[6]) + (a[15] * b[7]); 88 89 ///////// 90 result[8] = (a[0] * b[8]) + (a[4] * b[9]) + (a[8] * b[10]) + (a[12] * b[11]); 91 92 result[9] = (a[1] * b[8]) + (a[5] * b[9]) + (a[9] * b[10]) + (a[13] * b[11]); 93 94 result[10] = (a[2] * b[8]) + (a[6] * b[9]) + (a[10] * b[10]) + (a[14] * b[11]); 95 96 result[11] = (a[3] * b[8]) + (a[7] * b[9]) + (a[11] * b[10]) + (a[15] * b[11]); 97 98 ///////// 99 100 result[12] = (a[0] * b[12]) + (a[4] * b[13]) + (a[8] * b[14]) + (a[12] * b[15]); 101 102 result[13] = (a[1] * b[12]) + (a[5] * b[13]) + (a[9] * b[14]) + (a[13] * b[15]); 103 104 result[14] = (a[2] * b[12]) + (a[6] * b[13]) + (a[10] * b[14]) + (a[14] * b[15]); 105 106 result[15] = (a[3] * b[12]) + (a[7] * b[13]) + (a[11] * b[14]) + (a[15] * b[15]); 107 108 109} 110 111//行列計算 a x b 112void mul_A_B(float a[16], float b[16], float result[16]) 113{ 114 result[0] = (a[0] * b[0]) + (a[1] * b[4]) + (a[2] * b[8] ) + (a[3] * b[12]); 115 result[1] = (a[0] * b[1]) + (a[1] * b[5]) + (a[2] * b[9] ) + (a[3] * b[13]); 116 result[2] = (a[0] * b[2]) + (a[1] * b[6]) + (a[2] * b[10]) + (a[3] * b[14]); 117 result[3] = (a[0] * b[3]) + (a[1] * b[7]) + (a[2] * b[11]) + (a[3] * b[15]); 118 119 result[4] = (a[4] * b[0]) + (a[5] * b[4]) + (a[6] * b[8]) + (a[7] * b[12]); 120 result[5] = (a[4] * b[1]) + (a[5] * b[5]) + (a[6] * b[9]) + (a[7] * b[13]); 121 result[6] = (a[4] * b[2]) + (a[5] * b[6]) + (a[6] * b[10]) + (a[7] * b[14]); 122 result[7] = (a[4] * b[3]) + (a[5] * b[7]) + (a[6] * b[11]) + (a[7] * b[15]); 123 124 125 result[8] = (a[8] * b[0]) + (a[9] * b[4]) + (a[10] * b[8]) + (a[11] * b[12]); 126 result[9] = (a[8] * b[1]) + (a[9] * b[5]) + (a[10] * b[9]) + (a[11] * b[13]); 127 result[10] = (a[8] * b[2]) + (a[9] * b[6]) + (a[10] * b[10]) + (a[11] * b[14]); 128 result[11] = (a[8] * b[3]) + (a[9] * b[7]) + (a[10] * b[11]) + (a[11] * b[15]); 129 130 result[12] = (a[12] * b[0]) + (a[13] * b[4]) + (a[14] * b[8]) + (a[15] * b[12]); 131 result[13] = (a[12] * b[1]) + (a[13] * b[5]) + (a[14] * b[9]) + (a[15] * b[13]); 132 result[14] = (a[12] * b[2]) + (a[13] * b[6]) + (a[14] * b[10]) + (a[15] * b[14]); 133 result[15] = (a[12] * b[3]) + (a[13] * b[7]) + (a[14] * b[11]) + (a[15] * b[15]); 134} 135 136 137 138//ベクトルと行列の掛け算 139void mul_vec3_matrix(float m[16], float v[3], float r[3]) 140{ 141 printf("\n\n"); 142 for (int j = 0; j < 3; j++) 143 { 144 printf("[ %.2f ] ", r[j]); 145 } 146 printf("\n"); 147} 148 149 150//画面表示 151void print_(float tmp[16]) 152{ 153 for (int i = 0; i < 16; i++) 154 { 155 if (i % 4 == 0) 156 { 157 printf("\n"); 158 } 159 160 printf(" [ %.2f ] ", tmp[i]); 161 } 162 163 printf("\n\n"); 164 165} 166 167 168int main() 169{ 170 create_matri_mp(1.0f, -1.0f, -1.0f, 1.0f, 1.0, 10.f, mp);//透視射形変換行列mp 171 172 173 //回転行列 174 struct position pos; 175 176 pos.x = 1.0f; 177 pos.y = 0; 178 pos.z = 0; 179 180 pos.w = 1.0f; 181 float r = 1.0f; 182 183 float rotate[16] = { 184 (pos.x * pos.x * (1 - cos(r)) + cos(r)), 185 (pos.x * pos.y * (1 - cos(r)) - (pos.z * sin(r))), 186 (pos.x * pos.z * (1 - cos(r)) + (pos.y * sin(r))), 187 0, 188 189 (pos.x * pos.y * (1 - cos(r)) + (pos.z * sin(r))), 190 (pos.y * pos.y * (1 - cos(r)) + cos(r)), 191 (pos.y * pos.z * (1 - cos(r)) - (pos.x * sin(r))), 192 0, 193 194 (pos.x * pos.z * (1 - cos(r)) - (pos.y * sin(r))), 195 (pos.y * pos.z * (1 - cos(r)) + (pos.x * sin(r))), 196 (pos.z * pos.z * (1 - cos(r)) + cos(r)), 197 0, 198 199 0,0,0,1 200 }; 201 202 // print_(rotate); 203 204 //平行移動 205 struct position p; 206 p.x = 0; 207 p.y = 0; 208 p.z = 0; 209 p.w = 1; 210 211 float move[16] = 212 { 213 1,0,0,0, 214 0,1,0,0, 215 0,0,1,0, 216 p.x,p.y,p.z,1, 217 }; 218 219 // print_(move); 220 221 float t[16]; 222 mul(rotate, move, t); 223 // print_(t); 224 225 //スケール行列 226 float scale[16] = { 227 1,0,0,0, 228 0,1,0,0, 229 0,0,1,0, 230 0,0,0,1 231 }; 232 233 print_(scale); 234 235 float t2[16]; 236 mul(scale, t, t2); 237 print_(t); 238 239 240 241 242 243 for (int i = 0; i < 6; i++) 244 { 245 float t3[16]; 246 mul(Vertex[i], t2, t3); 247// print_(t2); 248 249 250 float t4[16]; 251 mul(mp, t2, t4); 252 // print_(t4); 253 } 254 255 256 float a[16] = 257 { 258 0,3,2,5, 259 0,2,2,1, 260 261 0,7,4,3, 262 0,3,3,7, 263 264 }; 265 266 267 float b[16] = 268 { 269 0,3,5,5, 270 0,5,8,6, 271 272 8,7,3,3, 273 5,8,3,8, 274 275 }; 276 277 278 float c[16] = { 0 }; 279 280 //mul_A_B(a,b,c); 281 282// print_(c); 283 284 285 286 return 0; 287}
デバッグのための行いなのですから,そこは頑張りましょうよ.
・行列の乗算処理が間違っていないか?
→ これが疑わしいのならば,乗算処理を単体でテストして,まともなことを確認しましょう.真っ先に.
「適当に要素値を決めた行列2個と,手計算なりで求めたその積」をテストパターンとして何個か用意すれば確認できるでしょう.
・create_matri_mp()がおかしいのか?
→ これで計算された行列には「(これこれこういう作用だ,という)意味」があるハズ.
つまり,「ある座標に乗じたならばその結果はこうなるハズだ」というINとOUTのセットを,その意味から,前述の行列の積と同じようにテストパターンとして用意して確認することができるハズ.
なるほど。しかしなにか間違えているというのは事実でしょうか?
それを調べるのですよね?
やっている計算は
最終結果 = MP * scale * rotate * move * v
なわけですが,
例えば,vに何か適当な値を定めたときに,
move * v
は期待通りの値になっているか? を確認する.
ここが大丈夫そうならば,次は,
rotate * (move * v )
までが期待通りの値になっているか? を同様に確認する.
ここまでが大丈夫ならば……
として,見ていけばよいのでは.
どこかで「期待と異なる結果」に遭遇したならば,怪しいのはそこです.
各段階での「期待される結果」をあなたが把握していることが必要です.(それが無いと確認のしようがないので)
SOJに似たような質問があったから定期的にチェックしてみては。
https://ja.stackoverflow.com/questions/70444
わかりました。質問ですがこの手のバグはどうやったらいいのでしょうか?
create_matri_mpの result[3][3]の値が0になっているのか気になります。記憶は曖昧ですが、1.0だったような気がします。
result[3][3] = 1.0;としましたがやはり値が同じくマイナスですw
質問内容を編集しましたので再度御覧ください
デバッグについてはfanaさんが書いているように
入力に対して各関数の出力が期待値通りか確認して
違ったら関数内で引数は正しくわたっているか、
計算結果は正しいかとかを確認していけばいいのではないでしょうか。
質問内容を大幅に変更しましたので御覧ください。
検証などはしていないので確かなことは言えませんが、
回転行列がおかしくないですか?
12個しか初期化要素がないため(4,4)成分にあたるrot[15]が0になってしまっています。
また、ロドリゲスの回転公式を表現したいのでしょうが、そうであれば回転軸posは単位ベクトル(大きさが1のベクトル)でなければいけません。
※追記
ロドリゲスの回転公式としてもおかしいですね。
(1 - cos(r))は足すのではなく掛けないといけませんし、ほかにもいくつか間違いがあるみたいです。
それともう一つ。
rotateの初期化部分で、16個初期化しないといけないにも関わらず、最初の12個しか初期化されていないのは何故でしょうか?
提示コードを編集しましたので御覧ください
以前にも貴方に言いましたが、ここは他人にデバッグをしてもらうサイトではないですよ?
そう見えてしまうのですが。デバッグ依頼をするつもりは一切ないのですが自分の知らない範囲で何かやっているものがあるのかと思い質問しました。削除したほうがよろしいのでしょうか?
別に後ろめたいことが無いなら消さなくてもいいと思いますが、Soeiさん、stdioさんにコメントで指摘されてる事くらいまともに返信したらどうでしょう。
わかりました。 Soeiさん、stdioさん 修正したのですが治りませんでした。また追記の文章を御覧ください。実装を変えましたがだめでした。 rotateの最後の4つの数値に0,0,0,1というコードを忘れていたので追加しました。が結果が変わりません
指摘した部分が直っていませんよ。
・回転軸posは単位ベクトル(大きさが1のベクトル)でなければいけません。
・(1 - cos(r))は足すのではなく掛けないといけません。
・ほかにもいくつか間違いがあります。細かく指摘しないので自分で探してください。
様々な場所のコードを編集しました。演算子のミスなどの間違えを修正しましたので御覧ください。
何故私が他人にデバッグをして貰ってるように見えるかというと、コンピュータは外部から入力されるランダムなデータなど不確定要素が入らない限りは数式通りの答えしか出しません。
デバッグでステップ実行したり、変数値を出力しながら少しづつ入力値と計算結果、数式を照合しながら調べていけば、通常は自分で間違いに気づく筈なのです。
なので、きちんとデバッグをしている人が、
> 3次元目がよくわからない値に変わっているため
などという事を言うのがおかしいのです。これは、つまり自分で計算結果を何も検証していないということです。
fana さんが指摘されている、
> 各段階での「期待される結果」をあなたが把握していることが必要です.(それが無いと確認のしようがないので)
これが全てだと思います。
回答1件
あなたの回答
tips
プレビュー

