Knowhow/Vision

Open3D Normal map rendering, Normal 이미지 얻는 방법

침닦는수건 2024. 11. 5. 11:08
반응형

Open3D에서 주어진 mesh의 normal을 얻어내는 방법은 쉽다. Document에서도 이 기능만 설명한다.

import open3d as o3d

mesh = o3d.io.read_triangle_mesh(MESH_PATH)
mesh.compute_vertex_normals() # vertex normals are filled in
mesh.compute_triangle_normals() # face normals are filled in

 

그런데 normal map 즉 2D 형태로 얻는 방법은 명확히 없다. normal rendering을 하는 방법이 뚜렷하지 않다. 

  vis = o3d.visualization.Visualizer()
  vis.create_window(visible=True)
  opt = vis.get_render_option()    
  opt.mesh_color_option = o3d.visualization.MeshColorOption.Normal # core

 

위와 같이 visualizer의 색상 옵션을 normal로 변경하면 normal 이미지를 만들어 주긴 하지만 RGB값이 normal vector (nx, ny, nz)와 어떻게 대응되는지 알 수 없어서 값을 변환해서 쓸 수 없다.

 

nx = 2*R-1 # R 0-1
ny = 2*G-1 # G 0-1
nz = 2*B-1 # B 0-1

 

보통 위와 같이 변환하는데, 그대로 해보면 normal vector가 mesh face에 수직한 방향이 아니라 나란한 방향으로 나온다. (축이 어딘가 다르다는 뜻. RGB가 Combination(XYZ) 중 어떤 조합으로 계산되는지는 모른다.) 게다가 크기도 1로 normalized되어 있는 값이 아니어서 RGB만 보고 normal vector를 계산할 수 없다.

 

우회법

어떻게 normal map을 렌더링하느냐? 방법은 생각보다 간단하다. RGB 렌더링 모드를 그대로 사용하는데 vertex color 부분에 vertex normals을 채워넣는 방법이다. 

   mesh = o3d.io.read_triangle_mesh(MESH_PATH)   
   mesh.compute_vertex_normals()
   vertex_normals = np.asarray(mesh.vertex_normals) * 0.5 + 0.5 
   mesh.vertex_colors = o3d.utility.Vector3dVector(vertex_normals)
   
   #with
   opt.mesh_color_option = o3d.visualization.MeshColorOption.Color

 

-1~1 범위의 normal 값들을 0~1 범위의 RGB 크기에 맞춰 scale+trans 해준 뒤, vertex_colors에 채워넣고 그대로 렌더링하면 된다. 

 

렌더링 하는 방법은 이전 글 참고.

반응형