

こんにちは。  
PythonのModernglでGLSLを触りだした初心者です。

OpenCVのカメラモデル（放射方向歪みのパラメータはk1~k3まで）に従って、写真と地形モデルから作成した（直角座標系の）三次元点群をレンダリングするプログラムを書いています。

基本的にはうまく動いており、[![正しくレンダリングされた画像](https://i.stack.imgur.com/ZtX7t.jpg)](https://i.stack.imgur.com/ZtX7t.jpg)
一枚目のようにレンダリングされるのですが、k1,k2に（小さな）負の値を与えると三角形が放射状に広がる図がレンダリングされてしまいます。[![失敗した例](https://i.stack.imgur.com/yyGbK.png)](https://i.stack.imgur.com/yyGbK.png)  
以下がGLSLのプログラムです。

[code]

         vertex_shader='''
             #version 330
             in vec3 in_vert;
             in vec3 in_color;
             out vec3 v_color;
    
             // decrare some values used inside GPU by "uniform"
             // the real values will be later set by CPU
             uniform mat4 proj; // projection matrix
             uniform mat4 view; // model view matrix
             uniform float dist_coeffs[5]; // distortion coefficients 
             // distortion coefficients of OpenCV model k1, k2, k3, p1, p2
             // note that opencv distort-coeff vecor is (k1, k2, p1, p2 [,k3])
    
             vec4 distort(vec4 view_pos){
              // normalize
              float z =  view_pos[2];
              float z_inv = 1 / z;
              float x1 = view_pos[0] * z_inv;
              float y1 = view_pos[1] * z_inv;
              // precalculations
              float x1_2 = x1*x1;
              float y1_2 = y1*y1;
              float x1_y1 = x1*y1;
              float r2 = x1_2 + y1_2;
              float r4 = r2*r2;
              float r6 = r4*r2;
              // rational distortion factor
              float r_dist = (1 + dist_coeffs[0]*r2 + dist_coeffs[1]*r4 + dist_coeffs[2]*r6);
              // full (rational + tangential) distortion
              float x2 = x1*r_dist + 2*dist_coeffs[3]*x1_y1 + dist_coeffs[4]*(r2 + 2*x1_2);
              float y2 = y1*r_dist + 2*dist_coeffs[4]*x1_y1 + dist_coeffs[3]*(r2 + 2*y1_2);
              // denormalize for projection (which is a linear operation)
              return vec4(x2*z, y2*z, z, view_pos[3]);
              }
    
             void main() {
                 vec4 local_pos = vec4(in_vert, 1.0);
                 vec4 view_pos = vec4(view * local_pos);
                 vec4 dist_pos = distort(view_pos);
                 v_color = in_color;
                 gl_Position = vec4(proj * dist_pos);
             }
         ''',
         fragment_shader='''
             #version 330
             in vec3 v_color;
             layout(location=0)out vec4 f_color;
             void main() {
                 f_color = vec4(v_color, 1.0); // 1,0 added is alpha
             }
         '''
    
[/code]

また、カメラのオイラー角、座標、視野角、画像サイズからモデルビュー行列・プロジェクション行列を作る関数は以下の通りです（R言語）

[code]

    # camera intrinsic matrix
    projection_mat <- function(fov_x_degree, w, h, near = -1, far = 1
                               , cx = w/2, cy = h/2){
      fov_x <- fov_x_degree * pi /180
      fov_y <- fov_x * h / w
      fx <- 1/(tan(fov_x/2))
      fy <- 1/(tan(fov_y/2))
      matrix(c(fx , 0, (w-2*cx)/w, 0, 
               0, fy, -(h-2*cy)/h, 0,
               0, 0, -(far+near)/(far-near), -2*far*near/(far-near),
               0, 0, -1, 0), 
             ncol = 4, 
             byrow = F) %>% 
        as.vector() %>% 
        reticulate::np_array(dtype = "float32")
    }
    
    # camera extrinsic parameter
    modelview_mat <- function(pan_degree, tilt_degree, roll_degree, t_x, t_y, t_z){
      y <-  (360 - pan_degree) * pi / 180
      x <-  (tilt_degree) * pi / 180 
      z <-  (roll_degree) * pi / 180
    
      rmat_z <- c(cos(z), -sin(z), 0, 0,
                  sin(z), cos(z), 0, 0,
                  0, 0, 1, 0,
                  0, 0, 0, 1) %>% matrix(ncol = 4, byrow = T)
      rmat_x <- c(1, 0, 0, 0,
                  0, cos(x), -sin(x), 0,
                  0, sin(x), cos(x), 0,
                  0, 0, 0, 1) %>% matrix(ncol = 4, byrow = T)
      rmat_y <- c(cos(y), 0, sin(y), 0,
                  0, 1, 0, 0,
                  -sin(y), 0, cos(y), 0,
                  0, 0, 0, 1) %>%matrix(ncol = 4, byrow = T)
      rmat <- rmat_x %*% rmat_z %*% rmat_y
      tmat <- matrix(c(1, 0, 0, -t_x,
                       0, 1, 0, -t_z,
                       0, 0, 1, -t_y,
                       0, 0, 0, 1), byrow = T, ncol = 4)
      rmat %*% tmat %>%
        as.vector() %>% 
        reticulate::np_array(dtype = "float32")
    }
    
    
[/code]

どうやらカメラ座標に近いところや視界の端に位置する点群がレンダリングされていそうなことはわかったのですが、理由や対処法がわかりません。ジオメトリシェーダを使って不審な三角形を除く（？ジオメトリシェーダについてまだ良く知らないので間違っていたら教えてください）ことも考えています。

このような図がレンダリングされる理由や解決策についてなにかご存知のことがあれば教えていただけると幸いです。


CC BY-SA 4.0
2020-04-30T06:37:54.073
66141
2020-04-30T06:49:15.003
2020-04-30T06:49:15.003
39892
39892
question
opencv opengl
GLSLでレンズ歪みを実装したが、係数次第で放射状に広がる三角形がレンダリングされる