반응형

최근 다관절 셋팅을 하면서 컨트롤러 셋팅을 많이 하게 되는데, 맥스의 컨트롤러 뷰어는 불편한 점이 많아서 서포트 툴을 하나 제작하게 됐습니다.

특히 LookAtConstraint나 Orientation Controller같이 다른 헬퍼 본과 연계되서 사용할 경우 연계된 본이 어떤건지 구분하기도 힘들고 선택하기도 힘들어 자주쓰는 노드들과 연계하기 편하도록 제작해 봤습니다.


 


이번 툴을 제작하면서 공부한 내용

1. Struct로 따로 분리하여 기능 별로 함수 관리하기.

- 닷넷에 사용하는 트리뷰와 리스트뷰기능만을 구조체로 따로 뺀뒤 기능 함수를 호출해서 사용하는 방식에 대해서 공부하고 숙지했습니다.

기능 구현에만 집중해서 코딩하다 보면 나중에 손댈 수 없는 지저분한 코딩이 될 수 있어 미리미리 코드 정리하는 습관이 중요함을 알게됐습니다.

 

2. 재귀함수의 사용법 다시 한 번 숙지

- 아트직업군에 오래 머물러 있다보니 논리적 사고가 부족해 재귀함수의 흐름을 익히는데 어려움이 많이 있습니다.

지난번 페이스 셀렉트 툴에서도 여러번 익히며 사용법을 완전 숙지했다고 생각했으나 이번 툴을 만들면서 아직 개념이 들 잡혀있음을 알게 되었고, 좀더 연습할 수 있는 시간이었습니다. 좀 더 많은 코딩을 통해 계속해서 숙지해야 할 필요성을 느끼게 됐습니다.

 

ControllerNodeViewer2.mse

 

반응형
반응형

최근 회사에서 언리얼 마켓 플레이스에서 구매해 사용하는 데이터들이 점점 많아지다 보니 관리가 힘들어져 만든 스크립트입니다.

애니메이션 팩 같은 경우는 한번 사면 60개는 기본으로 들어 있더라구요.

이 데이터를 그대로는 못쓰기 때문에 맥스에서 불러온뒤 본 네이밍등을 변경해서 다시 저장해주는 스크립트입니다.

중간에 본 네이밍을 바꿔주는 내용은 저희 회사 규약에 맞춰져 있어서 빼고 사용하시면 됩니다.


1. 대상 FBX 파일들을 불러옴

2. 맥스에서 FBX를 임포트하여 MAX 파일로 변환 후 저장

3. 완료된 MAX 파일들 다시 일괄적으로 익스포트

 

FbxToMaxListBox.ms


1번을 통해 일괄 변환할 FBX 파일들을 선택하여 부르면 2번에 리스트가 나옵니다.

3번을 눌러 맥스파일을 저장할 경로를 선택하고,

4번을 누르면 일괄적으로 본 네임과 애니메이션 길이등을 자동으로 맞춰 맥스파일로 저장해줍니다.

그리고 5번을 눌러 배치익스포트를 불러 다시 일괄 익스포트를 하면 언리얼용 FBX 데이터로 변환됩니다.

 

반응형
반응형

기존에 제작한 은면제거 방식은 벡터의 내적이라는 수학 공식을 활용하여 카메라와 대치되는 각을 계산하여 면을 제거하는 방식이었습니다.

하지만 이 방식은 몇가지 단점이 존재합니다.


1. 각도를 계산해서 하다보니 카메라에 안잡히는 면도 각도조건만 맞으면 남아있게 된다.

2. 면이 깔끔하게 지워지지 않는다. 가령 면은 지워졌는데, 버텍스가 남는다던지..

 

등등.. 여러번 시뮬레이션을 돌려보면 금방 알 수 있는 단점들이 존재합니다.

하지만, 이번에 제작한 Hidden Surface 방식은 렌더링 된 G-Buffer의 값을 얻어와 지오메트리의 렌더링된 면을 메모리에 기억하여 삭제하는 방식이라 더 깔끔하게 면들을 정리해줍니다.

