none
正多面体の正二十面体の作成の仕方 RRS feed

  • 質問

  • F#とOpenTKでicosahedron(正二十面体)を作成使用していたのですが, たまたまですが下記のようなものが生成されてしまいました。 どこが間違っているのかご教授の程よろしくお願いします。

    実験結果:

    2017年7月23日 4:47

回答

  • OpenTKを使ったことが無いのでGLEx.Faceが何をやっているコードなのか不明ですが、おそらく面を描画させているのだとすると、3面しか描画してないので20面には足らないですよね。
    この直交する3つの四角形の12個の頂点を結ぶと正20面体ができるのでしょうから、そのように20個の3頂点を用意すればよいのではないでしょうか。

    C#でOpenTKのサンプルコードに手を加えてみると20面体になりますし

    public HelloGL3()
        : base(640, 480,
        new GraphicsMode(), "OpenGL 3 Example", 0,
        DisplayDevice.Default, 3, 0,
        GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
    {
        //正20面体の頂点座標を用意する
        float G = (float)((1.0 + Math.Sqrt(5)) * 0.5);
        Vector3[] vertexies = new Vector3[]{
                new Vector3(1, G, 0),
                new Vector3(0, 1, G),
                new Vector3(G, 0, 1),
    
                new Vector3(-1, G, 0),
                new Vector3(0, -1, G),
                new Vector3(G, 0, -1),
    
                new Vector3(1, -G, 0),
                new Vector3(0, 1, -G),
                new Vector3(-G, 0, 1),
    
                new Vector3(-1, -G, 0),
                new Vector3(0, -1, -G),
                new Vector3(-G, 0, -1)
        };
                
    
        //各頂点に直近の点の集合
        List<int[]> listNear5 = vertexies.Select(a => vertexies.Select((b, i) => new { Index = i, LEN = (a - b).Length }).OrderBy(_ => _.LEN).Skip(1).Take(5).Select(_ => _.Index).OrderBy(_ => _).ToArray()).ToList();
    
        //各頂点から作られる三角形の頂点のインデックスを集める
        List<int[]> list3 = new List<int[]>();
        for (int i = 0; i < vertexies.Length; i++)
        {
            for (int j = 0; j < 5; j++)
            {
                for (int k = j + 1; k < 5; k++)
                {
                    int p1 = listNear5[i][j];
                    int p2 = listNear5[i][k];
                    if (listNear5[p1].Contains(p2))
                    {
                        int[] a = new int[] { i, p1, p2 };
                        Array.Sort(a);
                        if (!list3.Any(b => b[0] == a[0] && b[1] == a[1] && b[2] == a[2]))
                        {
                            list3.Add(a);
                        }
                    }
                }
            }
        }
    
        List<int> indexies = new List<int>();
        foreach (int[] a in list3)
        {
            indexies.AddRange(a);
        }
    
        //頂点座標と三角形の面のインデックス集合をサンプルコードに渡す
        positionVboData = vertexies;
        indicesVboData = indexies.ToArray();
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年7月23日 10:55
  •  /// Creates a 3D icosahedron of unit size using the current color
      let icosa = DF (fun ctx ->
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, ctx.Color)
        GL.Begin(BeginMode.Triangles)
        let G  = float32 ((1.0 + Math.Sqrt(5.0)) * 0.5)
        GLEx.Face
          ( 1.f, 0.f, G)
          [ ( 1.0f,  0.0f,  G); ( 0.0f, -G, 1.0f); ( G, -1.0f,  0.0f); 
            ( 1.0f,  0.0f,  G); (-1.0f,  0.0f,  G); ( 0.0f, -G, 1.0f);
            ( 1.0f,  0.0f,  G); ( G,  1.0f,  0.0f); ( G, -1.0f, 0.0f);
            ( 1.0f,  0.0f,  G); (-1.0f,  0.0f,  G); ( 0.0f,  G, 1.0f); 
            ( 1.0f,  0.0f,  G); ( 0.0f,  G,  1.0f); ( G,  1.0f,  0.0f) ]
        GLEx.Face
          (G,  1.f,  0.f)
          [  ( G,  1.0f,  0.0f); ( G, -1.0f,  0.0f); ( 1.0f, 0.0f, -G) ]
        GLEx.Face
          (0.f,  G, -1.f)
          [ ( 0.0f,  G, -1.0f); (-1.0f,  0.0f, -G); ( 1.0f,  0.0f, -G);
            ( 0.0f,  G, -1.0f); ( G,  1.0f,  0.0f); ( 1.0f,  0.0f, -G);
            ( 0.0f,  G, -1.0f); ( G,  1.0f,  0.0f); ( 0.0f,  G,  1.0f); 
            ( 0.0f,  G, -1.0f); ( 0.0f,  G,  1.0f); (-G,  1.0f,  0.0f);
            ( 0.0f,  G, -1.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f, -G) ]
        GLEx.Face
          (-G, 1.f, 0.f)
          [ (-G,  1.0f,  0.0f); (-1.0f,  0.0f,  G); ( 0.0f,  G,  1.0f) ]
        GLEx.Face
          (-G, -1.f, 0.f)
          [ (-G, -1.0f,  0.0f); ( 0.0f, -G,  1.0f); (-1.0f,  0.0f,  G);
            (-G, -1.0f,  0.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f, -G);
            (-G, -1.0f,  0.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f,  G) ]
        GLEx.Face
          (0.f, -G, -1.f)
          [ ( 0.0f, -G, -1.0f); ( 0.0f, -G,  1.0f); ( G, -1.0f,  0.0f);
            ( 0.0f, -G, -1.0f); ( G, -1.0f,  0.0f); ( 1.0f,  0.0f, -G);
            ( 0.0f, -G, -1.0f); ( 1.0f,  0.0f, -G); (-1.0f,  0.0f, -G);
            ( 0.0f, -G, -1.0f); (-1.0f,  0.0f, -G); (-G, -1.0f,  0.0f);
            ( 0.0f, -G, -1.0f); (-G, -1.0f,  0.0f); ( 0.0f, -G,  1.0f) ]
        GL.End() )

    libraryはこれを使って書きました。
    • 回答としてマーク phy_6 2017年8月18日 23:17
    2017年8月18日 23:15

すべての返信

  • OpenTKを使ったことが無いのでGLEx.Faceが何をやっているコードなのか不明ですが、おそらく面を描画させているのだとすると、3面しか描画してないので20面には足らないですよね。
    この直交する3つの四角形の12個の頂点を結ぶと正20面体ができるのでしょうから、そのように20個の3頂点を用意すればよいのではないでしょうか。

    C#でOpenTKのサンプルコードに手を加えてみると20面体になりますし

    public HelloGL3()
        : base(640, 480,
        new GraphicsMode(), "OpenGL 3 Example", 0,
        DisplayDevice.Default, 3, 0,
        GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug)
    {
        //正20面体の頂点座標を用意する
        float G = (float)((1.0 + Math.Sqrt(5)) * 0.5);
        Vector3[] vertexies = new Vector3[]{
                new Vector3(1, G, 0),
                new Vector3(0, 1, G),
                new Vector3(G, 0, 1),
    
                new Vector3(-1, G, 0),
                new Vector3(0, -1, G),
                new Vector3(G, 0, -1),
    
                new Vector3(1, -G, 0),
                new Vector3(0, 1, -G),
                new Vector3(-G, 0, 1),
    
                new Vector3(-1, -G, 0),
                new Vector3(0, -1, -G),
                new Vector3(-G, 0, -1)
        };
                
    
        //各頂点に直近の点の集合
        List<int[]> listNear5 = vertexies.Select(a => vertexies.Select((b, i) => new { Index = i, LEN = (a - b).Length }).OrderBy(_ => _.LEN).Skip(1).Take(5).Select(_ => _.Index).OrderBy(_ => _).ToArray()).ToList();
    
        //各頂点から作られる三角形の頂点のインデックスを集める
        List<int[]> list3 = new List<int[]>();
        for (int i = 0; i < vertexies.Length; i++)
        {
            for (int j = 0; j < 5; j++)
            {
                for (int k = j + 1; k < 5; k++)
                {
                    int p1 = listNear5[i][j];
                    int p2 = listNear5[i][k];
                    if (listNear5[p1].Contains(p2))
                    {
                        int[] a = new int[] { i, p1, p2 };
                        Array.Sort(a);
                        if (!list3.Any(b => b[0] == a[0] && b[1] == a[1] && b[2] == a[2]))
                        {
                            list3.Add(a);
                        }
                    }
                }
            }
        }
    
        List<int> indexies = new List<int>();
        foreach (int[] a in list3)
        {
            indexies.AddRange(a);
        }
    
        //頂点座標と三角形の面のインデックス集合をサンプルコードに渡す
        positionVboData = vertexies;
        indicesVboData = indexies.ToArray();
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年7月23日 10:55
  • どうやってC#のサンプルソースを改編するんですか?
    2017年7月23日 13:07
  • どうやってと問われましてもOpenTKのどこにもないGLEx.Faceがどこから湧いて出てきたかわからないので変換しようがないですよ。

    それでもエスパーしてみると

    List<int> indexies = new List<int>();
    foreach (int[] a in list3)
    {
        indexies.AddRange(a);
        System.Diagnostics.Debug.WriteLine("GLEx.Face\r\n\t{0}\r\n\t[{0};{1};{2}]", vertexies[a[0]], vertexies[a[1]], vertexies[a[2]]);
    }

    な感じでやれば

    GLEx.Face
    	(1, 1.618034, 0)
    	[(1, 1.618034, 0);(0, 1, 1.618034);(1.618034, 0, 1)]
    GLEx.Face
    	(1, 1.618034, 0)
    	[(1, 1.618034, 0);(0, 1, 1.618034);(-1, 1.618034, 0)]
    GLEx.Face
    	(1, 1.618034, 0)
    	[(1, 1.618034, 0);(1.618034, 0, 1);(1.618034, 0, -1)]
    GLEx.Face
    	(1, 1.618034, 0)
    	[(1, 1.618034, 0);(-1, 1.618034, 0);(0, 1, -1.618034)]
    GLEx.Face
    	(1, 1.618034, 0)
    	[(1, 1.618034, 0);(1.618034, 0, -1);(0, 1, -1.618034)]
    GLEx.Face
    	(0, 1, 1.618034)
    	[(0, 1, 1.618034);(1.618034, 0, 1);(0, -1, 1.618034)]
    以下略
    のような変換はできるんじゃないかな

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年7月23日 14:27
  • このライブラリを使ってフォーラムトップの図形を作成しました。

    C#で改編しようとしたとき
    Designer.csファイルとOpenTKの複数の形式が存在しないため
    ビルドできないと出ました。
    どういったところが作用してこの問題を作っているのか、
    簡易な解決策を示していただけたらと思います。


    2017年7月25日 5:06
  • F#やOpenTKは知らないので、申し訳ございませんが
    よろしければ、お試しいただきたいことがございます。

    正二十面体の頂点を簡単に求められる方法があったなんて

    上記サイトとphy_6様のロジックに使用しているパラメータは
    同一ではないでしょうか?

    そのため、パラメータの部分を次のように修正したのち
    再度、実行してみてください。
    ※おそらく各頂点の設定値が正十二面体の頂点と異なる場所を
    結んでしまったために生じたデザインになったものと推測しております。

    GLEx.Face
    	( 1.0f, G, 0.0f)
    	[ ( 1.0f, G, 0.0f); (-1.0f,  G, 0.0f);
    	  ( 1.0f,-G, 0.0f); (-1.0f, -G, 0.0f) ]
    GLEx.Face
    	( G, 0.0f, 1.0f)
    	[ ( G, 0.0f, 1.0f); ( G, 0.0f, -1.0f);
    	  (-G, 0.0f, 1.0f); (-G, 0.0f, -1.0f) ]
    GLEx.Face
    	( 0.0f, 1.0f, G)
    	[ ( 0.0f, 1.0f, G); ( 0.0f,-1.0f, G);
    	  ( 0.0f, 1.0f,-G); ( 0.0f,-1.0f,-G) ]
    

    2017年7月25日 9:37
  • GLのBeginmodeに叢さんのサイトに書かれたofmeshと対応する表現があるでしょうか?

    ただ単に、頂点を書き連ね頂点をつなぐ方法でやるしかないのではと思ったり
    各多面体座標頂点集

    ここの正二十面体の各座標頂点を利用して記述するしかないと思いました。




    • 編集済み phy_6 2017年7月25日 11:13
    2017年7月25日 10:53
  • 正二十面体は20面と12頂点と30辺

    BeginmodeはPolygonとTriangleとQuadしか描画できない

    • GL TRIANGLES / GL QUADS: 3 あるいは 4 点を組にして,三角形あるいは四角形を描く.

    • GL TRIANGLE STRIP / GL QUAD STRIP: 一辺を共有しながら帯状に三角形あるいは四角形を描く.

    • GL TRIANGLE FAN: 一辺を共有しながら扇状に三角形を描く.

    • GL POLYGON: 凸多角形を描く

    これらに合わせた座標の書き方をするか

    頭にあるのは

      /// Creates a 3D sphere with unit size
      let sphere = DF (fun ctx ->
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, ctx.Color)
        GL.Begin(BeginMode.Triangles)
      
        // points that will be used for generating the circle
        let q = float32 (Math.PI / (float quality / 2.0))
        let circlePoints = 
          [ for i in 0 .. quality -> 
              sin(float32 i * q) * 0.5f, cos(float32 i * q) * 0.5f ]
      
        // points from the top to the bottom
        let heightPoints = 
          [ for i in 0 .. quality -> 
              sin(float32 i * q) * 0.5f, cos(float32 i * q) * 0.5f ]
        
        //  Array (along one dimension) of circles
        let points = 
          [| for hx, hy in heightPoints ->
               [| for x, y in circlePoints -> 
                    Vector3(x * hx * 2.0f, y * hx * 2.0f, hy) |] |]
      
        /// Generate the sphere 
        for lat in 0 .. quality - 1 do
          for i in 0 .. quality - 1 do
            GL.Normal3 points.[lat].[i]
            GL.Vertex3 points.[lat].[i]
            GL.Normal3 points.[lat].[i+1]
            GL.Vertex3 points.[lat].[i+1]
            GL.Normal3 points.[lat+1].[i+1]
            GL.Vertex3 points.[lat+1].[i+1]
      
            GL.Normal3 points.[lat+1].[i+1]
            GL.Vertex3 points.[lat+1].[i+1]
            GL.Normal3 points.[lat+1].[i]
            GL.Vertex3 points.[lat+1].[i]
            GL.Normal3 points.[lat].[i]
            GL.Vertex3 points.[lat].[i]
        GL.End() )
      

    表面積か体積を求めてしまい、実行させる方法です

    正三角形を定義して作成、

    そして12個の座標頂点に

    当てはめる方法ってありますか?

    Beginmode.Quadsで

    立方体はGLEx.Faceの座標が24個

    Beginmode.Trianglesで

    正二十面体はGLEx.Faceの座標が60個

    必須かなと。

    後、F#の基礎もC#の基礎も押さえずに

    進捗の話を進めていたので前、さゆりさんから

    コンソールアプリケーションを作成しまくって

    学習に勤しむべきだとの教示をもらったので

    その通りにし、どういうメカニズムでこの言語は作動するのか?

    というところにポイントを絞ってやっていこうと思います。

    ソースコードと丁寧で簡潔な説明を書いていただき皆様ありがとうございました。

    JAVAとOpenGLで書く正二十面体







    • 編集済み phy_6 2017年7月26日 10:20
    2017年7月25日 12:10
  •  /// Creates a 3D icosahedron of unit size using the current color
      let icosa = DF (fun ctx ->
        GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, ctx.Color)
        GL.Begin(BeginMode.Triangles)
        let G  = float32 ((1.0 + Math.Sqrt(5.0)) * 0.5)
        GLEx.Face
          ( 1.f, 0.f, G)
          [ ( 1.0f,  0.0f,  G); ( 0.0f, -G, 1.0f); ( G, -1.0f,  0.0f); 
            ( 1.0f,  0.0f,  G); (-1.0f,  0.0f,  G); ( 0.0f, -G, 1.0f);
            ( 1.0f,  0.0f,  G); ( G,  1.0f,  0.0f); ( G, -1.0f, 0.0f);
            ( 1.0f,  0.0f,  G); (-1.0f,  0.0f,  G); ( 0.0f,  G, 1.0f); 
            ( 1.0f,  0.0f,  G); ( 0.0f,  G,  1.0f); ( G,  1.0f,  0.0f) ]
        GLEx.Face
          (G,  1.f,  0.f)
          [  ( G,  1.0f,  0.0f); ( G, -1.0f,  0.0f); ( 1.0f, 0.0f, -G) ]
        GLEx.Face
          (0.f,  G, -1.f)
          [ ( 0.0f,  G, -1.0f); (-1.0f,  0.0f, -G); ( 1.0f,  0.0f, -G);
            ( 0.0f,  G, -1.0f); ( G,  1.0f,  0.0f); ( 1.0f,  0.0f, -G);
            ( 0.0f,  G, -1.0f); ( G,  1.0f,  0.0f); ( 0.0f,  G,  1.0f); 
            ( 0.0f,  G, -1.0f); ( 0.0f,  G,  1.0f); (-G,  1.0f,  0.0f);
            ( 0.0f,  G, -1.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f, -G) ]
        GLEx.Face
          (-G, 1.f, 0.f)
          [ (-G,  1.0f,  0.0f); (-1.0f,  0.0f,  G); ( 0.0f,  G,  1.0f) ]
        GLEx.Face
          (-G, -1.f, 0.f)
          [ (-G, -1.0f,  0.0f); ( 0.0f, -G,  1.0f); (-1.0f,  0.0f,  G);
            (-G, -1.0f,  0.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f, -G);
            (-G, -1.0f,  0.0f); (-G,  1.0f,  0.0f); (-1.0f,  0.0f,  G) ]
        GLEx.Face
          (0.f, -G, -1.f)
          [ ( 0.0f, -G, -1.0f); ( 0.0f, -G,  1.0f); ( G, -1.0f,  0.0f);
            ( 0.0f, -G, -1.0f); ( G, -1.0f,  0.0f); ( 1.0f,  0.0f, -G);
            ( 0.0f, -G, -1.0f); ( 1.0f,  0.0f, -G); (-1.0f,  0.0f, -G);
            ( 0.0f, -G, -1.0f); (-1.0f,  0.0f, -G); (-G, -1.0f,  0.0f);
            ( 0.0f, -G, -1.0f); (-G, -1.0f,  0.0f); ( 0.0f, -G,  1.0f) ]
        GL.End() )

    libraryはこれを使って書きました。
    • 回答としてマーク phy_6 2017年8月18日 23:17
    2017年8月18日 23:15