반응형

 회사 모델러들의 요청으로 모델링 관리를 펴하게 해주는 툴을 제작해 봤습니다.

 

이 툴에서 사용할 수 있는 기능들 간단 요약

1. 파일 서치 기능

2. 맥스파일을 열어보지 않고 고퀄의 프리뷰와 다양한 파일 정보(갯수, 크기, 버텍수등..) 로 미리 확인 가능

3. 다중 파일을 지정된 폴더에 동시 익스포트 가능

4. 다중 선택 파일을 지정한 폴더에 자동으로 익스포트 가능

5. FBX를 맥스로 맥스를 FBX로 변환이 매우 간단함(여러파일 동시에도 가능)

6. 대규모 파일관리와 여러 프로젝트를 동시에 관리하게 용이함



* 간단한 기능 설명

제일 먼저 대표로 사용될 폴더를 지정해 줍니다.

모델링 라이브러리 SVN 폴더를 지정하시면 됩니다.

 

(1) 간단한 익스포트

-단일 파일 익스포트 방식

익스포트 폴더를 지정하시고 난후 오브젝트를 선택하거나 파일을 선택한후, 혹은 Export나 ExportSelected 버튼을 눌러주시면

지정한 익스포트 폴더에 바로 익스포트가 진행됩니다.

 

 

 

** 익스포트 폴더를 Export Path로 지정하지 않고, 폴더 리스트중에 선택하셔서 지정하실 수도 있습니다.

Path Clean 버튼을 눌러 Export Path를 초기화 한후 New Folder로 원하시는 폴더를 만들고 폴더를 선택하신 다음 Export 버튼을 누르면 해당 폴더에 익스포트 됩니다.

--->

 

-- 다중 익스포트 방식

파일 리스트에서 익스포트를 원하는 파일들을 모두 선택후 Export Path로 경로를 설정하시면 선택한 파일들 모두 Export가 한방에 진행됩니다.

 

 

 

 

(2) 간단한 파일 서치와 편리한 프리뷰 기능

예 -> ART에 사용된 나무 데이터만 추려서 보고 싶을때..

ART 폴더 지정 -> tree 키워드 입력후 엔터 -> 파일에 대한 정보 출력.

검색된 파일의 Open, Merge, Export 등이 가능합니다. 

 

 

 (3) 간단한 파일변환 FBX -> MAX   or  MAX -> FBX

FBX를 MAX로 변환할 파일들을 리스트뷰에서 선택한 후 SAVE 버튼을 누르면 FBX가 있는 폴더에 그대로 MAX 로 저장되면서 파일이 생성됩니다.

 

 

(4) 맥스에서 씬 배치후 씬 그대로 유니티나 언리얼로 옮겨오기가 간편함

맥스상에서 터레인과 오브젝트등을 배치한 후 전부 선택한 Export Selected 버튼을 누르면 그대로 각 오브젝트별로 익스포트를 진행해 줍니다.

FBX  이름은 각 오브젝트 이름으로 지정됩니다.

 

 

위 과정을 거쳐 익스포트 하시면 Export Path 로 지정한 폴더에 각 이름별로 알아서 FBX 파일이 뽑히게 됩니다.

그후에 아래 파일들을 유니티로 그대로 임포트해오면 맥스 씬에 있는 그대로 불러와지게 됩니다.  

 

 

 

 

ModelingLibrary.mse

반응형
반응형

1. 먼저 Newtonsoft.dll 파일을 구해서 원하는 폴더에 넣어 놓습니다. Dll 이 있어야 편하게 파싱이 가능합니다.

- 처음에 DLL이 없다보니까 텍스트의 라인과 위치까지 세면서 코드를 짜느라 굉장히 애먹었는데, DLL로 파싱하니 굉장히 간단하게 코드가 마무리되었습니다.

구글에 치시면 금방 찾으실 수 있습니다.

 

2. 사용될 스크립트 코드에 DLL 을 로드 하는 구문을 넣어 줍니다.

위 경로에 DLL을 넣고 아래 코드를 넣어주면 DLL을 로드해 옵니다.

 

 

 

3. JSON이 사용될 부분에서 파싱한다는 코드를 넣어줍니다.

  local data ="" 

  if filePath == undefined then
   return 0

  fs=openFile filePath mode:"r"

  while not eof fs do
  ( 
   jsonString = readline fs
   append data jsonString   ---> 제이슨 스트링을 data 라는 텍스트 어레이 변수에 담으면 제이슨을 읽어옵니다.
  )

  o = JObj.parse data -> 읽어온 제이슨 데이터를 파싱해주는 구문입니다.

 

 

4. 파싱이 완료되면 아래같은 간단한 코드로 원하는 부분의 텍스트 정보를 읽어오게 됩니다.

   sidelength = ((o.item["gridCells"].item[1].item["sideLength"].value) as integer)
--> 제이슨 데이터의 GridCells의 첫번째 아이템에서 sidelength의 값을 읽어오라는 코드입니다.




위 과정을 통해 유니티의 그리드 정보를 json으로 읽어와서 그대로 맥스 스크립트로 옮겨올 수 있었습니다.

 

test.json

UnityGridViewer.mse

 

 

반응형
반응형

회사 모델러들이 맥스에서 엔진 버텍스를 바로 보고 싶다는 의견이 있어 혼자서 고민하며 만들어봤습니다.