단, 계산시간이 오래 걸릴수 있다는 단점이 있습니다. 이 부분도 차후에 개선할수있도록 해보겠습니다.


이 스크립트의 구동방식을 간단히 살펴보면

1. 먼저 대상이 될 오브젝트의 면들을 전부 디테치 한 후 메모리에 저장한후 각 면마다 오브젝트를 생성해 줍니다.

-여기서 먼저 대상이 될 원본 오브젝트를 하이드 시켜 줍니다.(G-Buffer값 구할때 방해되는 요소)


 



2. 디테치된 면들의 렌더링 된 채널값에서 G-Buffer(지오메트리버퍼) 값을 구해온다.

G-Buffer의 개념 - http://en.wikipedia.org/wiki/Deferred_shading


3. 렌더링 버퍼의 값을 구해서 원본 모델링에 저장이 됐으면 이제 각 면들은 필요없어 졌으니 전부 지워버린다.


4. 원본 면의 페이스 정보들을 비트어레이에 담고 G-Buffer에 담긴 값들만 False로 선언해준다.

5. 이제 원본 오브젝트의 비트어레이에 담긴 면들을 삭제하라는 명령을 실행하면 false로 제외된 값들을 빼고 삭제를 하게 된다.



벡터의 내적 방식과 Hidden Surface 방식의 비교 샷


백페이스 방식- 면이 지저분하게 정리된다.  


 

 히든 서페이스 방식 - 면이 깔끔하게 정리된다.

 

 

이번 과제를 통해 알게 된 내용

1. G-Buffer의 개념과 렌더링에 대한 기초

2. 원본에 있는 면을 뜯어내서 메모리에 저장시킬 수 있는 기능

3. finditem을 이용하여 비트어레이의 값을 조절할수 있는 기능

반응형
반응형

이 스크립트는 최적화를 위한 툴로서 카메라에 보이지 않는 면들을 제거하여 카메라렌더링에 대한 연산을 최소화

시키지 위한 툴입니다.

 

이번 과제를 해결하기 위해서는 삼각함수의 기본 원리와 벡터의 내적을 구하는 공식에 대한
이해가 필요했습니다.

카메라와 오브젝트간 벡터의 내적이 0보다 큰 수의 면만 선택하여 삭제하는 공식을 이해하는데

많은 시간이 필요했습니다.

카메라가 A이고 오브젝트의 한 단면이 B 이고 살리고 싶은 면이 C일때

C = a b cos@를 이용한 벡터의 내적을 이용하여 cos@가 0보다 큰면은 카메라가 바라보는 방향과

같은 방향을 바라보기 때문에 카메라가 잡히지 않는 구간입니다.

따라서 0보다 작은 마이너스 구간을 살리고 0보다 큰 플러스 구간은 삭제하면 됩니다.

 

이 공식을 이용하여 스크립트를 짜게 되면 영상과 같은 결과가 출력됩니다.


 


스크립트

Global backFaceDeleter


--======================================================================================
-- DestroyDialog
--======================================================================================
try (DestroyDialog backFaceDeleter) catch()

--==========================================================================================================

-- rollout backFaceDeleter

