• 締切済み

C++ 法線の計算

Depthmapをもつ画像のピクセルごとに法線を計算する関数を作成したのですが、いまいち計算が遅いです。if文をできるだけ使わないようにしたり、自分なりに変更したのですが、どなたかアドバイスを頂けないでしょうか。 Visual Studio, windows7, C++ です。 Tvector3<float> calc_normal(Tvector3<float> p1, Tvector3<float> p2, Tvector3<float> p3){ Tvector3<float> v1; Tvector3<float> v2; Tvector3<float> cross; float length; Tvector3<float> n; v1 = p1 - p2; v2 = p3 - p2; cross = v2.cross(v1); /* 外積v2×v1の長さ|v2×v1|(= length)を求める */ cross.normalize(); /* 長さ|v2×v1|が0のときは法線ベクトルは求められない */ if (length == 0.0f) { //cout<<"lenth=0"<<endl; //break (); } /* 外積v2×v1を長さ|v2×v1|で割って法線ベクトルnを求める */ //cout<<cross<<endl; return cross; } void calc_all_noraml(Ttexturef dmap, vector<Tvector3<float>> &n){ int w = dmap.getWidth(); int h = dmap.getHeight(); Tvector3<float> pc,pl,pr,pd,pu; int j=0; cout<<j<<endl; for(int i=0; i<w; i++){ vector<Tvector3<float>> temp; pc = Tvector3<float>(i,j,return_depth(dmap,i,j)); if(i-1 > 0)pl = Tvector3<float>(i-1,j,dmap.get(i-1,j).r); if(i+1 < w)pr = Tvector3<float>(i+1,j,dmap.get(i+1,j).r); pu = Tvector3<float>(i,j+1,dmap.get(i,j+1).r); if(i-1 > 0)temp.push_back(calc_normal(pl,pu,pc)); if(i+1 < w)temp.push_back(calc_normal(pc,pu,pr)); Tvector3<float> sum(0,0,0); for(int k=0; k<(int)temp.size(); k++){ sum += temp.at(k); } sum.normalize(); //cout<<sum<<endl; n.push_back(sum); } for(j=1;j<(h-1);j++){ cout<<j<<endl; int i=0; vector<Tvector3<float>> temp; pc = Tvector3<float>(i,j,return_depth(dmap,i,j)); pr = Tvector3<float>(i+1,j,return_depth(dmap,i+1,j)); pu = Tvector3<float>(i,j+1,return_depth(dmap,i,j+1)); pd = Tvector3<float>(i,j-1,return_depth(dmap,i,j-1)); temp.push_back(calc_normal(pc,pu,pr)); temp.push_back(calc_normal(pc,pr,pd)); Tvector3<float> sum(0,0,0); for(int k=0; k<(int)temp.size(); k++){ sum += temp.at(k); } sum.normalize(); n.push_back(sum); temp.clear(); for(int i=1; i<(w-1); i++){ Tvec

みんなの回答

noname#137556
noname#137556
回答No.3

> 一般的にfloatよりdoubleのほうが早いのでしょうか? 一概にどちらが早いとは言えないようです。 ↓実際に試した方のブログ。 http://lazyattribute.sakuratan.com/la/?p=1302

larry0708
質問者

お礼

ありがとうございます。なかなか奥が深そうですが頑張ります!

すると、全ての回答が全文表示されます。
noname#137556
noname#137556
回答No.2

Relaese ビルドにしてますよね? float から double にするだけで変わるかも。 関数のインライン展開を使ってみる。 ループの中でテンポラリオブジェクトの生成,代入が無駄に多い気がする。

larry0708
質問者

お礼

リリースビルドで作成しています。 一般的にfloatよりdoubleのほうが早いのでしょうか? てっきりfloatのほうが範囲が狭いので早いと思っていました。

すると、全ての回答が全文表示されます。
  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

どうもコードが途中で終わっているようので的確なアドバイスになるか不明ですが…… (1) calc_normal()の引数が参照になっていないのでそれを参照にする。内部で値を変更しないので、 Tvector3<float> calc_normal(const Tvector3<float> &p1, const Tvector3<float> &p2, const Tvector3<float> &p3){  …… } というぐあいに。 calc_all_noraml()の引数Ttexturef dmapも同様。 (2) calc_all_noraml()の引数vector<Tvector3<float>> &nで、入るデータ数が分かるならばその個数をresearve()しておくと処理の重いメモリーアロケーションの回数が減る。たぶん入るデータ数は冒頭で計算しているwとhから容易に計算できるのではないかと思われる。 (3) calc_all_noraml()の最初のループ内でvector<Tvector3<float>> tempを使っているが、tempにpush_backされるのは最大2回と分かりきっている。要素数が分かりきっている配列として使うにはvectorは重いしオーバースペックである。 たとえば以下のように、  for(int i=0; i<w; i++){   Tvector3<float> buf[2];   int buf_size = 0;   pc = Tvector3<float>(i,j,return_depth(dmap,i,j));   pu = Tvector3<float>(i,j+1,dmap.get(i,j+1).r);   if(i-1 > 0){    pl = Tvector3<float>(i-1,j,dmap.get(i-1,j).r);    buf[buf_size++] = calc_normal(pl,pu,pc);   }   if(i+1 < w){    pr = Tvector3<float>(i+1,j,dmap.get(i+1,j).r);    buf[buf_size++] = calc_normal(pc,pu,pr);   }   switch (buf_size){   case 1:    //cout<<buf[0]<<endl;    n.push_back(buf[0]);    break;   case 2:    //cout<<(buf[0] + buf[1]).normalize()<<endl;    n.push_back((buf[0] + buf[1]).normalize());    break;   default:    //cout<<"("<<i<<", "<<j<<"): no normal."<<endl;   }  } と配列を使用すればよい(インデントを全角空白で行っています。コピペするときはその後半角空白かタブに変換してください)。イテレーターを持つ配列が必要ならばstd::tr1::arrayを使うという手もある。 なお、bufとbuf_sizeをループの外に出すとより早くなると思われるが、たぶん似たようなコードが後に出てくるであろうから一つにまとめるときのことを考えて外に出していない。 (4) (上の例では消えてしまっているが)for(int k=0; k<(int)temp.size(); k++)というループ内部でat(k)を使って値を取り出しているが、代わりにイテレーターを使うべき。 あるいは、やっていることは要素の加算なので、<numeric>をインクルードして、 Tvector3<float> sum = std::accumulate(temp.begin(), temp.end(), Tvector3<float>(0, 0, 0)); とする。 ……といったことが思い浮かびます。

larry0708
質問者

お礼

複数のアドバイスありがとうございます。 まだまだ勉強中でして、すこしづつ試してみようと思います。

すると、全ての回答が全文表示されます。