2018年6月11日月曜日

embreeの入門に挫折

CGを観察する方向ばかりでしたのですが、開発方面のtipsとして久しぶりの投稿です。

初心者が書いているので、あまり参考にしないでください。

後述にもある通り、グラフィックプログラミング(?)は最近始めました。


2018/6/12 追記:libmmd.dllについて 
2018/9/14 追記:libmmd.dllについて

あくまでもチラチラ見て「ほぉ、そんなもんか、触るか」程度の前段階として考えてください。 embreeというのはintelが作ったOSSのCPUのレイトレです。

最近openGLやレイトレの技術の興味を持っているのでいろいろ触ったりしています。
openGLは和歌山大学、床井教授の GLUTによる「手抜き」OpenGL入門
レイトレーシングはPeter Shirley教授のRay Tracing in One Weekend (Ray Tracing Minibooks Book 1)を和訳した週末レイトレーシング
を途中までしています。
なんか途中ってなぁとは思います。やっている途中でglfwの新しいバージョンが出ましたし。
中身がどうなっているのか知りたい感じなので、写経になっているものをしています。
理論はいろいろ乗ってますけど、実際の計算はどのようにプログラムするかってあんまりわからない気がしますし。あとヘッダーの嵐で理解が危ういですし。

レイトレの基礎の基礎を知るならば週末レイトレーシングはいいと思います、a-mくらいまでは今のところ流し見では説明してくれています。
ヘッダーを書くので初心者の理解としては非常にいいと思います。
只今segment faultで投げ出している。

embreeを参考にしたサイトはembree入門です。
ですが、これをそのまま書くとだめなんですよね。
ver3に上がってAPIの刷新がされています。

私がそれに伴って書いたソースコードは

#include 
#include 
#include 
#include 
#define inf     1e30f
struct Vertex { float x, y, z; };
struct Triangle { int v0, v1, v2; };

int main(void)
{
 /* デバイスを作成 */
 RTCDevice device = rtcNewDevice(NULL);
 /* シーンを作成 */
 RTCScene scene = rtcNewScene(device);

 /* ここでこの後いろいろな処理を行う */
 /* .... */
 
 /* 3角形ジオメトリを作成 */
 RTCGeometry mesh = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
 /*頂点の設定*/
 Vertex* vertices = (Vertex*) rtcSetNewGeometryBuffer(mesh,RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vertex), 4);
 vertices[0].x = 10; vertices[0].y = 10; vertices[0].z = 0; // 点Aの座標
 vertices[1].x = 10; vertices[1].y = -10; vertices[1].z = 0; // 点Bの座標
 vertices[2].x = -10; vertices[2].y = 10; vertices[2].z = 0; // 点Cの座標
 vertices[3].x = -10; vertices[3].y = -10; vertices[3].z = 0; // 点Dの座標
 
 /*面の設定(用意?)*/
 int tri = 0;
 Triangle* triangles = (Triangle*)rtcSetNewGeometryBuffer(mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(Triangle), 2);
 triangles[tri].v0 = 0; triangles[tri].v1 = 1; triangles[tri].v2 = 3; tri++; // 三角形ABD
 triangles[tri].v0 = 1; triangles[tri].v1 = 2; triangles[tri].v2 = 3; tri++; // 三角形BCD

 unsigned int geomID = rtcAttachGeometry(scene, mesh);


 /*ジオメトリの削除*/
 rtcReleaseGeometry(mesh);

 /* シーンへ登録 */
 rtcCommitGeometry(mesh);

 /*/*レイ交差の初期化*/
 RTCIntersectContext context;
 rtcInitIntersectContext(&context);
 RTCHit rtchit;
 rtchit.geomID = RTC_INVALID_GEOMETRY_ID;

 /* レイを生成する */
 RTCRay rtcray;
 /* レイの始点 */
 rtcray.org_x = 0.0;  // x
 rtcray.org_y = 0.0;  // y
 rtcray.org_z = 20.0; // z
 /* レイの方向 */
 rtcray.dir_x = 0.0;  // x
 rtcray.dir_y = 0.0;  // y
 rtcray.dir_z = -1.0;  // z
 /* 交差判定する範囲を指定 */
 rtcray.tnear = 0.0f;     // 範囲の始点
 rtcray.tfar = inf;  // 範囲の終点.交差判定後には交差点までの距離が格納される.
 rtcray.time = 0;

 /* 交差判定 */
 RTCRayHit ray;
 rtcIntersect1(scene, &context, &ray);
 if (rtchit.geomID == RTC_INVALID_GEOMETRY_ID)
 {
  /* 交差点が見つからなかった場合 */
  std::cout << "Reject." << std::endl;
 }
 else
 {
  /* 交差点が見つかった場合 */
   std::cout << "Intersect" << std::endl;
  
 }
 
 /* シーンを削除 */
 rtcReleaseScene(scene);
 /* デバイスを削除 */
 rtcReleaseDevice(device);
 system("pause");
 return 0;
}
}
です。 

 躓いているのが、「レイと三角形との交差判定」なんですよね。
 RTCHitで判定すると思うのですが、初期化したデータがそのまま受け継がれているんですよね。


 プログラムの解説なのですが、
