ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Make Low Poly Trees & Save the Planetのチュートリアルを試す(Blender 2.8)(4)

    最後、シェーディングについて。

    13:28~

    シェーディングタブに切り替える

    [Shift+A]→[Plane]でPlaneを追加し、[S]で拡大して地面にする

    二番目に作った木の葉を選択し、Newを押し、追加されたマテリアルの名前をgreen1に設定する

    Principled BSDFのRoughnessを1.0に設定、さらにBaseColorをHSVで0.336,0.475,0.662 に設定する

    Shiftを押しながらクリックして複数選択する。この際、コピーしたいマテリアルのオブジェクトを最後に選択する。そして[Ctrl+L]→Materialを選択しマテリアルをコピーする

    幹を選択し、先ほどと同様にNewボタンでマテリアルを新規追加し、名前をbrownにする

    Roughnessを1.0,色をHSVで0.066,0.729,0.486に設定する。

    上の葉と同じ方法で、三つの幹全てのマテリアルをbrownにLinkする

    葉の設定は以下

    同様にして最後の木も設定する

    レンダリングの際、Ambient Cclusionを設定する

    Ambient Occlusion=off
    Ambient Occlusion Distance=4m

    Make Low Poly Trees & Save the Planetのチュートリアルを試す(Blender 2.8)(3)

    8:55~

    1.円筒追加

    [Shift+A]→[Cylinder]でシリンダを追加。

    前回同様Verticesを6にする。

    ① [1]を押してXZビューに変更、[S][Z]でZ方向に拡大する。

    ② [S][Shift+Z]でXY方向に縮小し、細くする

    ③ [G][Z]で円筒の底面をX平面に置く。

    [Ctrl+R]でループカットし、円筒を二分割する。

    [3]で面選択モードにし、上面を選択、[S]で円筒の上部だけを細くする

    [2]でエッジ選択モードにし、[Alt+左クリック]で連続したエッジを選択する。

    [S]で縮小、[R]で回転、[G]で移動を行い、幹の曲げを作る

    [3]で面選択モードに移行し、[S]で底面を拡大する

    カメラ方向を変え、枝の曲げが見えない方向を無いように、[Alt+左クリック]→[G]で下のLoopCut部分にも曲げを加える

    [Shift+右クリック]で幹の根本付近に3Dカーソルを移動し、[Shift+A]→[Plane]で面を追加する

    Editモードに入り、[Ctrl+R]でループカットで三分割する

    各エッジを[S]で拡大し、葉っぱの形を整える

    Editモードに入り、中央の四角形を少し持ち上げる

    Objectモードで[S][X]で引き延ばす

    [G]で根元を幹の側面に移動する

    回転・複製を行うため、originを葉の左側のエッジの中点に置く。

    ①Editモードに入り、[2]でエッジモードにし、幹の方のエッジを選択する。

    ②[Shift+S]→[Cursor to Selected]を選択

    ③Objectモードに切り替え、右クリック→[Set Origin]→[Origin to 3D curosor]を選択

    葉のエッジを回転し、形状を有機的にする

    [7]でTopビューにし、[Alt+D]でオブジェクトをコピー、[R]で回転する。

    コピー時にAlt+Dを使用しているので、全てのオブジェクトはリンクしている。

    一番幹側のエッジを選択し、[S]で縮小し、一括で編集する.

    根元から頭頂まで葉をコピーする

    Make Low Poly Trees & Save the Planetのチュートリアルを試す(Blender 2.8)(2)

    Make Low Poly Trees & Save the Planet | #Teamtrees | Blender 2.8

    二種類目の木

    3:50~

    1.葉の作成

    [Shift+A]→[Mesh]→[Cylinder]で円筒を作成。

    頂点数を6にしポリゴンが目立つようにする

    2.木の上部の作成

    Objectモードに戻り、幹を[Shift+D]で複製、上に配置する

    [S] + [Shift+Z]でXY方向に拡大する

    上の手順と同様にして、葉の部分の上部を細くする

    葉の下部分を広げ、さらにくぼませる

    [Shift+D]で葉をコピーし、上に重ねる。回転・拡大縮小を行いバリエーションを増やす。

    3.葉にバリエーションを付ける

    葉の一つを選択し、Editモードへ入る。

    [Ctrl+R]でループカットを行い、下部のエッジを選択して移動する

    4.葉にノッチ(切り欠き)をつける

    Editモードで[K]を押しナイフにする。

    奥行きのある三角形のような形に切り込みを入れる

    できた三つの平面を[X]→[Faces]で削除する

    [2]を押しエッジ選択モードに切り替え、エッジを一本選択して[F]を押し、面を張る

    作業中、他のオブジェクトが邪魔な時は[Num /]で選択中のオブジェクトだけを表示できる

    5.幹に変化を付ける

    [S] + [Shift+Z]でXY方向に縮小し、幹を細くする

    [Ctrl + R]でループカットし、[G]で移動して幹を曲げる

    Make Low Poly Trees & Save the Planetのチュートリアルを試す(Blender 2.8)(1)

    Make Low Poly Trees & Save the Planet | #Teamtrees | Blender 2.8

    ローポリの自然物のチュートリアル。Blender 2.8のUIになれるにはちょうどいい素材。

    1:05~

    1.キューブを頂点に

    TabキーでEditモードに入り、[1] キー (NumPadではないほう)を押しVertex Selectにする。そして[A]キーでキューブの頂点を全て選択し、[Alt+M]→At Centerで一つの頂点にマージする

    2.木の骨格を作る

    Editモードのまま、頂点を選択し、[E]で押し出して木の形を作る。

    頂点がうまく選択できない、[C]の範囲選択が解除できないときは、左上のSelectのモードがただのSelectになっているかを確認する。

    3.Skinモディファイアを適用

    Editモードで[Alt+Z]を押すと、X-rayモードになり頂点とエッジが見やすくなる

    [Ctrl+A]でスケールを変更する

    エッジの両端を選択し、[右クリック→Subdivide]で分割できる

    形が整ったら、ObjectModeに戻りApplyする。

    4.木に葉を追加する

    木の先端を[Shift+右クリック]で3Dカーソルをクリック位置に配置する

    [Shift+A]→[Mesh]→Ico SphereでICO Sphereを追加

    ICO Sphere はSubdivisionsを1にしてよりポリゴンぽくする

    [Shift+D]で複製、[R]で回転、[S]で縮小などを行い、葉を増やして配置する

    5.移動・次の準備

    [B]の矩形選択で木全体を選択し、[G][X]でX方向にずらしておく。

    [Shift+S]→Cursor to World Originを選択し、3Dカーソルを(0,0,0)に初期化する

    次回:二本目

    X,Y,Z軸回転の回転行列を作成

    これもさすがに簡単すぎるので一回でやります。

    X軸の回転行列とC言語での配列の配置

    Y軸の回転行列とC言語での配列の配置

    Z軸の回転行列とC言語での配列の配置

    #include <iostream>
    
    #include <Windows.h>
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    // freeglut:
    // http://freeglut.sourceforge.net/
    
    //ウィンドウの幅と高さ
    int width, height;
    
    
    //! @brief X軸回転行列を作成する //! @param [out] m 結果を格納する要素数16の配列 //! @param [in] rad 回転角(ラジアン) //! @return なし void GetXRotate(double* m, double rad) { m[ 0] = 1; m[ 1] = 0; m[ 2] = 0; m[ 3] = 0; m[ 4] = 0; m[ 5] = cos(rad); m[ 6] = sin(rad); m[ 7] = 0; m[ 8] = 0; m[ 9] = -sin(rad); m[10] = cos(rad); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
    //! @brief Y軸回転行列を作成する //! @param [out] m 結果を格納する要素数16の配列 //! @param [in] rad 回転角(ラジアン) //! @return なし void GetYRotate(double* m, double rad) { m[0] = cos(rad); m[1] = 0; m[2] = -sin(rad); m[3] = 0; m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; m[8] = sin(rad); m[9] = 0; m[10] = cos(rad); m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
    //! @brief Z軸回転行列を作成する //! @param [out] m 結果を格納する要素数16の配列 //! @param [in] rad 回転角(ラジアン) //! @return なし void GetZRotate(double* m, double rad) { m[0] = cos(rad); m[1] = sin(rad); m[2] = 0; m[3] = 0; m[4] = -sin(rad); m[5] = cos(rad); m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; }
    //! @brief 角度degreeをラジアンに変換する //! @param [in] degree 度で表した角度 //! @return ラジアンの角度 inline double toRadian(const double degree) { return degree * 3.1415926535897932384626 / 180; } double rotate_angle = 0; //描画関数 void disp(void) { glViewport(0, 0, width, height); glClearColor(0.2, 0.2, 0.2, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glEnable(GL_CULL_FACE); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); double v; //テスト1 OpenGLZ軸回転する { v = 0.7; glPushMatrix(); glRotated(rotate_angle, 0, 0, 1); glBegin(GL_QUADS); glColor3d(0, 0, 1); glVertex2d(-v, -v); glColor3d(1, 0, 1); glVertex2d(v, -v); glColor3d(1, 1, 1); glVertex2d(v, v); glColor3d(0, 1, 1); glVertex2d(-v, v); glEnd(); glPopMatrix(); } //テスト2 自作関数でZ軸回転行列を作ってOpenGLのMatrixに掛ける { v = 0.5; glPushMatrix(); double m[16]; GetZRotate(m, toRadian(rotate_angle)); glMultMatrixd(m); glBegin(GL_QUADS); glColor3d(1, 1, 0); glVertex2d(-v, -v); glColor3d(1, 1, 1); glVertex2d(v, -v); glColor3d(0, 1, 0); glVertex2d(v, v); glColor3d(1, 0, 0); glVertex2d(-v, v); glEnd(); glPopMatrix(); } glFlush(); } //ウィンドウサイズの変化時に呼び出される void reshape(int w, int h) { width = w; height = h; disp(); } void timer(int value) { rotate_angle += 5; disp(); glutTimerFunc(100, timer, 0); } //エントリポイント int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(500, 500); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutCreateWindow("sample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glutTimerFunc(10, timer, 0);//タイマー glutMainLoop(); return 0; }

    実行結果

    外側の矩形はOpenGLのglRotate(r,0,0,1);で描いている。

    内側の矩形は自覚関数でZ回転行列を作成してglMultMatrixdしている。

    テンプレートテンプレートパラメータ(基本)

    C++のテンプレートテンプレートパラメータ(誤表記ではない)について。

    1.動かないサンプル

    以下をやりたい。つまりコンテナとテンプレート引数を別にとるようなテンプレートを書きたい。

    しかしこれは動かない。

         
    //エラー コンパイルできない
    template< class Ty, class Type> auto makelistError() { Ty<Type> v; v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); return v; }
    int main() { auto mylist = makelistError<std::vector, int>(); std::cout << "出力" << std::endl; for (auto it = std::begin(mylist); it != std::end(mylist); it++) { std::cout << *it << std::endl; } int i; std::cin >> i; }

    2.動くサンプル

    template< template<class,class> class Ty, class Type> auto makelist() { Ty<Type, std::allocator<Type> > v;//STLのリスト構造は本来データ型とデータのallocatorの二つをとる v.push_back(5); v.push_back(6); v.push_back(7); v.push_back(8); return v; }
    int main() { auto mylist = makelist<std::vector, int>(); std::cout << "出力" << std::endl; for (auto it = std::begin(mylist); it != std::end(mylist); it++) { std::cout << *it << std::endl; } int i; std::cin >> i; }

    makelistの第一テンプレート引数の意味は、「テンプレート引数を二つとる型」という意味になる。第二引数はそのまま。

    vectorの場合、定義が以下のようになっているので、受け取る側もそれに合わせなければならない。

    上記プログラムのstd::vectorの所をstd::listにしても正常に動作する。

    VCG LibでOpenEdgeのループを検出する

    MyMesh

    #pragma once
    
    // vcg コア
    #include <vcg/complex/complex.h>
    
    // vcg input output
    #include <wrap/io_trimesh/import_ply.h>
    #include <wrap/io_trimesh/export_ply.h>
    #include <wrap/io_trimesh/import_stl.h>
    
    
    using namespace vcg;
    using namespace std;
    
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    // メッシュデータ型
    /////////////////////////////////////////////////
    /////////////////////////////////////////////////
    class MyFace;
    class MyVertex;
    class MyEdge;
    
    struct MyUsedTypes : public
      UsedTypes<
      Use<MyVertex>::AsVertexType,
      Use<MyFace>::AsFaceType,
      Use<MyEdge>::AsEdgeType
    
      >
    {};
    
    class MyVertex :
      public Vertex<
      MyUsedTypes,
      vertex::Coord3f,
      vertex::Color4b,
      vertex::Normal3f,
      vertex::BitFlags,
      vertex::VEAdj,// needed
      vertex::Mark>
    {
    public:
      bool m_loopchecked;
      MyVertex() {
        m_loopchecked = false;
      }
    
    };
    
    class MyEdge : public vcg::Edge<
      MyUsedTypes,
      vcg::edge::VertexRef,
      vcg::edge::VEAdj,// needed
      vcg::edge::BitFlags> {
    
    public:
      MyEdge() {
      }
    };
    
    class MyFace :
      public Face  <
      MyUsedTypes,
      face::VertexRef,
      face::Normal3f,
      face::FFAdj,// needed
      face::BitFlags >
    {};
    
    
    class MyMesh :
      public vcg::tri::TriMesh<
      vector<MyVertex>,
      vector<MyFace>,
      vector<MyEdge>
      >
    {};
    

    実装

    #pragma once
    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/freeglut.h>
    #include "nurotate.h"
    
    
    #include "MyMesh.h"
    
    //! @brief 穴構成頂点の配列をhole_tとする。
    using hole_t = std::vector<int>;
    
    //! @brief 穴の配列
    std::vector<hole_t> holes;

    //! @brief 穴を検出する関数 //! @param [in] mesh メッシュデータ //! @param [out] hole 穴構成頂点の格納先 //! @param [in] vid 検索開始地点の頂点ID //! @retval false 穴が見つからなかった //! @retval true 穴が見つかった bool search_near_edge(MyMesh& mesh, hole_t& hole,int vid) { vcg::edge::VEIterator<MyEdge> vfe(&mesh.vert[vid]); for (; !vfe.End(); ++vfe) { MyEdge* e = vfe.E(); // OpenEdge以外は読み飛ばす if (e->IsB() == false) { continue; } //現在検索中の頂点ともう一方に分ける int from, to; if (vcg::tri::Index(mesh, e->cV(0)) == vid) { from = vid; to = vcg::tri::Index(mesh, e->cV(1)); } else { from = vid; to = vcg::tri::Index(mesh, e->cV(0)); } if (hole.size() != 0) { if (hole[0] == to) { hole.push_back(from); return true; } } if (mesh.vert[to].m_loopchecked == true) continue; mesh.vert[from].m_loopchecked = true; hole.push_back(from); if (search_near_edge(mesh, hole, to) == true) { return true; } } return false; }
    MyMesh m; int width, height; //回転オブジェクト定義 nu::mrotate camr; //! @brief 表示関数 //! @return なし void disp(void) { glClearColor(0.3, 0.3, 0.3, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,width / (double)height, 0.1, 5); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1); GLfloat lpos[4] = { 0,1,1,1 }; GLfloat ambw[4] = { 0.5,0.5,0.5,1 }; GLfloat color[4] = { 1,1,1,1 }; GLfloat lspec[4] = { 1,1,1,1 }; GLfloat mspec[4] = { 0.5,0.5,0.5,1 }; ///////////////////////////////////////////// glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, ambw); glLightfv(GL_LIGHT0, GL_SPECULAR, lspec); glLightfv(GL_LIGHT0, GL_POSITION, lpos); ///////////////////////////////////////////// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mspec); glPushMatrix(); //原点を視線方向に0.5ずらす glTranslated(0, 0, -2); //回転行列を適用 double mat[16]; glMultMatrixd(camr.getmatrix(mat));
    glPushMatrix(); glScaled(2.0 / m.bbox.Diag(), 2.0 / m.bbox.Diag(), 2.0 / m.bbox.Diag()); { //全ての面を表示 glBegin(GL_TRIANGLES); for (auto& f : m.face) { glNormal3f(f.cN().X(), f.cN().Y(), f.cN().Z()); glVertex3d(f.cV(0)->cP().X(), f.cV(0)->cP().Y(), f.cV(0)->cP().Z()); glVertex3d(f.cV(1)->cP().X(), f.cV(1)->cP().Y(), f.cV(1)->cP().Z()); glVertex3d(f.cV(2)->cP().X(), f.cV(2)->cP().Y(), f.cV(2)->cP().Z()); } glEnd(); } { //全てのエッジを表示 glDisable(GL_LIGHTING); glLineWidth(1); glColor3d(0, 0, 0); for (auto& f : m.face) { glBegin(GL_LINE_LOOP); glVertex3d(f.cV(0)->cP().X(), f.cV(0)->cP().Y(), f.cV(0)->cP().Z()); glVertex3d(f.cV(1)->cP().X(), f.cV(1)->cP().Y(), f.cV(1)->cP().Z()); glVertex3d(f.cV(2)->cP().X(), f.cV(2)->cP().Y(), f.cV(2)->cP().Z()); glEnd(); } } { //見つかった穴だけを表示 glDisable(GL_LIGHTING); glLineWidth(3); glColor3d(0, 0, 1); for (auto& hole : holes) { glBegin(GL_LINE_STRIP); for (auto& v : hole) { glVertex3d( m.vert[v].cP().X(), m.vert[v].cP().Y(), m.vert[v].cP().Z() ); } glEnd(); } } glPopMatrix();

    glPopMatrix(); glFlush(); } void reshape(int w, int h) { width = w; height = h; //クライアント領域のサイズを指定 //Win32APIの場合はGetClientRectで求めたrightとbottomだがglutではwとh camr.setWindowSize(width, height); //クライアント領域のどこの範囲に描画しているかを指定。 //glViewportで一画面丸々描画しているので、クライアント領域の(0,0)-(width,height)に書いていることになる camr.setRenderRect(0, 0, width, height); disp(); } //マウスクリック時のイベント void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { camr.dragstart(x, y);//最初の回転軸を決定 } else if (state == GLUT_UP) { camr.dragend();//ドラッグ終了 } glutPostRedisplay(); } //ドラッグ時のイベント void motion(int x, int y) { camr.dragto(x, y);//移動中の回転軸を更新 disp(); } //エントリポイント int main(int argc, char ** argv) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(400, 300); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutCreateWindow("MouseRotateSample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion);
    vcg::tri::io::ImporterPLY<MyMesh>::Open(m, "sample.ply"); vcg::tri::Clean<MyMesh>::RemoveDuplicateVertex(m); vcg::tri::UpdateBounding<MyMesh>::Box(m); vcg::tri::UpdateNormal<MyMesh>::PerFace(m); vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); vcg::tri::UpdateTopology<MyMesh>::AllocateEdge(m); vcg::tri::UpdateTopology<MyMesh>::VertexEdge(m); vcg::tri::UpdateFlags<MyMesh>::VertexBorderFromFaceAdj(m);
     
    ///////////////////////////////// // 穴検出 /////////////////////// bool ret; for (size_t i = 0; i < m.vert.size(); i++) { //OpenEdgeのフラグが立っていないなら何もしない if (m.vert[i].IsB() == false) continue; //すでにループかどうかの評価をしたフラグが立っていれば何もしない if (m.vert[i].m_loopchecked) continue; m.vert[i].m_loopchecked = true; hole_t hole; ret = search_near_edge(m, hole,i);//未チェックのOpenEdge構成頂点を渡して穴かどうかの評価 if (ret == true) { holes.push_back(hole);//穴一覧を更新 } }
     
    glutMainLoop(); return 0; }

    回転について

    以下を参照

    実行結果

    4×4行列の積を実装(C++)

    4×4行列の積を行うと以下のような結果になる

    高精度計算サイト https://keisan.casio.jp/exec/system/1308269580

    二次元行列を一次元に変換

    行列は数学ではi,jの二次元で表現されたりするが、C/C++ではメモリが一次元のため大抵は一次元で扱われる。以下の式で二次元を一次元に変換する

    サンプルコード

    inline int f(const int i, const int k) {
      return i + 4*k;
    }
    //4x4行列の乗算関数
    void multMatrix(double* C, double* A, double* B) {
    
      for (int i = 0; i < 4; i++)
        for (int k = 0; k < 4; k++) {
          C[f(i, k)] = 0.0;
          for (int j = 0; j < 4; j++) {
            C[f(i, k)] += A[f(i, j)]*B[f(j, k)];
          }
        }
    }
    
    //描画関数
    void disp(void) {
    
      glViewport(0, 0, width, height);
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      double in[4] = { 0.2,0.1,0.1,1 };
    
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
    
      double rmat[16];
      double tmat[16];
    
      ////////////////////// OpenGLで計算
      glPushMatrix();
      glRotated(120, 0, 0, 1);
      glTranslated(0.5, 0, 0);
      glColor3d(1, 0, 0);
      glPointSize(15);
      glBegin(GL_POINTS);
      glVertex3d(in[0], in[1], in[2]);
      glEnd();
      glPopMatrix();
    
    
      ////////////////////// 自前実装
      ////////////////////// OpenGLで行列作成
      glPushMatrix();
      glRotated(120, 0, 0, 1);
      glGetDoublev(GL_MODELVIEW_MATRIX, rmat);
      glPopMatrix();
      glPushMatrix();
      glTranslated(0.5, 0, 0);
      glGetDoublev(GL_MODELVIEW_MATRIX, tmat);
      glPopMatrix();
    
      //行列のかけ算
      double amat[16];
      glPushMatrix();
      multMatrix(amat, rmat, tmat);
      glLoadMatrixd(amat);
      glColor3d(0, 1, 0);
      glPointSize(10);
      glBegin(GL_POINTS);
      glVertex3d(in[0], in[1], in[2]);
      glEnd();
      glPopMatrix();
    
      glFlush();
    }
    

    三次元座標をアフィン変換する

    ソースコード

    template<typename real_t>
    inline void multMatrixVec(real_t* const out4, const real_t* const matrix, const real_t* const in4)
    {
      int i;
    
      for (i = 0; i<4; i++) {
        out4[i] =
          in4[0] * matrix[0 * 4 + i] +
          in4[1] * matrix[1 * 4 + i] +
          in4[2] * matrix[2 * 4 + i] +
          in4[3] * matrix[3 * 4 + i];
      }
    }
    

    使用サンプル

    template<typename real_t> inline void multMatrixVec(real_t* const out4, const real_t* const matrix, const real_t* const in4) { int i; for (i = 0; i < 4; i++) { out4[i] = in4[0] * matrix[0 * 4 + i] + in4[1] * matrix[1 * 4 + i] + in4[2] * matrix[2 * 4 + i] + in4[3] * matrix[3 * 4 + i]; } }
    //描画関数 void disp(void) { glViewport(0, 0, width, height); glClearColor(0.2, 0.2, 0.2, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); double in[4] = { 0.1,0.2,0.3,1 }; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); double mat[16]; ////////////////////// OpenGLで描画 glPushMatrix(); glRotated(25, 0, 0, 1); glTranslated(0.5, 0, 0); glGetDoublev(GL_MODELVIEW_MATRIX, mat); //行列を退避 glColor3d(1, 0, 0); glPointSize(15); glBegin(GL_POINTS); glVertex3d(in[0], in[1], in[2]); glEnd(); glPopMatrix(); ////////////////////// 自前実装 double out4[4]; multMatrixVec(out4, mat, in);//退避した行列で座標を変換 glColor3d(0, 1, 0); glPointSize(10); glBegin(GL_POINTS); glVertex3d(out4[0], out4[1], out4[2]); glEnd(); glFlush(); }

    OpenGLで常に正面を向いた簡単な円を描く

    球を模倣したい。wireframeなsphereだと表示が鬱陶しくなったりするので円で代用したいような場合に用いる。

    今回のプログラムは前回のものに付け足すのでdrawcircle.hppをincludeする。なおbbはbillboardの意。

    ソースコード

    円を描く関数(drawcircle_bb.hpp)

    //! @file drawcircle_bb.hpp
    #pragma once
    #include "drawcircle.hpp"
    
    //! @brief カメラ行列から視線方向に対して垂直で画面右向きのベクトルを取得する
    //! @param [out] v3 結果を格納する三次元ベクトル 要素数3
    //! @param [in] cameraModelView カメラ行列
    //! @return なし
    inline void getRayRightFromCamera(double* v3, double* cameraModelView) {
      v3[0] = cameraModelView[0];
      v3[1] = cameraModelView[4];
      v3[2] = cameraModelView[8];
    }
    
    //! @brief カメラ行列から視線方向に対して垂直で画面上向きのベクトルを取得する
    //! @param [out] v3 結果を格納する三次元ベクトル 要素数3
    //! @param [in] cameraModelView カメラ行列
    //! @return なし
    inline void getRayUpFromCamera(double* v3, double* cameraModelView) {
      v3[0] = cameraModelView[1];
      v3[1] = cameraModelView[5];
      v3[2] = cameraModelView[9];
    };
    
    //! @brief 常に正面を向いた円を描く
    //! @param [in] x 中心座標
    //! @param [in] y 中心座標
    //! @param [in] z 中心座標
    //! @param [in] r 半径
    //! @param [in] count 分割数 4 ぐらいがとりあえず適当
    //! @param [in] カメラ行列。nullptrを指定した場合はglGetDoublevでOpenGLから取り出す
    //! @return なし
    inline void circle_xy_bb(double x, double y, double z, double r, const int count,double* cameramatrix=nullptr) {
    
      coord_t center(x, y, z);
    
      double vr[3];
      double vu[3];
    
    
      //モデルビュー行列から四角形の頂点を取り出す
      if (cameramatrix == nullptr) {
        double model[16];
        glGetDoublev(GL_MODELVIEW_MATRIX, model);
        getRayRightFromCamera(vr, model);
        getRayUpFromCamera(vu, model);
      }
      else {
        getRayRightFromCamera(vr, cameramatrix);
        getRayUpFromCamera(vu, cameramatrix);
      }
    
      double a[3] = { vr[0], vr[1], vr[2] };
      double b[3] = { vu[0],vu[1], vu[2] };
      double c[3] = {-vr[0],-vr[1], -vr[2] };
      double d[3] = {-vu[0],-vu[1], -vu[2] };
    
    
      coord_t p[4];
      p[0] = coord_t(a);
      p[1] = coord_t(b);
      p[2] = coord_t(c);
      p[3] = coord_t(d);
    
      glBegin(GL_LINE_LOOP);
      for (int i = 0; i < 4; i++) {
    
        int ia = i % 4;
        int ic = (i + 1) % 4;
    
        coord_t a(p[ia].x, p[ia].y, p[ia].z);
        coord_t c(p[ic].x, p[ic].y, p[ic].z);
        plot_ab(center, count, r, a, c);
      }
      glEnd();
    }
    

    呼び出しサンプル

    #include <iostream>
    #include <Windows.h>
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    #include <cassert>
    
    // freeglut:
    // http://freeglut.sourceforge.net/
    
    //矢印描画関数
    #include "drawarrow.hpp"
    //円描画関数
    #include "drawcircle.hpp"
    #include "drawcircle_bb.hpp"
    
    
    //ウィンドウの幅と高さ
    int width, height;
    
    double rotate_angle = 0;
    
    
    //描画関数
    void disp(void) {
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      glEnable(GL_DEPTH_TEST);
    
      glViewport(0, 0, width, height);
    
      //カメラの設定
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(60, width / (double)height, 0.1, 3);
      glMatrixMode(GL_MODELVIEW);
    
      glLoadIdentity();
    
      glTranslated(0, 0, -2);
    
      //表示用の回転
      glRotated(rotate_angle, 0, 1, 0);
      glRotated(rotate_angle, 1, 0, 0);
    
      //表示用に全体を少しずらす
      glTranslated(0, 0.2, 0.2);
    
      //矢印を三つ描画
      
      glLineWidth(2);
      double center[3] = { 0.3,0,0 };
      double tox[3] = { 1 + center[0],0 + center[1],0 + center[2] };
      double toy[3] = { 0 + center[0],1 + center[1],0 + center[2] };
      double toz[3] = { 0 + center[0],0 + center[1],1 + center[2] };
      glColor3d(1, 0, 0);
      drawArrow(center, tox);
      glColor3d(0, 1, 0);
      drawArrow(center, toy);
      glColor3d(0, 0, 1);
      drawArrow(center, toz);
      glLineWidth(1);
    
      //////////////////////////////////////
      //円を描画
      glLineWidth(3);
      glColor3d(1, 1, 0);
      circle_xy(center[0], center[1], center[2], 0.5, 3);
      glColor3d(0, 1, 1);
      circle_xy_bb(center[0], center[1], center[2], 0.5, 3,nullptr);
    
      glFlush();
    }
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
      width = w; height = h;
    
      disp();
    }
    
    void timer(int value)
    {
      rotate_angle += 5;
    
      disp();
      glutTimerFunc(100, timer, 0);
    }
    
    //エントリポイント
    int main(int argc, char** argv)
    {
      glutInit(&argc, argv);
      glutInitWindowPosition(100, 50);
      glutInitWindowSize(500, 500);
      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    
      glutCreateWindow("sample");
      glutDisplayFunc(disp);
      glutReshapeFunc(reshape);
      glutTimerFunc(1000, timer, 0);//タイマー
      glutMainLoop();
    
      return 0;
    }