여러가지 이유로 엔진과 동일한 수는 얻어 올 수 있지만, 아래와 같은 방법으로 비슷한 수치는 얻어 올 수 있었습니다.

첨부파일을 받으시면 사용하실 수 있습니다.



1. 모델링 버텍스가 아닌 언렙 버텍스를 계산하라!

언렙을 사용하면 한 버텍스에 두개의 UV정보를 가지게 되는 경우가 생기므로 이 때 버텍스가 증가하게 됩니다.

 

 

따라서 6200개의 버텍스의 모델링이

 

언렙된 버텍스의 수를 계산하면 8500여개가 됩니다.

 

따라서 언렙전과 언렙후에 엔진에서는 버텍스수가 달라지게 됩니다.

스크립트를 사용할 때도 반드시 언렙후에 사용해야 좀더 정확한 수치를 알게 됩니다.

 

 

 

2. 연속성이 떨어지는 메쉬를 재 연산하라.

엔진에서 불 연속성의 메시라고 파단될 경우 2배로 곱해져서 버텍스가 연산된다.

근데 그 기준을 잡기가 매우 애매하다.. 그래서 불연속성이 많이 발생할 것으로 예상되는 아웃라인 쪽의 메시를 한번더 연산했다.

선택하기가 매우 까다로워 약간의 꼼수를 사용했기 때문에 정확한 갯수는 집계가 어렵다.

현재는 이 두가지의 버텍스를 카운트 하여 제법 근사치에 가까운 결과를 얻었습니다.

유니티 9120 - 맥스 6248 = 2872 차이에서

유니티 9120 - 맥스 스크립트 9086 = 34 개 차이가 남


위 모델링 외에 5개를 더 테스트해봐도 꾀 만족스러운 결과를 얻었습니다.

테스트캐릭터   맥스 버텍스 엔진 버텍스 스크립트 사용시
samuro04  6248 (3000차이) 9120 9086 (40 차이)
Achilleus  699 (500차이) 1157 1155 (2 차이)
plane03  822 (700차이) 1568 1422(140 차이)
agentsmire  711 (400차이) 1162 1160 (2 차이)
akedb  685 (500차이) 1201 1152(50 차이)
alfina  783 (400차이) 1179 1203(20 차이)


하지만, 이 외에도 노멀벡터와 라이팅 등에 의해서 재 연산되는 엔진 버텍스를 정확히 재정의하는것은 무리가 있습니다.

위 정보에 따른 버텍스는 언리얼과 유니티도 버텍스수가 다릅니다.

EngineVertexCount.mse

 


 

반응형
반응형

제작한 스크립트를 메뉴에 등록하지 않으면 실 작업자들이 실제로 사용하는데 많은 제약이 따릅니다.

그런 문제가 없기 위해 제작한 스크립트는 반드시 메뉴에 등록을 해줘야하는데, 그 방법에 대한 가이드입니다.



맥스 스크립트 메뉴 등록 가이드

1. 맥스 스크립트 상단메뉴에 들어가려면 반드시 메크로 스크립트로 등록된 스크립트만 사용이 가능 합니다.

  • 현재 사내 매크로 스크립트는 맥스 설치폴더\\MacroSciprs\\Nlabs 폴더에 모여 있습니다.

  • 스크립트는 MacroScript 폴더에 모여있는 매크로 스크립트와 Script 폴더에 모여있는 보통 스크립트로 나뉘어 집니다..

  • 두 개의 차이점 : 

            (1) 매크로는 간단하게 실행가능한 원클릭 스크립트에 대부분 사용된다.  매크로는 맥스가 실행될께 함께 실행 되기 때문에 덩치가 커서는 안됩니다.

            (2) 일반 스크립트는 시퀀스 매니저나 애니메이션 라이브러리 같이 덩치가 큰 스크립트에 사용된다.

                내가 실행을 해야만 작동하기때문에 덩치가 커도 무리가 없습니다.

 

 

2.  매크로 스크립트를 만들기

- 현재 사내에 사용중인 매크로 스크립트들은 메뉴 등록에만 사용되고, 실제 만들어진 덩치큰 스크립트를 실행해주는 교두보 역할을 해주고 있습니다.

- 예) SequenceManeger가 메뉴에 등록될때는 매크로가 사용되고, 메뉴 버튼을 누르는 순간 실제 스크립트가 실행됩니다.

 

**사내에서 사용중인 본 메이커의 실행 매크로 스크립트

macroScript BoneMaker       --> 매크로 등록
category:"Nlabs"                    --> 카테고리 등록
buttonText:"Bone Maker"        --> 메뉴 버튼 이름 등록
tooltip:"Bone Maker"            --> 툴팁 등록
(
 on execute do
 (
   include "Nlabs/BoneMaker.ms"  --> 매크로 스크립트에 실제 스크립트가 실행되도록 연결해 줍니다.
  )
)



 

 

3. 위 매크로 스크립트를 메뉴에 등록시키기 위한 코드

- 아래 코드를 만든 후 Scripts\\Startup 폴더에 저장하시면 맥스가 실행될때 항상 메뉴가 나오게 됩니다.

스타트업에 들어간 스크립트는 맥스가 실행될때 항상 같이 실행되오니 꼭 필요한 것들만 넣어야 합니다.

 

--------------------------------------------------------------------------------------------------------

-- MainMenuClass

--------------------------------------------------------------------------------------------------------

struct MainMenuClass