引用元の最初に当たる、初期化と終了処理は


#include 
#include 
#include 

int main(void)
{
 /* デバイスを作成 */
 RTCDevice device = rtcNewDevice(NULL);
 /* シーンを作成 */
 RTCScene scene = rtcNewScene(device);

 /* シーンを削除 */
 rtcReleaseScene(scene);
 /* デバイスを削除 */
 rtcReleaseDevice(device);
 return 0;
}
 
シーンの作成にあたり、embree2と違って、deviceの選択のみです。
embree3では他はシーンの品質の左右のみのようです。


次に三角形の作成なのですが、tutorialsのtrianglesをパクり参考にしましたので、構造体になっています。
ジオメトリの名前をmeshにしているのはgeomIDとRAYHitのgeomIDで使いたかったからです。



struct Vertex { float x, y, z; };
struct Triangle { int v0, v1, v2; };

 /* 3角形ジオメトリを作成 */
 RTCGeometry mesh = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
 /*頂点の設定*/
 Vertex* vertices = (Vertex*) rtcSetNewGeometryBuffer(mesh,RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vertex), 4);
 vertices[0].x = 10; vertices[0].y = 10; vertices[0].z = 0; // 点Aの座標
 vertices[1].x = 10; vertices[1].y = -10; vertices[1].z = 0; // 点Bの座標
 vertices[2].x = -10; vertices[2].y = 10; vertices[2].z = 0; // 点Cの座標
 vertices[3].x = -10; vertices[3].y = -10; vertices[3].z = 0; // 点Dの座標
 
 /*面の設定(用意?)*/
 int tri = 0;
 Triangle* triangles = (Triangle*)rtcSetNewGeometryBuffer(mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(Triangle), 2);
 triangles[tri].v0 = 0; triangles[tri].v1 = 1; triangles[tri].v2 = 3; tri++; // 三角形ABD
 triangles[tri].v0 = 1; triangles[tri].v1 = 2; triangles[tri].v2 = 3; tri++; // 三角形BCD

 unsigned int geomID = rtcAttachGeometry(scene, mesh);


 /*ジオメトリの削除*/
 rtcReleaseGeometry(mesh);

 /* シーンへ登録 */
 rtcCommitGeometry(mesh);

ジオメトリの作成にあたって、引数でジオメトリのタイプを設定し、
ジオメトリに対して、頂点や面の数、場所を書き込んでいます。