--==========================================================================================================
rollout backFaceDeleter "백페이스 방식 삭제"
(
 local mainCamera  -- 메인 카메라 선언
 
 --======================================================================================
 -- struct
 --====================================================================================== 
 struct strt_objinfo   --max 스크립트는 변수 선언에 형식의 제한이 없다. 모든 값을 넣을 수 있음(오브젝트형식)
 (
  obj,     -- 오브젝트 정보
  faces = #(),    -- 전체 페이스 정보
  faceobjs = #()   --  참인 값의 페이스 정보
 )
 ------------------------------------------------------------------------
 -- CameraFilter
 ------------------------------------------------------------------------
 fn FilterCam cam =   --카메라 아니면 선택되지 않게 설정
 (
  if iskindof cam camera then
   return true
  else
   return false
 )
 --======================================================================================
 -- UI
 --======================================================================================
 pickbutton ptn_camera "Pick" filter:FilterCam
 button btn_BackFace "BackFace"
  
  
 --======================================================================================
 -- Fn
 --======================================================================================

 ------------------------------------------------------------------------
 -- FindBackface
 ------------------------------------------------------------------------ 
 fn BackFaceinfo obj camLookPos =     ---- 백페이스 정보와 오브젝트와 카메라의 바라보는 뷰를 변수 선언
 (
  local backFaces = #{}      ----백페이스 관련 좌표와 벡터값을 얻어내기 위해 비트 어레이 변수 선언
                                     
  faceNum = getNumFaces obj        --- 페이스 넘버는 곧 오브젝트의 페이스 넘버다
  for i = 1 to faceNum do                           ----- 1번부터 전체 페이스 넘버를 돌면서 아래를 실행
  (
   facePos = meshop.getFaceCenter obj i        ---- 한 페이스의 중앙 점 좌표를 camLookPos이라는 변수에 대입
   lookV = facePos - camLookPos                            ---- 위에서 구한 중앙 좌표에서 카메라의 위치값을 빼서 lookV에 넣는다. 그래야 벡터의 내적을 구하니까
   
   faceNormal = getFaceNormal obj i        --- 한 페이스가 바라보는 벡터값을 faceNormal 이라는 변수값에 대입
   if dot lookV faceNormal > 0 then       --- 그래서 페이스에서 카메라위치값을 뺀 벡터와 한 페이스의 벡터값을 뺀것의 내적이  0보다 클경우 참.  참인면을 최종적으로 지울것   바라보는 각을 지우고 반대쪽을 바라보는 각을 살리기 위해
    backfaces[i] = true                   --- 비트어레이 backfaces의 페이스 넘버의 참과 거짓을 가림
  )
  
  return backFaces     --- 백페이스 정보 리턴
 )
 
 --======================================================================================
 -- UI Control
 --======================================================================================
 ------------------------------------------------------------------------
 -- ptn_camera
 ------------------------------------------------------------------------ 
 on ptn_camera picked cam do    --- 카메라를 클릭했을때 이름 보여줌
 (
  ptn_camera.text = cam.name
  mainCamera = cam
 )
 
 ------------------------------------------------------------------------
 -- btn_DeleteBackface
 ------------------------------------------------------------------------
 on btn_BackFace pressed do
 (
  local meshObj = $
  local cams = mainCamera

  convertToMesh meshObj  ---메시 형태가 아니면 폴리 넘버를 알수 없다.
  backfaces = BackFaceinfo meshObj cams.pos  ---bacakfaces에 오브젝트와 카메라의 포지션을 넣는다.
  objinfo = strt_objinfo meshObj backfaces   --struct함수로 선언한 세 변수에 각각 값을 집어넣는다. obj에 선택한 오브젝트, face에 backfaces(참인 면)

  --obj : 선택한 오브젝트      faces : 참인 면들의 배열(비트어레이)
  
  print objinfo
  print  objinfo.faces
  
  if objinfo.faces.numberset < getNumFaces meshObj then   -- numberset은 비트어레이 배열안에 몇개의 수가 있는지 알려줌, struct안에 배열의 수가 선택한 메시 수보다 작을경우 선택한 메시의 struct 변수에 넣은
    meshop.deleteFaces meshObj objinfo.faces             ---참인면들을 지워라!
   
  deselect $
  select meshObj
 )
)

CreateDialog backFaceDeleter width:100 height:50

 

 

이번 과제는 저에게 큰 벽이었습니다. 중 고딩때 수학공부를 게을리한 내 자신이 이렇게 미울수가 없었네요..ㅠ

지난 한주간 용인 사는 누나댁을 오가며 열심히 원리를 깨우쳤습니다. 수학과 나온 누님이 저에게 도움 되는 날이

올줄 몰랐어요..ㅎㅎ   어렵지만, 이해하고 나니 정말 극 쾌감이 몰려오네요~^^ 

근데 백페이스 방식은 여러가지 단점이 있어 HIdden 방식을 써야 하는 경우가 생깁니다.

그 방식에 대해서는 다음에 다뤄보겠습니다.


참고 사이트 황군 - http://hwanggoon.tistory.com/118

반응형

+ Recent posts