(

 --------------------------------------------------------------------

 -- FindMenu

 --------------------------------------------------------------------

 fn FindMenu menuName = 

 (

             local menu = menuMan.findMenu menuName -- 없으면 undefined

             return menu

 ),

 

 --------------------------------------------------------------------

 -- AddMenu

 --------------------------------------------------------------------

 fn AddMenu menuName =

 (

             local newMenu

            

             -- 중복 추가 방지 --

             if FindMenu menuName != undefined then

              return undefined

            

             -- Menu 추가 --

             newMenu   = menuMan.createMenu menuName

             mainMenu  = menuMan.getMainMenuBar()

             subMenuItem = menuMan.createSubMenuItem menuName newMenu

             subMenuIndex = mainMenu.numItems() + 1

             mainMenu.addItem subMenuItem subMenuIndex

            

             return newMenu

 ),

 

 --------------------------------------------------------------------

 -- AddItem

 --------------------------------------------------------------------

 fn AddItem menuName item =

 (

             local newIndex

            

             menu = FindMenu menuName

            

             -- Menu가 없으면 패스 --

             if menu == undefined then

              return undefined

            

             newIndex = menu.numItems() + 1

             menu.addItem item newIndex

            

             return newItem

 ),

 

 --------------------------------------------------------------------

 -- RemoveMenu

 --------------------------------------------------------------------

 fn RemoveMenu menuName =

 (

             menu = menuMan.findMenu menuName

            

             if menu != undefined do

              menuMan.unRegisterMenu menu

            

             return ok

 ), 

 

 --------------------------------------------------------------------

 -- UpdateMenuBar

 --------------------------------------------------------------------

 fn UpdateMenuBar =

 (

             menuMan.updateMenuBar()

            

             return ok

 ), 

 

 --------------------------------------------------------------------

 -- CreateActionItem

 --------------------------------------------------------------------

 fn CreateActionItem macroScriptName categoryName =

 (

  local actionItem

 

  actionItem = menuMan.createActionItem macroScriptName categoryName

 

  return actionItem

 )

)

          

(

           menuName    = "Test"

           macroScriptName = "TestItem"

           categoryName   = "Nlabs"

 

           MainMenu = MainMenuClass()

 

           -- menu 만들기 --

           MainMenu.AddMenu menuName

 

           -- Item 만들기 --

           item = MainMenu.CreateActionItem  macroScriptName categoryName

 

           -- menu Item 등록 하기 --

           MainMenu.AddItem menuName item 

 

           -- 화면 갱신 하기 --

           MainMenu.UpdateMenuBar()

)



위 코드를 실행하면 아래 처럼 맥스 메인 메뉴에 원하는 스크립트가 등록이 됩니다.

 


위 상태에서 BoneMaker를 실행하시면 본 메이커 스크립트가 실행됩니다.

 

출처 - ​ http://hwanggoon.tistory.com/212

반응형
반응형

회사에서 맥스 스크립트를 많이 쓰게 되면서 스크립트 관리포인트가 상당히 많이 생겼습니다.

그러다보니 여기저기 버그도 발생하고, 누가 쓰고 있는지 알기도 힘들고, 업데이트 마다 mzp 파일 배포하는 것도 피곤하고..

그래서 SVN이 도입되어 사용되어 왔습니다. 제 선임이 멋지게 구축해 놓은걸 저는 인계받아 쓰고 있는데요

맥스 스크립트에서 SVN에 접근하는 방식에 대한 내용 정리입니다.

출처 -  http://hwanggoon.tistory.com/109

 

 

1. SVN Command Line 설치하기 

다운로드 경로 : http://tortoisesvn.net/downloads.html 

SVN 설치시에는 반드시 Comand 라인을 설치해 줘야만 맥스 설치폴더에서 접근할 수 있게 됩니다.

Command Line 이란? Dos 명령어를 사용해 Svn을 작동 시켜주는 방법입니다.

맥스도 Dos 명령어를 사용할 수 있기 때문에 Command Line을 설치함으로SVN을 맥스에서도 쓸 수 있게 됩니다.

 

 

2. 맥스에서 SVN 사용하기 

1) HiddenDOSCommand 

Dos 명령어를 사용하는 방법은 HiddenDOSCommand 함수를 사용하는 것이 일반적 입니다.

Dos 창이 보이지 않지만 Dos 명령어는 실행 되니깐 즐겨 사용 하는 방법 입니다.

그런데 HiddenDOSCommand는 기능 상 한계가 있는데요.

Log같은 정보를 받을 수 없습니다.

(return 되는 exitCode는 성공, 실패 같은 간단한 정보만을 보여줍니다.)

 

 

2) dotNet Process 

위와 같은 경우는 dotNet을 사용하면 해결 할 수 있습니다.

 

<예제 코드>

commandString = "info \"" + thePath + "\"" -- SVN 파일 경로

-- StartInfo -------------------------------------

 dno_ProcessStartInfo = dotNetObject "System.Diagnostics.ProcessStartInfo"
 dno_ProcessStartInfo.CreateNoWindow = true
 dno_ProcessStartInfo.UseShellExecute = false
 dno_ProcessStartInfo.RedirectStandardOutput = true
 dno_ProcessStartInfo.FileName = "svn"
 dno_ProcessStartInfo.Arguments = commandString
 ------------------------------------------------
 -- Process 적용 --------------------------------
 dnc_Process = dotNetClass "System.Diagnostics.Process"
 process = dnc_Process.Start dno_ProcessStartInfo
 process.WaitForExit()

