ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      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
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         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     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       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     
         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
           
  • テンプレートテンプレートパラメータ(基本)

    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;
    }
    

    OpenGLで簡単な円を描く

    ※2020/09/08追記:正直、以下の方が簡単です。


    OpenGLで円を描くプログラム。

    普通のやり方だと三角関数を使って正多角形を描くのだけれど、面倒なので、まず正方形を用意し、それをN分割することで円に近づける。

    ただし今回、円はXY平面上にある。

    ソースコード

    円を描くプログラム(drawcircle.hpp)

    //! @file drawcircle.hpp
    #pragma once
    
    #include <Windows.h>
    #include <gl/GL.h>
    #include <cmath>
    
    //! @brief 座標を管理する構造体
    struct coord_t {
      double x, y, z;
      coord_t() {}
      coord_t(double X, double Y, double Z) :x(X), y(Y), z(Z) {}
      coord_t(double* v3) {
        x = v3[0];
        y = v3[1];
        z = v3[2];
      }
      coord_t(const coord_t& src) {
        x = src.x;
        y = src.y;
        z = src.z;
      }
    
      inline bool normalize()
      {
    
        double len = static_cast<double>(sqrt(x * x + y * y + z * z));
    
        if (len < 1e-6) return false;
    
        len = 1.0 / len;
        x *= len;
        y *= len;
        z *= len;
    
        return true;
      }
      inline void mult(const double val) {
        x *= val;
        y *= val;
        z *= val;
      }
    
    
    };
    
    //! @brief a----c という辺をa--b--cと分割し、a--bを描画する。呼び出し側でGL_LINE_LOOPを使う限りb--cは勝手につながる
    //! @param [in] offset 円の中心座標
    //! @param [in] count 分割数
    //! @param [in] r 半径
    //! @param [in] a 始点
    //! @param [in] c 終点
    //! @return なし
    inline void plot_ab(const coord_t offset, const int count, double r, coord_t a, coord_t c) {
    
    
      a.normalize();
      c.normalize();
      a.mult(r);
      c.mult(r);
    
    
      if (count == 0) {
        glVertex3d(a.x + offset.x, a.y + offset.y, a.z + offset.z);
        return;
      }
    
      //a----c  →   a--b--c
      coord_t b((a.x + c.x) / 2.0, (a.y + c.y) / 2.0, (a.z + c.z) / 2.0);
      b.normalize();
      b.mult(r);
    
      if (count == 1) {
        glVertex3d(a.x + offset.x, a.y + offset.y, a.z + offset.z);
        glVertex3d(b.x + offset.x, b.y + offset.y, b.z + offset.z);
      }
      else {
    
        plot_ab(offset, count - 1, r, a, b);
        plot_ab(offset, count - 1, r, b, c);
    
      }
    
    }
    
    //! @brief OpenGLで円を描く
    //! @param [in] x 中心座標
    //! @param [in] y 中心座標
    //! @param [in] z 中心座標
    //! @param [in] r 半径
    //! @param [in] count 分割数 4 ぐらいがとりあえず適当
    //! @return なし
    inline void circle_xy(double x, double y, double z, double r, const int count) {
    
      coord_t center(x, y, z);
    
    
      coord_t p[4];
      p[0] = coord_t(-1, -1, 0);
      p[1] = coord_t(1, -1, 0);
      p[2] = coord_t(1, 1, 0);
      p[3] = coord_t(-1, 1, 0);
    
    
      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" //ウィンドウの幅と高さ 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); //矢印を三つ描画 glLineWidth(2); double from[3] = { 0,0,0 }; double tox[3] = { 1,0,0 }; double toy[3] = { 0,1,0 }; double toz[3] = { 0,0,1 }; glColor3d(1, 0, 0); drawArrow(from, tox); glColor3d(0, 1, 0); drawArrow(from, toy); glColor3d(0, 0, 1); drawArrow(from, toz); glLineWidth(1); ////////////////////////////////////// //円を描画 glLineWidth(3); glColor3d(1, 1, 0); circle_xy(0,0,0,0.5,4); 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; }

    OpenGLで簡易的な矢印を描く

    本格的な矢印はポリゴン数も計算も大変なので簡易的な矢印を実装する。

    なおそろそろ拡張子.hppを割と意識して使うことにする

    ソースコード

    矢印描画(drawarrow.hpp)

    #pragma once
    
    #include <Windows.h>
    #include <gl/GL.h>
    
    namespace numath {
      typedef double real_t;
    
      //! @brief ラジアンを度に変換
      //! @param [in] radian ラジアンの値
      //! @return 度の値
      inline real_t toDegree(const real_t radian) { return radian * 180 / 3.1415926535897932384626; }
    
      //! @brief 三次元のベクトルを正規化する
      //! @param [in,out] pV 三次元ベクトル1 要素数3
      //! @retval true 成功
      //! @retval false 失敗
      inline bool normalize(real_t* const pV)
      {
    
        const int X = 0;
        const int Y = 1;
        const int Z = 2;
    
        real_t len;
        real_t& x = pV[X];
        real_t& y = pV[Y];
        real_t& z = pV[Z];
    
        len = static_cast<real_t>(sqrt(x * x + y * y + z * z));
    
        if (len < static_cast<real_t>(1e-6)) return false;
    
        len = static_cast<real_t>(1.0) / len;
        x *= len;
        y *= len;
        z *= len;
    
        return true;
      }
    
      //! @brief ベクトルの長さを求める
      //! @param [in] vec 三次元ベクトル1 要素数3
      //! @return vecの長さを表すスカラー値
      inline real_t length(real_t const* const vec) {
        const int X = 0;
        const int Y = 1;
        const int Z = 2;
        return sqrt(vec[X] * vec[X] + vec[Y] * vec[Y] + vec[Z] * vec[Z]);
      }
    
      //! @brief 二つの三次元ベクトルの内積を求める
      //! @param [in] vec1 三次元ベクトル1 要素数3
      //! @param [in] vec1 三次元ベクトル2 要素数3
      //! @return ベクトルの内積
      inline real_t inner(real_t const* const vec1, real_t const* const vec2) {
        const int X = 0;
        const int Y = 1;
        const int Z = 2;
        return ((vec1[X]) * (vec2[X]) + (vec1[Y]) * (vec2[Y]) + (vec1[Z]) * (vec2[Z]));
      }
    
      //! @brief 二つの三次元ベクトルの角度を求める
      //! @param [in] vec1 三次元ベクトル1 要素数3
      //! @param [in] vec1 三次元ベクトル2 要素数3
      //! @return ベクトルの角度(ラジアン)
      inline real_t vectorAngle(real_t const* const vec1, real_t const* const vec2) {
        real_t x = inner(vec1, vec2) / (length(vec1) * length(vec2));
        if (x <= -1)
          x = -0.9999999;
        if (x >= 1)
          x = 0.99999999;
        return acos(x);
      }
    
      //! @brief ベクトルにスカラー値をかける
      //! @param [in,out] 対象の三次元ベクトル1 要素数3
      //! @param scalar スカラー値
      //! @return なし
      inline void vectorMult3(real_t * dst, const real_t scalar) {
        dst[0] *= scalar;
        dst[1] *= scalar;
        dst[2] *= scalar;
      }
    
      //! @brief 始点終点の線分をベクトルに変換
      //! @param [out] vec3 結果を格納する三次元ベクトル 要素数3
      //! @param [out] from 始点を表す三次元ベクトル 要素数3
      //! @param [out] to 終点三次元ベクトル 要素数3
      //! @return vec3のポインタ
      inline real_t* lineToVector3(real_t * const vec3, const real_t * const from, const real_t * const to) {
        vec3[0] = to[0] - from[0];
        vec3[1] = to[1] - from[1];
        vec3[2] = to[2] - from[2];
        return vec3;
      }
    
      //! @brief 与えられた二つのベクトルの外積を求める
      //! @param [out] dvec 結果を格納する三次元ベクトル 要素数3
      //! @param [in] svec 三次元ベクトル1 要素数3
      //! @param [in] svec 三次元ベクトル2 要素数3
      //! @return なし
      inline void outer(real_t * const dvec, real_t const* const svec1, real_t const* const svec2) {
        const int X = 0;
        const int Y = 1;
        const int Z = 2;
    
        const real_t& x1 = svec1[X];
        const real_t& y1 = svec1[Y];
        const real_t& z1 = svec1[Z];
        const real_t& x2 = svec2[X];
        const real_t& y2 = svec2[Y];
        const real_t& z2 = svec2[Z];
    
        dvec[X] = static_cast<real_t>(y1 * z2 - z1 * y2);
        dvec[Y] = static_cast<real_t>(z1 * x2 - x1 * z2);
        dvec[Z] = static_cast<real_t>(x1 * y2 - y1 * x2);
      }
    
      //! @brief 与えられたベクトルと垂直なベクトルを計算する
      //! @param dst13 結果を表す三次元ベクトル 要素数3(一つ目 必須)
      //! @param dst23 結果を表す三次元ベクトル 要素数3(二つ目 いらないならnullptrを指定)
      //! @param src3 入力する三次元ベクトル 要素数3
      //! @return なし
      inline void rightAngleVector(real_t * const dst13, real_t * const dst23, const real_t * const src3) {
    
        real_t tmp[3] = { 1,0,0 };
    
        //tmpとsrc3の角度0またはそれに限りなく近いなら、別なベクトルを用意
        if (toDegree(vectorAngle(tmp, src3)) < 0.1) {
          tmp[0] = 0;
          tmp[1] = 1;
          tmp[2] = 0;
        }
        //外積を求める
        outer(dst13, tmp, src3);
    
        if (dst23 != nullptr) {
          outer(dst23, src3, dst13);
        }
      }
    
    }
    
    
    //! @brief 矢印を描画
    //! @param [in] 矢印の始点
    //! @param [out] 矢印の終点
    //! @return なし
    inline void drawArrow(const double* from3, const double* to3) {
      glBegin(GL_LINES);
      glVertex3dv(from3);
      glVertex3dv(to3);
      glEnd();
    
      numath::real_t v[3];
      numath::lineToVector3(v, from3, to3);
    
      double len = numath::length(v);
    
      numath::real_t p3[3] = {
        from3[0],
        from3[1],
        from3[2]
      };
      numath::vectorMult3(v, 0.8);
    
    
      numath::real_t v1[3], v2[3];
      numath::rightAngleVector(v1, v2, v);
    
      numath::normalize(v1);
      numath::normalize(v2);
      numath::vectorMult3(v1, len * 0.03);
      numath::vectorMult3(v2, len * 0.03);
    
      const double* f = from3;
      const double* t = to3;
    
      glBegin(GL_LINE_STRIP);
      glVertex3d(f[0] + v[0], f[1] + v[1], f[2] + v[2]);
      glVertex3d(f[0] + v[0] + v1[0], f[1] + v[1] + v1[1], f[2] + v[2] + v1[2]);
      glVertex3d(t[0], t[1], t[2]);
      glEnd();
      glBegin(GL_LINE_STRIP);
      glVertex3d(f[0] + v[0], f[1] + v[1], f[2] + v[2]);
      glVertex3d(f[0] + v[0] + v2[0], f[1] + v[1] + v2[1], f[2] + v[2] + v2[2]);
      glVertex3d(t[0], t[1], t[2]);
      glEnd();
      glBegin(GL_LINE_STRIP);
      glVertex3d(f[0] + v[0], f[1] + v[1], f[2] + v[2]);
      glVertex3d(f[0] + v[0] - v1[0], f[1] + v[1] - v1[1], f[2] + v[2] - v1[2]);
      glVertex3d(t[0], t[1], t[2]);
      glEnd();
      glBegin(GL_LINE_STRIP);
      glVertex3d(f[0] + v[0], f[1] + v[1], f[2] + v[2]);
      glVertex3d(f[0] + v[0] - v2[0], f[1] + v[1] - v2[1], f[2] + v[2] - v2[2]);
      glVertex3d(t[0], t[1], t[2]);
      glEnd();
    
    }
    

    使用例

    #include <iostream>
    #include <Windows.h>
    #include <gl/GL.h>
    #include <gl/GLU.h>
    #include <gl/freeglut.h>
    
    // freeglut:
    // http://freeglut.sourceforge.net/
    
    //矢印描画関数
    #include "drawarrow.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);
    
      //矢印を三つ描画
      glLineWidth(2);
      double from[3] = { 0,0,0 };
      double tox[3] = { 1,0,0 };
      double toy[3] = { 0,1,0 };
      double toz[3] = { 0,0,1 };
      glColor3d(1, 0, 0);
      drawArrow(from, tox);
      glColor3d(0, 1, 0);
      drawArrow(from, toy);
      glColor3d(0, 0, 1);
      drawArrow(from, toz);
      glLineWidth(1);
    
      double v = 0.2;
    
      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();
      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;
    }
    

    OpenGL+freeglut基本のプログラム(コピペ用)

    雑談

    現在管理人はゼノブレイド2をやっていてブログを書く暇がガチで無い(←)。

    いい機会なので暫く小物をアップロードしてお茶を濁す。正直どこかに置いておかないと無くしてしまうのでGitHubにでも捨てておきたいのだが色々と思うところがあってできないでいる。

    1.基本のやつ

    以下はOpenGLの基本のプログラム。いつも某所からコピペをしていた。

    #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;
    
    //描画関数
    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);
      double v = 0.7;
    
      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();
      glFlush();
    }
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
      width = w; height = h;
    
      disp();
    }
    
    //エントリポイント
    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);
      glutMainLoop();
    
      return 0;
    }
    

    2.gluPerspective+timer使用

    #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;
    
    double rotate_angle=0;
    
    
    //描画関数
    void disp(void) {
    
    
      glClearColor(0.2, 0.2, 0.2, 1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      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);
    
      //回転するならカリングはOffにしたほうがいい。
      //glEnable(GL_CULL_FACE);
      double v = 0.7;
    
      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();
      glFlush();
    }
    
    //ウィンドウサイズの変化時に呼び出される
    void reshape(int w, int h) {
      width = w; height = h;
    
      disp();
    }
    
    void timer(int value)
    {
      rotate_angle += 5;
    
      disp();
      glutTimerFunc(10, 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;
    }
    

    次回はもう少しオリジナリティあるのものを載せる

    Create Realistic Grass in Blender 2.8 in 15 minutesのチュートリアルを試す(3)

    12:00~

    Particleで草を生やす

    1.Object Modeへ行き、新たなParticleを追加する。

    2.Particleを以下のように設定

    この時、元のFoliage01_colオブジェクトを選択し[H]キーでHiddenにしておく。

    3.Weight Paintする。

    この時、ペンの種類を選ぶ場所が見当たらない時は、[View]→[Tool Settings]にチェックを入れる

    青の部分にはParticleが生じないので、緑~赤の領域が全体を占めるように塗る

    4.Object Modeへ戻り、Particleの設定から、Vertex Group→Densityに、今塗りつぶした"Group"を選択する

    5.Particleのその他の設定を以下のようにする

    最後に、hairの数を5000にする

    レンダリングの設定とその他

    6.Viewport ShaderをRenderedに設定する

    7.Renderを以下のように設定。動画ではSubsurface Scatteringにチェックを付けることになっている。自分の使っているバージョンにはそのチェックがない。

    8.Materialへ行き、Materialを一つ追加する。BaseColorを濃い茶色に設定する。

    9.Sunを夕暮れ時を想定して急な角度に配置し、色を赤みがける

    9.その他、Shadowの設定を以下のように行う

    10.cloud_layers_4K.hdrを以下からダウンロードする

    https://hdrihaven.com/hdri/?h=cloud_layers

    11.World Settingsへ行き、Color→Environment Textureを選択し、上記hdrファイルを設定する。

    12.[Shift+A]→[Mesh]→CubeでCubeを配置し、[S][Z]で縦に伸ばす

    影を付け、カメラを適切な場所に設置すると木が近くにあるように見える

    RenderのLookをHigh Contrastにすると結果が変わる。

    Create Realistic Grass in Blender 2.8 in 15 minutesのチュートリアルを試す(2)

    草を曲げる

    08:44

    1.[Tab]でEditモードへ行く

    2.[Ctrl+R]でループカットを開始

    3.ホイールを回し、草のポリゴンを7等分する

    4.エッジ選択モードにする

    5.Proportional EditingをSharpにする

    6.ポリゴンの一番上のエッジを選択し、[G]で曲げる

    7.Smooth Shadingに切り替える

    [F3]で検索窓でShade Smoothを検索する

    ※あるいは、Object→Shade Smoothを選択する

    草を増やす

    09:24~

    8.Editモードで[Shift+D]でDuplicateし、すぐ隣に移動する

    9.再び画面を二分割し、左側をUV Imageにする

    10.[D]でUVを移動し、別の葉に移動する

    11.回転・拡大縮小を加え、同様のものを複数設置し、草の株を作る

    12.複製などを利用すると比較的早くできる。最後に、originが草の根元にあることを確認する

    地面を設置する

    11:23~

    13.[Shift+A]→[Mesh]→Plane で新たなPlaneを追加し、[S]で約6弱の大きさに広げる

    14.Sculpt Modeへ移行する

    16.DyntopoをOnにする。(チェックを入れると警告が出るので"OK"を押す

    Sculptで地面を盛り上げる

    Smooth Shadingにする場合
    引き算は右ドラッグ
    半径を変えるには、上のメニューか、その場で右クリックする
    Xのミラーを解除する場合はここをOffにする

    区切りがいいので次は次回