レイの送受なのですが、
embree3ではembree2のRTCRayの役割がRTCrayとRTCHitに変わっています。
私はここのRTCHitの扱いがわかりませんでした。


    /*レイ交差の初期化*/
 RTCIntersectContext context;
 rtcInitIntersectContext(&context);
 RTCHit rtchit;
 rtchit.geomID = RTC_INVALID_GEOMETRY_ID;

 /* レイを生成する */
 RTCRay rtcray;
 /* レイの始点 */
 rtcray.org_x = 0.0;  // x
 rtcray.org_y = 0.0;  // y
 rtcray.org_z = 20.0; // z
 /* レイの方向 */
 rtcray.dir_x = 0.0;  // x
 rtcray.dir_y = 0.0;  // y
 rtcray.dir_z = -1.0;  // z
 /* 交差判定する範囲を指定 */
 rtcray.tnear = 0.0f;     // 範囲の始点
 rtcray.tfar = inf;  // 範囲の終点.交差判定後には交差点までの距離が格納される.
 rtcray.time = 0;

レイの生成に関しては全く変わっていないです。
RTCHitを後述のifなどで使うにあたり、初期化しなくてはならないのですが、何をどうしているのかいろいろ見てもさっぱりでした。


コピペです。交差判定は説明書を見て書き換えた形です。

 /* 交差判定 */
 RTCRayHit ray;
 rtcIntersect1(scene, &context, &ray);
 if (rtchit.geomID == RTC_INVALID_GEOMETRY_ID)
 {
  /* 交差点が見つからなかった場合 */
  std::cout << "Reject." << std::endl;
 }
 else
 {
  /* 交差点が見つかった場合 */
   std::cout << "Intersect" << std::endl;
  

上記のプログラムを実行した場合、普通にRejectと出ますが、
レイの交差初期化で
 rtchit.geomID = geomID;
とした場合、Intersectと出ます。

わからないなりに適当に書いてしまった缶はありますが、embree3を触ろうかなぁと思っている方の気持ちを押すだけの手助けになれば幸いです。
技術的な視点はないので、気になった方は各自でググってください。もうギブ。

それにしても、意外と奈良先端技術大学院大学って近いんですね、クソ遠いかと思っていたのですが、そうでもなかったです。

参考
embree入門
embree公式
説明書


追記:libmmd.dllがないためエラーが出る場合
私の環境ではでました。
検索すると、c4dの例が多いみたいです。
検索した結果ではMSのVS再配布パッケージをインストールすれば解消することが多いようですが、ダメな場合は、intelのc++再配布パッケージをダウンロードすると解消すると思います。
嫌ならば、Embree Example Rendererからlibmmd.dllだけ取り込んでぶっこむのもありかもしれません、保証はしません、ご了承ください。 

コメント欄にてうしおさんがlibmmd.dllについて述べられています。
ありがとうございます。
3.10 3.21alphaなどを使うと良いそうです。

githubの存在をすっかり忘れてました...どこからdlするのかって話になりますね...。

4 件のコメント:

  1. embree-3.2.0.x64.windows.zipのlibmmd.dllへの依存については、意図されたものではないようです。すでにissueとしてあがっておりました。
    https://github.com/embree/embree/issues/195

    3.1.0を使うことでも解決することが可能です。

    返信削除
    返信
    1. 全く開いていないのでいまさら気が付きました。
      ありがとうございます!

      削除
  2. 情報ありがとうございます!
    自分もlibmmd問題で悩まされていましたが、無事解決しました

    どうやらフリーでdllを配布している怪しいサイトもあるみたいです

    返信削除
  3. 初めまして embree-3系の情報を探して
    たどって参りました。

    もうご存知かもしれませんが
    先月のSIGGRAPHの資料にてembree3 の
    サンプルコードが記載されておりましたので
    参考になるかもしれません。

    https://www.slideshare.net/IntelSoftware/embree-ray-tracing-kernels-overview-and-new-features-siggraph-2018-tech-session

    また上記のコードでは
    rtcCommitScene(scene);
    が書かれていないため オブジェクトがシーンに
    登録されていないように思います。

    返信削除