------------------------------------------------

infoLine = process.StandardOutput.ReadLine()

-- infoLine : svn info 정보를 String으로 받아 볼 수 있음

 

dotNet Process를 사용해서 Dos 명령어를 실행 하는 방법입니다.

WaitForExit는 써주는 것이 좋은데요.

이걸 하지 않으면, Process가 끝나기 전에 MaxScript코드가 실행됩니다.

오류가 날 확률이 있으니 미리미리 방지해 봅니다.

 

 

 

3. User Name 찾기 

 

캐싱파일 분석하기 

SVN을 MaxScript로 만들다 보면 사용자 이름이 필요한 경우가 발생하는데요.

(사용자 정보를 수집할 때 필요하죠.)

SVN 명령어로 사용자 이름을 알 수는 없을 겁니다.

이럴 경우 캐싱 된 SVN파일을 열어 분석해줘야 하는데요.

 

SVN 사용자 정보

경로 : C:\Users\HwangGoon(개인마다 다름)\AppData\Roaming\Subversion\auth\svn.simple

안에 GUI로 되어 있는 파일이 있습니다.

이 파일을 텍스트 편집기에서 열어보면

다음과 같이 나오게 됩니다.

 

K 8
passtype
V 8
wincrypt
K 8
password
V 372
AQAAANCMnd8BFdERjHoAwE/ClK 15+.....
svn:realmstring
V 40
<http://100.100.100.100:80> VisualSVN Server
K 8
username
V 9
hwanggoon
END


 

svn:realmstring 값이 내가 사용하는 Url과 같은지 비교하는 것이 우선이 되겠죠.

(SVN을 2개 이상 사용하는 경우도 많기 때문에)

username 하위에 보시면 hwanggoon이 SVN username입니다.

 - K 8과 같은 코드는 무시하는 것이 좋습니다. 사용자마다 같다는 보장을 할 수 없어요.

 

  

3. SVN 설치 유무 알아내기 

1) TortoiseSVN 설치 알아내기 

특정 프로그램이 설치되어 있는지 확인하는 방법은 윈도우 레지스트리에서 찾을 수 있는데요. 

예제 코드를 보겠습니다.

dnc_Registry = dotNetClass "Microsoft.Win32.Registry"
registryKey = dnc_Registry.LocalMachine.OpenSubKey "SOFTWARE\\TortoiseSVN"

 

위와 같이 찾으면 TortoiseSVN이 설치 되어 있지 않다면 registryKey값은 undefined로 나오게 됩니다.

 

2) Command Line SVN 설치 알아내기 

TortoiseSVN이 설치되어 있어야 Command Line이 있을 수 있겠죠.

그렇다면 위에서 찾은 registryKey를 가지고 한번 더 하위를 찾아 봅니다.

 

dir = registryKey.GetValue "Directory"
svnFile = dir + "bin\svn.exe"

 

이제 svnFile이 있는지 여부만 판단하면 Command Line 설치를 확인이 가능해 지겠죠.

반응형
반응형

스크립트를 만들때 이름으로 서치하는 것은 매우 안좋은 습관이다.

하지만, 바이패드는 이름으로 서치하지 않으면 해당 오브젝트를 찾기 힘들다.

그래서 Script 헬프를 뒤져보니 바이패드의 고유 Node 넘버가 있는것을 확인했다.


biped.getNode $ #lArm link:4  라고 실행하면 아래 표에 따라 L Hand가 호출된다.


Index Limb Name Link Nodes in Link Index Order      
1 #larm L Clavicle L UpperArm L Forearm L Hand
2 #rarm R Clavicle R UpperArm R Forearm R Hand
3 #lfingers L Finger0 L Finger01 L Finger02 L Finger1
    L Finger11 L Finger12 L Finger2 L Finger21
    L Finger22 L Finger3 L Finger31 L Finger32
    L Finger4 L Finger41 L Finger42  
4 #rfingers R Finger0 R Finger01 R Finger02 R Finger1
    R Finger11 R Finger12 R Finger2 R Finger21
    R Finger22 R Finger3 R Finger31 R Finger32
    R Finger4 R Finger41 R Finger42  
5 #lleg L Thigh L Calf L HorseLink L Foot
6 #rleg R Thigh R Calf R HorseLink R Foot
7 #ltoes L Toe0 L Toe01 L Toe02 L Toe1
    L Toe11 L Toe12 L Toe2 L Toe21
    L Toe22 L Toe3 L Toe31 L Toe32
    L Toe4 L Toe41 L Toe42  
8 #rtoes R Toe0 R Toe01 R Toe02 R Toe1
    R Toe11 R Toe12 R Toe2 R Toe21
    R Toe22 R Toe3 R Toe31 R Toe32
    R Toe4 R Toe41 R Toe42  
9 #spine Spine Spine1 Spine2 Spine3
    Spine4      
10 #tail Tail Tail1 Tail2 Tail3
    Tail4      
11 #head Head      
12 #pelvis Pelvis      
13 #vertical Biped COM      
14 #horizontal Biped COM      
15 #turn Biped COM      
16 #footprints Footsteps      
17 #neck Neck Neck1 Neck2 Neck3
    Neck4      
18 #pony1 Ponytail1 Ponytail11 Ponytail12 Ponytail13
    Ponytail14      
19 #pony2 Ponytail2 Ponytail21 Ponytail22 Ponytail23
    Ponytail24      
20 #prop1 Prop1      
21 #prop2 Prop2      
22 #prop3 Prop3      
101 #lfArmTwist L ForeTwist L ForeTwist1 L ForeTwist2 L ForeTwist3
    L ForeTwist4 L ForeTwist5 L ForeTwist6 L ForeTwist7
    L ForeTwist8 L ForeTwist9    
102 #rfArmTwist R ForeTwist R ForeTwist1 R ForeTwist2 R ForeTwist3
    R ForeTwist4 R ForeTwist5 R ForeTwist6 R ForeTwist7
    R ForeTwist8 R ForeTwist9    
103 #lUparmTwist L UpTwist L UpTwist1 L UpTwist2 L UpTwist3
    L UpTwist4 L UpTwist5 L UpTwist6 L UpTwist7
    L UpTwist8 L UpTwist9    
104 #rUparmTwist R UpTwist R UpTwist1 R UpTwist2 R UpTwist3
    R UpTwist4 R UpTwist5 R UpTwist6 R UpTwist7
    R UpTwist8 R UpTwist9    
105 #lThighTwist L ThighTwist L ThighTwist1 L ThighTwist2 L ThighTwist3
    L ThighTwist4 L ThighTwist5 L ThighTwist6 L ThighTwist7
    L ThighTwist8 L ThighTwist9    
106 #rThighTwist R ThighTwist R ThighTwist1 R ThighTwist2 R ThighTwist3
    R ThighTwist4 R ThighTwist5 R ThighTwist6 R ThighTwist7
    R ThighTwist8 R ThighTwist9    
107 #lCalfTwist L CalfTwist L CalfTwist1 L CalfTwist2 L CalfTwist3
    L CalfTwist4 L CalfTwist5 L CalfTwist6 L CalfTwist7
    L CalfTwist8 L CalfTwist9    
108 #rCalfTwist R CalfTwist R CalfTwist1 R CalfTwist2 R CalfTwist3
    R CalfTwist4 R CalfTwist5 R CalfTwist6 R CalfTwist7
    R CalfTwist8 R CalfTwist9    
109 #lHorseTwist L HorseTwist L HorseTwist1 L HorseTwist2 L HorseTwist3
    L HorseTwist4 L HorseTwist5 L HorseTwist6 L HorseTwist7
    L HorseTwist8 L HorseTwist9    
110 #rHorseTwist R HorseTwist R HorseTwist1 R HorseTwist2 R HorseTwist3
    R HorseTwist4 R HorseTwist5 R HorseTwist6 R HorseTwist7
    RHorseTwist8 R HorseTwist9    

 

반응형
반응형

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

특히 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

반응형
반응형

이번에 만든 툴은 SpaceWarpToMorph(스페이스워프 투 모프)

라는 툴로서

맥스의 스페이스 워프 툴을 활용하여 물결치는 메시를 제작했지만, 엔진(유니티,언리얼)에는 들어가지지가 않습니다.

유니티나 언리얼에도 이런 애니를 넣도록 해주는 기능도 없습니다.

그럴때 맥스에서 제작된 스페이스 워프 애니를 모핑 애니데이터로 변경하여 버텍스애니를 적용하면

엔진에 불러올수 있습니다.

하지만, 이것을 수동으로 애니를 넣으려면 매프레임마다 오브젝트를 복사하여 키를 찍어주는 엄청난 노가다

작업을 해야하는데, 이 툴을 활용하면 버튼한방에 마무리됩니다.

 

 

 

문제의 발생과 피드백 상황

1. try( )catch( ) 명령어를 잘못사용하여 문제 발생
-catch 옆에 ( ) 안쳐서 버그 발생

2. 오브젝트에 모핑 모디파이를 추가하기 위해서는 반드시 오브젝트가 선택되어 있어야 하고
 모디파이 모드임을 알려줘야 하는데 빼먹었음.
max modify mode
select morpherObj

3. 모핑의 오브젝트를 등록하고도 Autoload 를 활성화 시키지 않으면 갱신이 안되는데 빼먹음

morpherObj.modifiers[#Morpher].Autoload_of_targets = 1

1값이면 true 0값이면 false

Default가 false라 발생한 문제

4. for문에서는 ( ) 를 한줄정도 생략이 가능한데, 어느 부분에서 쓰고 빼는지에 대해서 어려움을 느낌.

5. 버그가 엄청 발생했는데, print문을 활용하는 능력이 떨어져 버그 잡는데 많은 시간이 소요됨

 

 

본 공부를 통해 깨닫고 배운 내용

1. 함수 선언의 개념에 대해서 학습 - fn 을 통해 함수를 정의할 수 있고, 함수를 파일로 저장하여
include 명령어로 활용할수 있다.

2. for문과 if문에 대한 반복학습을 통해 개념 파악
- for문으로 곱하기 조차 어려워하던 수준인데.. 이제야 그 수준을 살짝 탈피해 가는거 같습니다..ㅠ

3. 레퍼런스 찾기 연습을 통해 버그나 코딩이 막힐때 해결방법에 대해 숙지
- 여전히 더 많은 훈련이 필요함.

4. 배열의 사용법과 append의 사용법 숙지

5. animationRange 활용법 숙지

6. print 문을 활용하여 버그 잡기

 


스크립트 코드



global g_MeshToMorph


try(destroydialog g_MeshToMorph)catch()


rollout g_MeshToMorph "버텍스애니를 모핑으로"
(
 --로컬로 픽 오브젝트 변수 선언--------------------------------------------------------- 
 local setMainObj
 ----------------------------------------------------------------------------------- 
 
 -- FilterMesh ---------------------------------------------------------------------------
 fn FilterMesh obj =
 (
  if iskindof obj PolyMeshObject or iskindof obj Editable_Mesh then
   return true
  else
   return false
 )

 -----------------------------------------------------------------------------------
 --레이아웃
 -----------------------------------------------------------------------------------
 pickbutton pkn_MeshButton "오브젝트 선택" witdh:180 Filter:FilterMesh
 spinner spn_StartFrame "시작프레임: " range: [-9999,9999,0] type:#integer
 spinner spn_EndFrame "끝프레임: " range: [-9999,9999,10] type:#integer
 button btn_make_morph "모핑시작"
 hyperLink hlnk_Frame "100f" color:(color 28 28 177) align:#left offset:[65,1]
 -----------------------------------------------------------------------------------
 
 -----------------------------------------------------------------------------------
 --한계치 넘어가면 색깔 변하게__
 -----------------------------------------------------------------------------------
 fn SetFrameHlink =
 (
  -- String --
  intervalFrame = spn_EndFrame.value - spn_StartFrame.value + 1
  hlnk_Frame.text = "" -- 한번 지워줘야 잔상이 생기지 않음
  hlnk_Frame.text = (intervalFrame as string) + "f"
  
  -- Color --
  if intervalFrame > 0 and intervalFrame < 101 then
   hlnk_Frame.color = color 28 28 177
  else
   hlnk_Frame.color = color 141 7 58
 )
 
 -----------------------------------------------------------------------------------
 --모핑버튼 활성화 조건--
 -----------------------------------------------------------------------------------
 fn IsValidMorpher =
 (
  startFrame = spn_startFrame.value
  endFrame = spn_endFrame.value
  
  if  startframe - endframe < 0 and abs(startFrame - EndFrame) <100 then
  (
   if SetMainObj != undefined then
    btn_make_morph.enabled =  true
   else
    btn_make_morph.enabled =  false
  )
  else
  (
   btn_make_morph.enabled =  false
  )
  
 )
 
 -----------------------------------------------------------------------------------
 --픽 버튼 누를때 
 -----------------------------------------------------------------------------------
 on pkn_MeshButton picked obj do
 (
  pkn_MeshButton.text = obj.name
  SetMainObj = obj
  
  IsValidMorpher()
  
 )
 -----------------------------------------------------------------------------------
 --시작프레임 수치는 아래 함수를 따른다
 -----------------------------------------------------------------------------------
 on spn_StartFrame changed val do
 (
  IsValidMorpher()
  SetFrameHlink()
  
 )
 -----------------------------------------------------------------------------------
 --끝프레임 수치는 아래 함수를 따른다 
 -----------------------------------------------------------------------------------
 on spn_EndFrame changed val do
 (
  IsValidMorpher()
  SetFrameHlink()
 )
 -----------------------------------------------------------------------------------
 --가장 중요한 모핑시작 버튼을 누를때의 반응설정--
 -----------------------------------------------------------------------------------
 on btn_make_morph pressed do
 (
  startFrame = spn_startFrame.value
  endFrame = spn_EndFrame.value
  
  --애니메이션 구간설정
  animationRange = interval startFrame endFrame
  
   
  targetObjs = #()  --복사될 오브젝트들을 배열로 변수 선언.  배열 번수는 복수형으로 쓰자
  objCount = 0
  
  --프레임 수 만큼 오브젝트 복사  
  for i = startFrame to endFrame do
  (
   slidertime = i
   objCount += 1
   newObj = snapshot SetMainObj
   append targetObjs newobj
   
   --복사된 오브젝트와 원본 오브젝트를 숨겨야 중간에 디버그하기가 편함
   newobj.ishidden = true
   setMainObj.ishidden = true
  )
  
  --모핑추가할 오브젝트 제어
  morpherObj = copy SetMainObj
  convertto morpherObj Editable_Poly
  addmodifier morpherObj(morpher())
  
  
  --모핑 리스트를 자동으로 갱신하기 위해서 필요한 명령어
  morpherObj.morpher.Autoload_of_targets = 1
 
   
  --모핑 오브젝트에 복사된 오브젝트 프레임순으로 등록
  for i=1 to targetObjs.count do  --모핑되는 인덱스를 반복문으로 설정하여 각 인덱스별로 오브젝트가 설정되도록 하기위한 반복문
  (
   WM3_MC_BuildFromNode morpherObj.morpher i targetObjs[i]  -- 모핑 오브젝트의 인덱스 i  그 인덱스에 들어갈 타겟 오브젝트 역시 i
  )
  
  --아래 두 명령어 없으면 실행 안됨
  max modify mode
  select morpherObj
  
  --적용된 모핑리스트들에 키 값 추가
  morpherCount = 0
  for i = startFrame to endFrame do
  (
   morpherCount += 1
   for k = -1 to 1 do
   addnewkey morpherObj.Morpher[morPherCount].controller.keys(i + k) --for문에 ()한개쯤은 생략할 수 있다.
   
    morpherObj.Morpher[morPherCount].controller.keys[2].value= 100
  )
  
  delete targetObjs
  delete SetMainObj
   
  
 )
    
   
)

createdialog g_MeshToMorph width:200 height:200

반응형
반응형
 바이패드를 박스모드로 변환시켜주는 툴입니다. 이 툴은 애니메이터들에게 필요한 툴로서 바이패드를 박스형태로

변환시켜 모델 원본을 보는데 방해를 받지 않고 애니메이션 작업을 할 수 있도록 하는 툴입니다.

 

1. 툴 화면


 

2. 전체 바이패드 전환


 

3. 선택 바이패드 전환


 

- 이 스크립트 제작을 통해 배운 내용

1. for문의 사용법 숙지(반복문)

2. 주석처리 방식 숙지

3. true와 false 수치를 글로별변수로 선언하여 제어하는 방법 숙지

4. 메크로 버튼을 만들어 나만의 메뉴를 생성하는 방식

 

코드 원문

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

-- 바이패드 박스 전환툴 : 바이패드를 박스모드로 변환해 해주는 Tool입니다.
-- 버그나 관련 내용 문의 요청 언제나 환영

-- 제작 : Taeyo

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


--박스모드와 플로터에 대한 글로벌변수 선언---------
Global BipedToBoxFloater
Global isBoxMode = true


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

---롤아웃지정------

--===========================================================================================================
rollout BipChange "바이패드 박스모드로 변환"
(

 --================================================================================== 
 -----버튼 지정----
 --================================================================================== 
 button BtnBipToBox1 "선택바이패드만전환"
 button BtnBipToBox3 "바이패드 박스모드전환"

 
 --================================================================================== 
 -----선택된 바이패드만 전환시킴-----
 --==================================================================================
 on BtnBipToBox1 pressed do
 (
  
  ----------------------------------------------------
  --SelObj선언---
  ----------------------------------------------------
  SelObj = $
  

  ----------------------------------------------------
  --선택된거 없을때---
  ----------------------------------------------------
  if selection.count == 0 then
   (
    messagebox "선택된게 없습니다."
    return 0
   )
  
  ----------------------------------------------------
  --for문을 통해 선택된 오브젝트가 무엇인지 판별----
  ----------------------------------------------------
    for SelObj in $selection do
   ( 
  
   if iskindof SelObj Biped_Object then
   (
    SelObj.boxmode = isBoxMode
   )
   else
   (
    SelObj.boxmode = isBoxMode
    messagebox "바이패드가 아닙니다."
    return 0
   )
  
   
  )
  
  ---------------------------------------------------------------------
  --isBoxMode로 선언된  글로벌변수를 통해 on/off를 지정할수 있는 함수--------------------------
  ---------------------------------------------------------------------
  if isBoxMode then
  (
   isBoxMode = false
  )
  else
  (
   isBoxMode = true
   return 0
  )
  clearselection()
 )
 
 --==================================================================================
 -------전체 씬을 뒤져서 바이패드만 골라 박스모드로 변환시켜줌------------------------
 --==================================================================================
 on BtnBipToBox3 pressed do
 (
  
  
  ----------------------------------------------------
  --for문을 통해 전체 씬의 오브젝트를 검색함--------------------------
  ----------------------------------------------------
  for obj in objects do
  (
   if iskindof obj Biped_Object then
    obj.boxmode = isBoxMode
  )
  
  ----------------------------------------------------
  --isBoxMode로 선언된  글로벌변수를 통해 on/off를 지정할수 있는 함수--------------------------
  ----------------------------------------------------  
  if isBoxMode then
  (
   isBoxMode = false
  )
   else
  (
   isBoxMode = true
   return 0
  )
   
 )
   
  
)

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

------재실행시 기존 창 지우기 위해 트라이 캐치 실행---------------------------------------------

--===========================================================================================================
try(CloseRolloutFloater BipedToBoxFloater) catch()


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

---실행창 생성--------------------------------------------

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

BipedToBoxFloater = newrolloutfloater "바이패드 박스로 변환툴" 200 130
addrollout BipChange BipedToBoxFloater

반응형
반응형

 

1.메쉬 LOD 변환툴


- LOD를 적용할 메쉬를 선택하여 수치를 정하여 메쉬를 변환시켜주는 툴입니다.

 

1. 툴 화면

 

2. 비대칭 실행시 적용화면 - 원본 오브젝트의 50퍼센트의 LOD를 적용하여 비대칭 메쉬를 새로 생성합니다.


 

 3. 대칭 실행시 적용 화면 - 원본 오브젝트의 50퍼센트의 LOD를 적용하여 대칭 메쉬를 새로 생성합니다.

 

- 이 스크립트 제작을 통해 배운 내용

1. if문의 사용법 숙지(조건문)

2. roll과 button을 사용하여 메뉴 창 생성하는 법

3. 오브젝트의 모디파이의 속성을 제어하는 방법

  

코드 원문

global TEST

rollout noskin "스킨없을때"
 
(
 spinner noskin1 "버텍스수치" range:[0,100,50] type:#integer
 button btn1 "비대칭"
 button btn2 "대칭"
 
 
 on btn1 pressed do
 (
  if selection.count != 1 then
  (
   messagebox "한개만 선택하세요"
   return 0
  )
  
  if $.modifiers[#skin] == undefined then
  
  (
   local VF = noskin1.value
   
   a= $
   copyobj = copy$
   select copyobj
   
   --modPanel.setCurrentObject $.baseObject
   modPanel.addModToSelection (MultiRes ()) ui:on
   $.modifiers[#MultiRes].reqGenerate = on
   $.modifiers[#MultiRes].vertexPercent = VF
   maxOps.CollapseNodeTo $ 1 off
   
   clearselection()
   
   delete a
   
   select copyobj
  )   
  else
  (
   messagebox "스킨없애시오"
   return 0
  )
  
 )
 ----------스킨 없고 대칭 일때-------------------
 on btn2 pressed do
 (
  if selection.count != 1 then
  (
   messagebox "한개만 선택하세요"
   return 0
  )
  
  if $.modifiers[#skin] == undefined then
  
  (
   local VF = noskin1.value
   
   
   a= $
   copyobj = copy$
      
   
   ---헬퍼박스 생성----
   Box lengthsegs:1 widthsegs:1 heightsegs:1 length:5000 width:5000 height:5000  pos:[0,0,0]  name:"Helper_Box"
   select $Helper_Box
   max rotate
   toolMode.coordsys #local
   rotate $(angleaxis -90 [0,1,0])
   move $ [-0.1,0,0]
   macros.run "Modifier Stack" "Convert_to_Poly"
   
  
   select copyobj
   
   modPanel.addModToSelection (Vol__Select ()) ui:on
   $.modifiers[#Vol__Select].level = 1
   $.modifiers[#Vol__Select].volume = 3
   $.modifiers[#Vol__Select].node = $Helper_Box
   modPanel.addModToSelection (Edit_Poly ()) ui:on
   subobjectLevel = 1
   max delete
   maxOps.CollapseNode $ off 
   modPanel.addModToSelection (MultiRes ()) ui:on
   $.modifiers[#MultiRes].reqGenerate = on
   $.modifiers[#MultiRes].vertexPercent = VF
   modPanel.addModToSelection (symmetry ()) ui:on
   $.modifiers[#Symmetry].threshold = 0
   maxOps.CollapseNode $ off
    
   clearselection()
   
   delete a 
   delete $Helper_Box
      
   select copyobj
  )   
  else
  (
   messagebox "스킨없애시오"
   return 0
  )
    
 )

)


----------------스킨있을때-------------------------------------

rollout yeskin "스킨있을때"
 
(
 spinner yeskin1 "버텍스수치" range:[0,100,50] type:#integer
 button btn3 "비대칭"
 button btn4 "대칭"
 
 on btn3 pressed do
 (
  if selection.count != 1 then
  (
   messagebox "한개만 선택하세요"
   return 0
  )
  
  if $.modifiers[#skin] != undefined then
  (
   local VF = yeskin1.value
   
   a= $
   copyobj = copy$
   select copyobj
   
   $.modifiers[#Skin].Enabled = off
   modPanel.setCurrentObject $.baseObject
   modPanel.addModToSelection (MultiRes ()) ui:on
   $.modifiers[#MultiRes].reqGenerate = on
   $.modifiers[#MultiRes].vertexPercent = VF
   maxOps.CollapseNodeTo $ 2 on
   $.modifiers[#Skin].Enabled = on
   
   clearselection()
   
   delete a
   
   select copyobj
  )  
 
  else
  (
   messagebox "스킨을 넣으세요"
  )
 
 )
  
 ------------스킨 있고 대칭 일때---------------------------------------------------------------
 on btn4 pressed do
 (
  if selection.count != 1 then
  (
   messagebox "한개만 선택하세요"
   return 0
  )
  
  if $.modifiers[#skin] != undefined then
  
  (
   local VF = yeskin1.value
   
   
   a= $
   copyobj = copy$
      
   
   ---헬퍼박스 생성----
   Box lengthsegs:1 widthsegs:1 heightsegs:1 length:5000 width:5000 height:5000  pos:[0,0,0]  name:"Helper_Box"
   select $Helper_Box
   max rotate
   toolMode.coordsys #local
   rotate $(angleaxis -90 [0,1,0])
   move $ [-0.1,0,0]
   macros.run "Modifier Stack" "Convert_to_Poly"
   
  
   select copyobj
   
   $.modifiers[#Skin].Enabled = off
   modPanel.setCurrentObject $.baseObject
   modPanel.addModToSelection (Vol__Select ()) ui:on
   $.modifiers[#Vol__Select].level = 1
   $.modifiers[#Vol__Select].volume = 3
   $.modifiers[#Vol__Select].node = $Helper_Box
   modPanel.addModToSelection (Edit_Poly ()) ui:on
   subobjectLevel = 1
   max delete
   maxOps.CollapseNodeTo $ 2 off
   modPanel.setCurrentObject $.baseObject
   modPanel.addModToSelection (MultiRes ()) ui:on
   $.modifiers[#MultiRes].reqGenerate = on
   $.modifiers[#MultiRes].vertexPercent = VF
   modPanel.addModToSelection (symmetry ()) ui:on
   $.modifiers[#Symmetry].threshold = 0
   maxOps.CollapseNodeTo $ 2 on
   $.modifiers[#Skin].Enabled = on
    
   clearselection()
   
   delete a 
   delete $Helper_Box
      
   select copyobj
  )   
  else
  (
   messagebox "스킨을 달라"
   return 0
  )
 )
  
)


TEST = newrolloutfloater "공부용 LOD시스템" 200 200

addrollout noskin TEST
addrollout yeskin TEST

 

반응형

+ Recent posts