반응형

안녕하세요 오랜만에 3DS MAX SCRIPT 포스팅을 합니다.

제가 올리는 글을 누가 보는가 싶은데.. 간혹 스크립트를 잘 봐주시는 방문객들이 계신듯 하여 포스팅을 하게 되었습니다.

오늘은 3DS MAX SCRIPT의 계층 구조에 대한 이야기 입니다. 

왠만한 개발을 해 보신 분들은 사실 약간 상식적으로 알고 계신 내용일 것 같기는 합니만 그래도 역시 누군가에게는 도움이 될 듯 하여 글을 남겨 봅니다.

 

3DS MAX Scritp 에서 어떤 오브젝트는 개발 관점에서 보면 클래스 입니다. 상위 클래스가 있고 또 하위 클래스가 있는데요. 계층 구조라고 말씀 드린것처럼 클래스 안에 또 작은 클래스가 정의 되어 있고 또 그안에 작은 클래스 또는 구조체가 정의 되어 있다고 보시면 됩니다.

 

클래스라고???

개발이 생소하신 분들은 클래스라고 하면 잘 이해가 안되시죠?

우리 인간을 예를 들어 클래스라는 개념을 설명해 보면 다음과 같습니다. (그냥 예 입니다)

각 단계는 상위 클래스의 하위 클래스가 됩니다.

  • 동물 - 호흡을 한다. 심장이 있다. 
    • 포유류 - 4개의 팔 또는 다리를 가지고 있다. 아기를 낳는다. 젖을 먹인다.
      • 영장류 - 지능이 뛰어나다. 두발 또는 네발로 걸을 수 있다. 시각 능력이 좋다
        • 인간 - 특별히 뇌가 발달했다. 다양한 언어를 구사할 수 있다. 손의 움직임이 뛰어나다
    • 조류 ... 
    • 양서류...
    • 파충류...

뭐 이런식으로 어떤 큰 개념을 정의하고 그 하위에 상위의 개념을 포함하지만 조금 세분화된 개념을 담는 그런 방식으로 한단계 한단계 세분화된 그런 개념을 담고 있는 것이 일반적인 클래스의 개념입니다. (위에 설명한 건 그냥 예를 든 것입니다. 시비 노노)

 

예를 들면 익히 잘 알고 있는 Box 는 

요런 순서의 계층 구조를 가지고 있습니다.

우린 레퍼런스 파일을 통해서 Box() 라는 클래스가 가지고 있는 다양한 프라퍼티에 접근을 할 수 있습니다.

2021.03.24 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트 레퍼런스 (헬프파일) 다운 받기

예를 들면 생성된 Box 개체의 width, Height, length 를 다음과 같이 변경할 수 있습니다.

myBox = box()
myBox.width = 25
myBox.Height = 150
myBox.Length = 50

그럼 아래와 같은 모델이 화면에 자동으로 생성되겠죠.

스크립트로 생성한 box

 스크립트에서 설정한 값이 잘 들어가 있는 것을 알 수 있습니다.

 

GeometryClass

그런데 위에 계층 구조를 보면 Box 위에 GeometryClass 라는 상위 클래스가 보이죠? 레퍼런스에서 해당 위치를 클릭해보면 GeometryClass 라는 녀석에 대한 정보가 나오는데요, 

"The mesh operations underlying the Boolean Compound Object in 3ds Max are accessible in MAXScript." 

라는 글이 해당 페이지의 첫줄에 보이고 

  • <node1> + <node2>
  • <node1>-<node2>
  • <node1>*<node2>

요런 수식들이 소개가 되어있습니다. 내용을 읽어 보면 GeometryClass 는 + - * 와 같은 연산자로 boolean 을 수행할 수 있다는 의미가 되겠습니다. Box 는 GeometryClass 이므로 당연히 Box 와 Box 는 위와 같은 boolean 연산이 된다고 볼 수 있겠습니다.

한번 해볼까요? 

myBoxA = box()
myBoxA.width = 50
myBoxA.Height = 50
myBoxA.Length = 50


myBoxB = box()
myBoxB.width = 150
myBoxB.Height = 25
myBoxB.Length = 25

myBoxB.pos.z = 12.5

요렇게 두개의 박스를 만드는 스크립트를 실행하면 

요런 형태의 두개의 박스가 생성이 됩니다.정육면체가 myBoxA, 길다란 육면체가 myBoxB가 되겠습니다.

자 그럼 myBoxA 에서 myBoxB를 빼 보도록 하겠습니다.

myBoxA = box()
myBoxA.width = 50
myBoxA.Height = 50
myBoxA.Length = 50

myBoxB = box()
myBoxB.width = 150
myBoxB.Height = 25
myBoxB.Length = 25
myBoxB.pos.z = 12.5

myBoxA - myBoxB

delete myBoxB

다른부분은 동일하고 마지막에 myBoxA 에서 myBoxB 를 빼는 수식을 추가한 다음 길다란 녀석을 삭제하는 코드를 추가하였습니다.

결과는요?

네. boolean 같은 복잡한 클래스를 사용하지 않아도 이렇게 쉽게 boolean 동작을 수행하는 군요. 

네 그럼 Box 뿐만 아니라 다른 geometryClass 의 모든 대상이 위와 같이 단순한 연산자를 이용하여 boolean 연산을 할 수 있다는 의미로 보시면 됩니다.

GeometryClass 에는 Box 외에도 Sphere 나 Cylinder, Tube 및 친근한 Teapot 같은 개체도 모두 GeometryClass 이므로 모두 동일하게 위와 같은 연산을 사용할 수 있다는 거죠.

GeometryClass 에는 아래와 같은 명령어도 지원합니다.

설명을 보면 

"Returns an array of two integers - the face count and the vertex count of the TriMesh on top of the modifier stack. "

라고 되어 있는데요, Sphere 를 하나 생성한 뒤 위의 코드를 한번 실행해 볼까요?

mySphere = Sphere()
GetTriMeshFaceCount mySphere

요렇게 작성한 뒤 실행해 보면 

$Sphere:Sphere002 @ [0.000000,0.000000,0.000000]
#(224, 114)

요런 결과가 리턴 됩니다. 첫째 줄은 생성된 sphere 에 대한 정보이고요, 두번째가 바로 작성한 코드의 결과물인데요. 위의 설명에 따르면 face 개수와 vertex 개수를 돌려 준다고 합니다. 생성된 sphere 는 224개의 face 와 114개의 vertex 로 이루어져 있다는 것을 알 수 있습니다. 다시 말하자면 우리는 생성한 geometryclass 가 뭐든간에 해당 개체의 폴리곤수를 바로 알 수 있게 되는 겁니다. mesh 나 poly 같은 개체의 geometry 속성 정보를 알기 위하여 class 구분을 하고 getNumfaces 나 polyop.getNumVertexs 를 사용하는 것처럼 개체의 클래스나 구성 방식 등을 검사를 할 필요가 없는거죠.

 

Node

자 그럼 한칸 더 상위로 올라가서 Node 를 볼까요?

Node 는 3DS MAX Script 에서 아주 중요한 개념으로 해당 클래스에서 사용할 수 있는 프라퍼티나 메소드가 아주 많습니다. 스크립팅의 아주 기본적인 부분도 많이 보이네요.

아주 간단한 예를 들면 우리가 scene 에서 보여지는 모든 개체는 node 라는 클래스라고 보면 됩니다. EditableMesh 건 EditablePoly 건 Camera 건 심지어 helper 나 dummy 같은 개체도 모두 node의 하위 클래스 입니다.

즉 Node 라는 개체에 대한 설명이 적혀있는 레퍼런스 페이지에 있는 모든 하위요소를 사용할 수 있습니다.

 제가 아~~주 자주 사용하는 node 의 대표적인 프라퍼티 또는 메소드를 보면 아래와 같습니다.

  • IsValidNode <var>
  • move <node> <point3> -- mapped
  • scale <node> <point3> -- mapped
  • rotate <node> <eulerangles> -- mapped
  • copy <node> -- mapped
  • reference <node> -- mapped
  • instance <node> -- mapped
  • delete <node> -- mapped
  • classOf <node>

딱 봐도 어떤 일을 하는지 아시겠죠? 우리가 알고있는 대부분의 요소는 node 이며 위와 같은 명령어를 이용하여 컨트롤 할 수 있답니다. 복사하고 이동하고, 회전하고 삭제하고, 해당 개체가 어떤 클래스인지 확인하는 그런 것들이죠.

Node Common Methods

 

라는 항목을 보면 Node 에서 사용할 수 있는 더 많은 상세한 레퍼런스들을 확인할 수 있습니다.

Node 클리스의 상세한 레퍼런스 들

이렇게 말이죠.

물론 Node 자신의 subClass 에는 GeometryClass, Shape, Light, Camera, Helper, SpacewarpObject, System 이러한 요소들이 있고 각기 자신에 해당하는 프라펕와 메소드들을 다룰 수 있지만 역시 node 에서 정의하고 있는 모든 프라퍼티와 메소드를 사용할 수 있는 것 입니다.

 

드디어 최상위 클래스 : Value

그럼 최상위 Value 라는 개체로 가 볼까요?

Value 개체는 3DS MAX 에서 정의하고 있는 class 의 최상위 개체입니다. 말하자면 모든 구조체, 클래스 등은 Value 에 속하므로 Value 에서 정의하고 있는 기능을 수행할 수 있는 것이라 할 수 있겠습니다.

최상위인 value 에는 대표적으로 다음과 같은 항목들이 정의되어 있습니다.

  • <value> == <value>
  • <value> != <value>

익히 잘 알고 있는 bool 연산자죠? if 구분 같은 곳에서 대상과 대상이 같은지 다른지 판단할 수 있고요. 

  • print <value>
  • format <format_string>

와 같은 코드를 통해서 해당 정보를 출력해 볼 수 도 있습니다. 

Working with Values

라는 레퍼런스 페이지에 보면 스크립팅을 하는 동안 Value 를 어떻게 다룰 수 있는지 잘 소개가 되어있습니다.

스크립트는 다른 개발 언어와 다르게 빠르게 작성하고 빠르게 컴파일, 실행을 할 수 있기 때문에 이런 구조체를 알면 디버깅도 빠르고 작성도 손쉽게 할 수 있겠습니다.

Value 에는 node 와 같은 scene 내의 개체 뿐만 아니라 Float ,Integer ,String ,BitArray ,Point3 ,Ray ,Quat ,AngAxis ,EulerAngles ,Matrix3 ,Point2 ,Color ,Arrays 와 같은 클래스나 구조체들도 포함되어 있습니다. Ray 에 대해서 지난 포스팅에 소개해 드렸었죠?

2022.05.31 - [DEV/MAX SCRIPT] - [3ds max script] ray 에 대하여 알아보기

 

[3ds max script] ray 에 대하여 알아보기

가끔 아니 어쩌면 자주 3D 공간안에서 물체의 위치를 지정할때 이 물체가 저쪽에 닿는 면에 딱 위치하고 싶은데... 할때가 있죠? 예를 들면 나무나 돌덩이 이런걸 랜덤하게 막 생성한 다음 굴곡진

diy-dev-design.tistory.com

사실 Value 는 정말 아~~주 아주 기본적인 속성들을 다루고 있다고 보시면 되고 해당 정보들 없이는 스크립팅이 불가능한 정말 개념이 없어도 늘 사용하는 그런 애들이라고 보시면 됩니다.

 

 

마치며

자 오늘 포스팅은 사실 개념적인 부분이어서 조금 어려울 수도 있을 것 같습니다.

하지만 스크립팅을 하다보면 저처럼 자연스럽게 알게 되기도 하고요. 또 이런 개념을 이해하고 스크립팅을 하면 훨씬 쉽고 유연하게 코딩을 하실 수 있을 거에요. 

저 처럼 무작정 코딩을 하며 배워가는 경우에도 "아~~~ 이게 이런거였어?!?!?" 이런 적이 셀 수 없이 많았거든요. 

 

자 다시 정리하자면 

  • 상위 클래스에서 정의되어 있는 프라퍼티나 메소드는 하위 클래스에서도 접근 할 수 있다.
  • 즉 name, rotate, move, delete, copy 같은 개념은 하위의 어떤 클래스에서도 사용할 수 있다.
  • 지금 보고 있는 개체의 상위 클래스가 무었인지 확인해 보자.

 

자 다들 화이팅하시고 스크립팅을 통해 에이스의 진면모를 보여주시기를 바라며 오늘의 포스팅을 마칩니다.

 

2021.02.26 - [DEV/MAX SCRIPT] - [3ds max script] vector 에 대하여

 

[3ds max script] vector 에 대하여

안녕하세요. 오늘은 디자이너라면 조금 생소할 수 있는 vector 라는 개념에 대하여 소개해 드릴까 합니다. 혹시 작년 쯤인가요? 슈퍼밴드라는 밴드 오디션 프로그램에서 F=ma 라는 곡으로 아주 인

diy-dev-design.tistory.com

2021.02.24 - [DEV/MAX SCRIPT] - 3da max script 점과 점 사이의 거리 구하기

 

3da max script 점과 점 사이의 거리 구하기

간단하게 포스팅을 남기려고 합니다. 제목 그대로 버텍스 간 거리 구하기 입니다. 아니 정확히는 두개의 point3 사이의 거리를 구하는 방법을 소개해 드릴까 합니다. 그리고 용용 편으로 두 점사

diy-dev-design.tistory.com

 

반응형
반응형

가끔 아니 어쩌면 자주 3D 공간안에서 물체의 위치를 지정할때 이 물체가 저쪽에 닿는 면에 딱 위치하고 싶은데... 할때가 있죠? 

예를 들면 나무나 돌덩이 이런걸 랜덤하게 막 생성한 다음 굴곡진 지형에 모두 딱 안착시키고 싶다거나요.

또는 어떤 물체를 기준으로 어떤 방향으로 뻗어 나갈때 무엇인가 닿는 물체가 있는지 검사하고 싶을때도 있지요.

이때 사용되는 개체가 바로 Ray 입니다.

실제로 Ray를 알기 전과 알고난 뒤는 정말 다른 세계라고 할수 있겠습니다.

 

자 오늘은 Ray 에 대하여 알아보도록 하겠습니다.

3D 는 정말 놀라울 정도로 기하학적인 수학의 결정체라 할 수 있겠습니다. 이를 구현하기 위하여 정말 얼마만큼의 수학적 노력이 있었는지 상상이 안될 정도 입니다.

오늘은 그 결정체중의 하나인 Ray에 대하여 알아볼텐데요. 3DS MAX 에서 Ray 는 두가지 명령어를 통해 사용됩니다.

intersectRay 와 intersectRayEx, intersectRayScene 이렇게 세가지 입니다. 사용하는 목적에 따라 구분하여 사용하시면 되는데요. 각각은 아래와 같습니다.

  • intersectRay : Ray 와 대상물체를 지정한 뒤 부딧히는 위치를 알아낸다.
  • intersectRayEx : 위와 동일하며 부딪힌 Face 정보와 부딪힌 면의 normal 정보를 돌려준다
  • intersectRayScene : 대상 개체를 지정하지 않고 Scene 내의 어떤 물체든 부딪힌 정보를 돌려준다. (느림)

사용하는 방법은 간단한데요, 먼저 Ray 를 생성해주고 필요하면 Ray의 출발 위치(pos)와 방향(dir)을 변경할 수 있습니다.

myRay = ray [0,0,0] [0,0,-1]

ray 를 생성하는 구문 인데요, [0,0,0] 위치를 출발점으로 하고 [0,0,-1] 을 방향으로 하는 ray 가 만들어 지게 됩니다. [0,0,-1] 이라 하면 z 축을 기준으로 아래쪽을 바라보는 방향이라고 보면 되겠죠? 

 

이렇게 만들어진 Ray를 위의 명령어와 함께 사용해볼까요?

임시로 테스트용 Scene 을 만들어 봄

먼저 위와 같은 Scene 을 만들어서 테스트 해보려 합니다. 노란색 공이 지면에 부딪히는 위치로 이동 시킬거에요. 중간에 네모 박스가 있지만 네모박스는 무시하고 지면에 위치시켜야 한다면 아래와 같이 intersectray 를 이용하여 위치시킬 수 있습니다.

-- ray 를 생성해 준다
myRay = ray [0,0,0] [0,0,-1]

-- 이동시킬 물체를 지정하자
obj = $Sphere001

-- ray 의 출발 위치를 물체의 중심으로 설정해보자
myRay.pos = obj.pos

-- 위치 검출에 사용될 지형을 지정해보자
tern = $terrain_01

-- intersectray 를 이용하여 지형과 부딪히는 위치를 찾아내자
interResult = intersectray tern myRay

-- 어떤 결과가 나왔는지 print 를 이용해서 살펴보자
print(interResult)

-- 부딪힌 위치에 오브젝트를 위치시키자
obj.pos = interResult.pos

요렇게 하면 어떻게 되냐면요

지면에 정확하게 안착함

요렇게 노란 공이 지면에 달라 붙게 됩니다. 코드에 주석을 달아 놓았으니 따로 설명은 안드려도 될 것 같은데요. 한가지만 설명해 드리자면 intersectray의 결과값을 보면 (ray [-1.62331,11.1008,1.22501] [-0.407511,-0.107746,0.906822]) 요런 식으로 ray 의 형식으로 결과가 나옵니다. ray 는 pos 와 dir 의 속성이 있지 않습니까?? 여기서 결과값의 pos 정보가 바로 부딧힌 면의 위치 정보가 됩니다. 그 뒤에 나오는 [-0.407511,-0.107746,0.906822] 는 부딪힌 면의 normal 값으로 만약 공이 부딪힌 다음 튕겨나간다거나 하는 다음 동작이 필요하다면 반드시 필요한 정보이지요.

어쨌든 intersectray 만 보자면 부딪힌 위치와 각도를 ray 의 형태로 돌려준다는 것을 알 수 있었습니다. 특징이라 하면 , 특정 개체를 대상으로 하기 때문에 속도가 매우 빠릅니다. 사실상 성능을 고려하지 않아도 되는 함수죠.

그런데 만약 부딪힌 면이 어디인지 알아야 하고 부딪힌 개체에도 뭔가 추가적인 액션이 필요할 수 있겠습니다. 사람일은 모르는거자나요? 누군가는 저 지형개체에 어떤 face에 물체가 부딪혔는지를 알아야 할수도 있지 않겠습니까? 이 때 intersectrayex 라는 함수를 이용하게 됩니다.

이번에는 intersectray 대신에 intersectrayex 를 사용해 볼 겁니다. 사용방법은 동일하고요. intersectrayEx [node] [ray] 와 같이 사용해 주면 됩니다.

-- intersectray 를 이용하여 지형과 부딪히는 위치를 찾아내자
interResult = intersectrayex tern myRay

-- 어떤 결과가 나왔는지 print 를 이용해서 살펴보자
print(interResult)

-- 결과는? 
#((ray [-1.62331,11.1008,1.22501] [-0.382998,-0.128105,0.914823]), 240, [0.383149,0.282177,0.334673])

아까와는 결과가 조금 다르죠? #(oo,oo,oo) 형태로 나온걸 보면 배열로 결과가 나온걸 알 수 있습니다. 총 3개의 리턴값이 나왔는데요.

  • (ray [-1.62331,11.1008,1.22501] [-0.382998,-0.128105,0.914823])
  • 240
  • [0.383149,0.282177,0.334673]

intersectray 와 마찬가지로 첫번째 결과에는 부딪힌 면의 위치, 방향을 담는 ray 정보가, 두번째에는 어떤 숫자가 나왔고요, 세번째에는 point3 형식으로 좌표가 나왔는데, 딱보니 위에 ray 에 부딪힌 면의 방향이라는 것을 알 수 있겠습니다. 두번째 숫자는 뭐냐고요?

부딪힌 face 의 index 임을 알 수 있다.

바로 부딪힌 mesh 의 face 인덱스 입니다. 240 번이죠? 바로 저부분에 부딪힌 것 입니다. (이번에는 이동은 하지 않았기 때문에..) 만약 동일하게 이동해야 한다면 배열 안의 개체에서 위치 정보를 뽑아내야 하므로 interResult[1].pos 와 같은 방법으로 부딪힌 면의 위치를 가져오면 됩니다.

이런 기능을 이용해서 부딪힌 면의 색상을 바꾸어 준다거나 해당 face를 삭제하는 등의 기능을 넣을 수 있겠지요? 뭐 레이저총에 맞은 face 가 폭파되며 사라지는 등의...  네.. 그럴때 꼭 필요한 훌륭한 명령어 입니다.

참고로 intersectray 나 intersectrayex 는 mesh 오브젝트에서 정확한 정보를 받아 올 수 있습니다. 가끔 기본 primatine 에 modifier 로 edit_poly 같은것을 씌운 경우에는 동작하지 않을 수 있으니 만약 결과값이 undefined 와 같은 값이 나온다면 검출에 사용된 모델링을 mesh 로 변경한 뒤 (convertTomesh obj) 검사를 진행하시면 됩니다.

 

끝으로 intersectRayScene 은 위와는 다르게 Ray 가 어떤 개체에 부딪히는지 알수 없을 때 사용합니다.

모두 동일하고 해당 명령만 intersectRayScene 으로 변경해서 돌려볼까요?

interResult = intersectrayScene myRay

요렇게 말이죠. 이번에는 대상을 특정하지 않기 때문에 함수 뒤에 인자가 ray 개체 하나만 들어갔습니다. 

결과를 볼까요? 

#(#($Editable_Mesh:terrain_01 @ [-4.616531,-2.612816,0.000000], (ray [-1.62331,11.1008,1.22501] [-0.382998,-0.128105,0.914823])), #($Sphere:Sphere001 @ [-1.623309,11.100846,65.260162], (ray [-1.62331,11.1008,61.9389] [0,0,-1])), #($Box:Box001 @ [15.646946,18.567043,19.666662], (ray [-1.62331,11.1008,26.4499] [0,0,1])))

뭔가 무시무시하게 길게 나왔죠?

이녀석도 역시 배열 개체이므로 하나씩 보면 

#($Editable_Mesh:terrain_01 @ [-4.616531,-2.612816,0.000000], (ray [-1.62331,11.1008,1.22501] [-0.382998,-0.128105,0.914823]))
#($Sphere:Sphere001 @ [-1.623309,11.100846,65.260162], (ray [-1.62331,11.1008,61.9389] [0,0,-1]))
#($Box:Box001 @ [15.646946,18.567043,19.666662], (ray [-1.62331,11.1008,26.4499] [0,0,1]))

요렇게 3개의 개체와 부딪혔다는 정보를 돌려준 것을 알 수 있습니다. 심지어는 본인(sphere) 에도 부딪힌 정보를 돌려 받았다는 것을 알 수 있네요 ㄷㄷㄷ. (저걸 원한건 아닌데) 부딪힌 정보를 보면 역시 내부 정보 역시 배열인데요, 첫번째는 부딪힌 대상 개체, 두번째는 부딪힌 위치정보 (ray 속성) 라는걸 알 수 있습니다.

만약 개체에 어떤 특정할만한 속성이 있다면 해당 개체에 물체를 위치 시킬 수 있습니다.

-- ray 를 생성해 준다
myRay = ray [0,0,0] [0,0,-1]

-- 이동시킬 물체를 지정하자
obj = $Sphere001

-- ray 의 출발 위치를 물체의 중심으로 설정해보자
myRay.pos = obj.pos

-- 위치 검출에 사용될 지형을 지정해보자
tern = $terrain_01

-- intersectray 를 이용하여 지형과 부딪히는 위치를 찾아내자
interResult = intersectrayScene myRay

-- 어떤 결과가 나왔는지 print 를 이용해서 살펴보자
print(interResult)

for i = 1 to interResult.count do
(
	testObj = interResult[i][1]
	if (findString testObj.name "Box") != undefined then
	(
		obj.pos = interResult[i][2].pos
	)
)

요렇게요. 

코드에서는 Box 라는 이름을 포함하는 개체를 만나면 해당 개체에 위치하도록 하는 코드 입니다.

이게 사실 한두개일 때는 간단한 이야기 인데 지면에 위치 시켜야 하는 개체가 수십개 ~ 수백개가 되면 일이 커집니다. 그럴때는 스크립트가 필요한 시점인거죠.

예를 들면 이렇게요..

이 많은 공들을 지면에 붙이라고?

 

모두 sphere 라는 이름을 갖고 있기때문에 간단하게 처리할 수 있겠네요. 지면에 닿는 개체는 지면에 닿도록 하고 box 에 닿는 개체는 box 에 위치시키도록 하겠습니다. 

sphere 의 중심을 기준으로 하다보니 약간 파뭍히는 대상이 있었는데요, sphere 의 반지름 만큼 위쪽으로 위치하도록 코드를 짜 보겠습니다.

-- ray 를 생성해 준다
myRay = ray [0,0,0] [0,0,-1]

-- 이름이 sphere 로 시작되는 모든 개체를 변수 objs 에 담자.
objs = execute("$Sphere*")

for obj in objs do
(
	-- 각 sphere 의 중심점으로 ray 의 위치를 지정함
	myRay.pos = obj.pos
	
	-- intersectray 를 이용하여 지형과 부딪히는 위치를 찾아내자
	interResult = intersectrayScene myRay


	for i = 1 to interResult.count do
	(
		testObj = interResult[i][1]
		if (findString testObj.name "Box") != undefined then
		(
			obj.pos = interResult[i][2].pos
			-- 파묻히지 않도록 반지름 만큼 위로 올림
			obj.pos.z += obj.radius
		)
		else if (findString testObj.name "terrain") != undefined then
		(
			--- 부딪힌 정보가 terrain 일때 해당 위치로 이동 시킴 
			obj.pos = interResult[i][2].pos
		-- 파묻히지 않도록 반지름 만큼 위로 올림
			obj.pos.z += obj.radius
		)
	)
)

 

뭐 별거 없죠? 위에서 설명한 것을 반복문만 추가했을 뿐 입니다.

결과는요?

한번에 모두 지면에 안착 성공

요렇게 예쁘게 안착된 것을 확인 할 수 있습니다.

물론 저는 본 기능을 설명 드리기 위해 위와 같은 예제를 들었지만요. 실제 제가 사용하는 함수에는 몇초만에 수천번 이상 위치를 검출하며 ray 가 사용되는 케이스가 허다분 합니다.

저는 주로 자동으로 모델링을 할때 모델링의 위치, 크기, 배치, 부딪힘, 확장 범위 등을 검사할때 사용하는데요, 이런 검사들을 통해 사람이 손을 데지 않고도 아주 정교한 모델링을 할 수 있는 근간이 됩니다.

참고로 intersectRayScene 의 경우 scene 의 모든 개체에 대하여 검사가 이루어지기 때문에 Scene 내에 아주 많은(수만개 이상의) node 들이 자리잡고 있는 경우에는 속도가 매우 느려질 수 있습니다. 그래서 시작 위치를 기준으로 반경내에 들어오는 대상을 먼저 골라낸 다음 속도가 빠른 intersectRay 를 이용하여 각각 부딪힌 위치를 검출하는 방식으로 사용하고 있습니다. 프로그래밍이라는게 그렇자나요. ㅎ 높은 성능과 효율성을 위해 다양하고 창의적인 방법으로 접근해 가는게 바로 프로그래밍의 묘미이지요.

오늘은 이만 마칩니다. 내용이 길어기니 힘드네요 ㅋ

2021.03.24 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트 레퍼런스 (헬프파일) 다운 받기

 

3DS MAX 스크립트 레퍼런스 (헬프파일) 다운 받기

스크립트 초급자든 중급자든 반드시 필요한 것 하나를 꼽으라면 저는 레퍼런스라고 생각합니다. 기존에는 3DS MAX 설치 시에 함께 설치되어 스크립트 작성 창에서 F1 키를 누르면 chm 파일 형식의

diy-dev-design.tistory.com

2021.02.24 - [DEV/MAX SCRIPT] - 3da max script 점과 점 사이의 거리 구하기

 

3da max script 점과 점 사이의 거리 구하기

간단하게 포스팅을 남기려고 합니다. 제목 그대로 버텍스 간 거리 구하기 입니다. 아니 정확히는 두개의 point3 사이의 거리를 구하는 방법을 소개해 드릴까 합니다. 그리고 용용 편으로 두 점사

diy-dev-design.tistory.com

2020.04.29 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 개체 선택하기

 

3DS MAX 스크립트로 개체 선택하기

Max Script 를 이용하여 무엇인가를 하려면 필수 요소라고 할 수 있는 것 중의 하나가 개체를 선택하거나 지정하는 방법입니다. 여기서 개체는 3D Scene 안의 오브젝트, 스플라인, 헬퍼 등과 같은 사

diy-dev-design.tistory.com

 

반응형
반응형

스크립트 초급자든 중급자든 반드시 필요한 것 하나를 꼽으라면 저는 레퍼런스라고 생각합니다. 기존에는 3DS MAX 설치 시에 함께 설치되어 스크립트 작성 창에서 F1 키를 누르면 chm 파일 형식의 레퍼런스 파일이 나타나 간편하게 사용을 했는데요. 언제부터인가 온라인 레퍼런스 사이트로 연결이 되기 시작했습니다.

내용상 큰 차이가 없더라도 매번 인터넷 페이지 안에서 검색하고 찾는 것보다 로컬에 저장되어 있는 chm 파일에서 찾고 검색하는 것이 훨씬 빠르고 쉽기 때문에 전느 chm 포멧의 레퍼런스를 선호하는 편입니다.

사실 autodesk 사이트에도 chm 파일을 배포하고 있는데 굳이 온라인 페이지로 연결 시켰는지 잘 이해가 가지 않는 부분입니다.

 

아래 경로에가시면 chm 형식으로 제작된 최신 레퍼런스 파일을 받으실 수 있으니 참고하시기 바랍니다.

www.autodesk.com/developer-network/platform-technologies/me-sdk-docs-2021

 

Media and Entertainment SDK Docs 2021 | Autodesk Developer Network

The Autodesk Media and Entertainment SDK page offers access to the latest documentation for the 2021 releases of the Autodesk Media & Entertainment SDKs. Use the links below to view the documentation in your browser, or to download the documentation to you

www.autodesk.com

위 페이지에 가셔서 아래 표시해 놓은 링크를 클릭하시면 로컬에 저장해 놓고 사용하실 수 있습니다.

빨간 박스 부분을 클릭하면 다운로드가 가능하다.

 

혹 해당 링크가 깨지는 경우를 대비하여 압축파일로도 업로드 해놓도록 하겠으니 아래 압축파일을 풀어 사용하시면 되겠습니다. 파일 4개를 모두 내려받으신 후 001 번을 압축해제 하시면 됩니다.

3dsmax-2021.1-maxscript-help-chm.zip.001
9.00MB
3dsmax-2021.1-maxscript-help-chm.zip.002
9.00MB
3dsmax-2021.1-maxscript-help-chm.zip.003
9.00MB
3dsmax-2021.1-maxscript-help-chm.zip.004
1.37MB

 

chm 파일은 파일 하나로 완전한 레퍼런스 북 입니다. 웹페이지에 비하여 색인도 훨씬 잘 되어 있고 로딩 시간도 필요치 않으며 오프라인 환경에서도 완벽하게 동작하는 훌륭한 녀석이라 할 수 있습니다.

스크립트 개발에 도움이 되시길 바랍니다.

 

감사합니다. 그럼 이만~

 

2021.03.03 - [DEV/MAX SCRIPT] - [3DS MAXscript] 스크립트 에디터 한글이 ??? 로 나오는 문제 해결 방법

 

[3DS MAXscript] 스크립트 에디터 한글이 ??? 로 나오는 문제 해결 방법

3DS MAX script 는 정말 훌륭한 개발 언어이지만 아쉬운점이 없는 것은 아닙니다. 대표적인 예가 바로 한글지원 문제인데요. 개발 코드 상에 한글이 지원되는건 바라지도 않습니다. 적어도 주석이라

diy-dev-design.tistory.com

2019.12.16 - [DEV/MAX SCRIPT] - 3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

 

3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

개발이라 하면 두드러기가 나는 디자이너 들이 있습니다. 아니 대부분 그렇죠. 이글을 읽고 계신 본인도 그러하다면, 그런데 스크립트로 무언가를 하고 싶다면 어쩌겠습니까.. 배워야지요. 그래

diy-dev-design.tistory.com

2019.06.12 - [DEV/Adobe Script] - 포토샵 스크립트 레퍼런스, 도움말 사용하기

 

포토샵 스크립트 레퍼런스, 도움말 사용하기

포토샵 스크립트 역시 다른 개발언어와 마찬가지로 도움말이 있습니다. 레퍼런스라고 해야할까요. 사실 개발자라고 해도 모든 명령어와 프라퍼티, 메소드를 외우고 있을 수는 없기 때문에 잘

diy-dev-design.tistory.com

 

반응형
반응형

3DS MAX script 는 정말 훌륭한 개발 언어이지만 아쉬운점이 없는 것은 아닙니다. 대표적인 예가 바로 한글지원 문제인데요. 개발 코드 상에 한글이 지원되는건 바라지도 않습니다. 적어도 주석이라도 한글이 되면 좋은데 막상 작성할때는 작성이 되지만 저장하고 다시 열어보면 한글로 된 문자는 모두 ??? 로 표시되는 문제가 있습니다.

오늘 포스트에서는 주석으로 남긴 한글 문자열이 ??? 로 나타나는 경우 해결 방법을 알려드리려고 합니다.

 

먼저 3DS MAX 를 실행하신 뒤 상단 메뉴에서 

Scripting > Max Script Editer 를 열어 줍니다.

그러면 아래와 같이 뭔가 잔뜩 작성되어 있는 설정 파일이 열리게 됩니다.

 

여기서 code.page 를 검색하신 후 아래와 같이 작성합니다.

code.page=949

이렇게 하고 저장하신 뒤 3DS Max 를 재실행 하시면 주석이 한글로 잘 보이는 것을 확인하실 수 있습니다.

물론 이렇게 해도 코드 상의 한글은 인식하지 못하니 참고바랍니다.

 

감사합니다.

 

2021/02/24 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트, 프라퍼티 와 매소드 이해하기

 

3DS MAX 스크립트, 프라퍼티 와 매소드 이해하기

오늘은 3DS MAX script 를 개발하면서 이해하면 도움이 될 용어 두가지를 설명 드릴까 합니다. 바로 property 와 method 입니다. 프라퍼티와 매소드 정도로 발음하시면 됩니다. 도대체 이게 뭐고 왜 이런

diy-dev-design.tistory.com

2021/02/26 - [분류 전체보기] - [3ds max script] vector 에 대하여

2019/12/16 - [DEV/MAX SCRIPT] - 3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

 

3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

개발이라 하면 두드러기가 나는 디자이너 들이 있습니다. 아니 대부분 그렇죠. 이글을 읽고 계신 본인도 그러하다면, 그런데 스크립트로 무언가를 하고 싶다면 어쩌겠습니까.. 배워야지요. 그래

diy-dev-design.tistory.com

 

반응형
반응형

안녕하세요. 오늘은 디자이너라면 조금 생소할 수 있는 vector 라는 개념에 대하여 소개해 드릴까 합니다.

혹시 작년 쯤인가요? 슈퍼밴드라는 밴드 오디션 프로그램에서 F=ma 라는 곡으로 아주 인기를 끌었던 적이 있습니다. 이식은 노래 가사에도 나오듯이 F (힘) = mass (질량) * accelation (가속도) 라고 정의를 하고 있습니다. 즉 힘이라는 개념은 단순한 한가지 속성이 아닌 두가지 속성이 합쳐져서 만들어진 개념인 것이죠.

오늘 소개해 드릴 vector (벡터) 가 바로 그러 합니다. vector 는 딱히 우리말로 번역된 문구가 있는지 모르겠지만 그냥 vector 로 이해하시는 것이 빠를 것 같습니다.

먼저 벡터를 간단하게 정의하자면

Vector = Direction (방향) * length (거리) 

라고 할 수 있습니다.

벡터의 정의

 

만약 [0,10,10] 이라는 벡터가 있다면 방향은 [0.0,1.0,1.0] 거리는 10 인 벡터라는 것이죠.

방향을 나타내는 point3 좌표의 x, y, z 값에 length 인 10을 각각 곱해주면 [0,10,10] 이라는 벡터가 만들어 지는것이죠.

여기서 길이의 속성을 뺀 순수한 방향을 normal vector 라고 합니다. x, y, z 의 값이 1.0이 넘지 않도록 정규화한 값인데요. 벡터를 이용할때 매우 자주 사용되는 개념이므로 잘 이해하셔야 합니다.

 

먼저 벡터의 표현을 볼까요?

3DS MAX script 에서는 [ x , y , z ] 와 같은 point3 좌표와 동일한 형태로 표현합니다.

max script 에서 point3는 점의 좌표이기도 하지만 [ 0 , 0 , 0 ] 으로 부터의 방향과 거리가 담긴 벡터이기도 한것이죠.

두 점 사이의 벡터를 구하는 방법은 아래와 같습니다. 점 A 로부터 점 B 까지의 벡터는 아래와 같습니다.

vector = pointB - pointA

벡터의 표현

어떤 점 P1 로부터 어떤 점 P2 까지의 벡터가 있다고 했을때 그 방향으로 지정한 거리만큼 이동된 제 3의 좌표를 구하려면 normal vector 가 필요합니다. max script 에서는 nomalize 라는 명령어로 vector 에서 방향 성분만 추출된 normal vector 를 얻을 수 있습니다.

먼저 두 점을 이용하여 vector 를 구하는 방법은 위에서 소개한 바와 같이 아래와 같이 스크립트로 표현됩니다. 

vec_p1p2 = p2 - p1

vec_p1p2 = p2 - p1

간단하죠? 도착점의 좌표에서 시작점의 좌표를 빼주면 됩니다. 

그리고 normal vector 를 구하는 방법은 아래와 같습니다.

normalVec_p1p2 = normalize(vec_p1p2))

 

요렇게 하면 normalVec_p1p2 라는 변수에 구해진 벡터의 노멀라이징된(정규화된) 벡터를 얻을 수 있습니다.

 

우리가 이제 방향을 알았다면 해당 방향으로 이동된 어떤 거리의 점의 위치를 얻을 수 있습니다.

구하는 방법은 아래와 같습니다.

최종 위치 = 시작위치 + (방향 * 거리)

벡터를 이용한 점의 위치 계산 방법

그림으로 보면 이런식입니다.

위에서 사용했던 스크립트를 이용해보면 

distance = 100

vec_p1p2 = p2 - p1

normalVec_p1p2 = normalize(vec_p1p2))

resultPos = p1 + (normalVec_p1p2 * distance )

이렇게 되겠죠.

Distance 가 - 가 되면 반대 방향으로 이동을 하게 됩니다.

Distance 를 p1 과 p2 사이의 거리를 구한다음 절반에 해당하는 거리를 부여하면 두 점사이의 중간에 해당하는 지점의 위치를 구할 수 있습니다. 

2021/02/24 - [DEV/MAX SCRIPT] - 3da max script 점과 점 사이의 거리 구하기

 

3da max script 점과 점 사이의 거리 구하기

간단하게 포스팅을 남기려고 합니다. 제목 그대로 버텍스 간 거리 구하기 입니다. 아니 정확히는 두개의 point3 사이의 거리를 구하는 방법을 소개해 드릴까 합니다. 그리고 용용 편으로 두 점사

diy-dev-design.tistory.com

이런식으로 두점 사이를 일정 간격으로 등분 할때도 사용할수 있고요. 

물체의 거리, 방향들을 바꾸어 주면서 연속해서 변화를 줄 경우 간단하게 2D 자동차 게임 같은 것을 만드는게 가능한거죠. 가속 페달 버튼을 누르면 매 프레임 당 이동하는 거리를 바꾸어 주면 되고 좌우 핸들 방향을 조절하면 normal vector 의 방향을 바꾸어 주면 됩니다.

방향과 길이를 조정하면서 이동된 점의 위치

이해 되시나요? 

 

사실 공간상의 이동 및 좌표 계산에 vector 는 빠질 수 없는 개념입니다.

 

 

 

예를 들어 세 점의 각도를 구해봅시다. 2D 좌표 안에서 각도를 구하는 것은 중학교 수학 정도를 잘 배웠다면 직접 계산 하는 것도 가능하긴 합니다. 그럼 3D 에서는요? 그냥 생각해도 쉽지 않겠죠 ?

그래서 max script 간단하게 세점의 각도를 구하는 방법을 소개해 드릴까 합니다.

p1
p2 -- 축이 되는 점
p3

vec01 = normalize ( p2 - p1 )
vec02 = normalize ( p2 - p3 )

angle = acos( dot (vec01, vec02))

이렇게 하면 간단하게 angle 을 구할 수 있습니다.

수많은 점을 가지고 있는 곡선 (폴리라인)의 점을 minimalize (단순화) 할 경우에도 연속된 세점의 각도를 측정하고 지정한 각도 미만일 경우 점을 삭제 하여 단순화 하는 기능에 적용할 수 있으며 지면으로 부터의 현재 벡터의 각도 등을 측저한다든가 하는 여러가지 응용을 할 수 있습니다.

 

벡터를 알면 어떤 직선에 수직이 되는 방향도 쉽게 구할 수 있습니다.

vecA = normalize ( p2 - p1 )

vecA1 = [ vecA.y , - vecA.x , vecA.z ]

--또는 

vecA2 = [ - vecA.y , vecA.x , vecA.z ]

와 같이 하면 vecA1 과 vecA2 는 vecA 의 수직이 되는 벡터가 되는데요 vecA1 과 vecA2 에 - 가 붙은 위치가 다른데 각각 기준이 되는 벡터의 오른쪽 과 왼쪽 벡터가 됩니다.

이는 직선의 방정식을 생각해보면 단순한 원리임을 알수 있습니다.

직선에 수직 성분을 갖는 다른 직선 --> 수직 벡터로 응용할 수 있다

어떤 직선을 기준으로 양쪽으로 확장되는 두께 등을 다이나믹하게 설정해야 하는 경우, 예를 들면 라인을 폴리곤으로 변경할 때 유용하게 사용될 수 있습니다.

기준이 되는 벡터의 양쪽으로 확장할 때 사용 가능

 

벡터를 응용함에 있어 중요한

벡터의 합

벡터의 합

 

응용을 해보면 직선상의 3점을 이용하여 어떤 점이 중간에 있는 점인지 알아내는 것에도 vector 연산을 이용하면 쉽게 할 수 있습니다.

점 A, B, C 가 있다고 했을 때 선분 AB, AC 또는 선분 BA, BC 등을 구해서 노멀 벡터를 구한 뒤 두개의 노멀 벡터를 더했을 때 [0,0,0] 이 나오면 해당 점이 중간에 있는 점인 것이죠. 

 

이상으로 간단하게 3DS Max 에서 사용되는 벡터의 개념에 대하여 알아 보았습니다. 

추가가 필요하다고 판단되는 내용이 생각나면 업데이트 하도록 하겠습니다.

문의하실 내용이 있으시면 뎃글로 남겨주시면 감사하겠습니다.

 

그럼 이만

 

2021/02/26 - [DEV/MAX SCRIPT] - [3ds max script] 카메라 생성, 이동 시키기

 

[3ds max script] 카메라 생성, 이동 시키기

오늘 다룰 주제는 맥스의 카메라 와 뷰포트 입니다. 3D 공간의 개체를 보여주기 위하여는 카메라 라고 하는 가상의 개체가 필요합니다. 카메라에 보여지는 대상을 이미지화 하여 사용자에게 보

diy-dev-design.tistory.com

2021/02/24 - [DEV/MAX SCRIPT] - 3da max script 점과 점 사이의 거리 구하기

 

3da max script 점과 점 사이의 거리 구하기

간단하게 포스팅을 남기려고 합니다. 제목 그대로 버텍스 간 거리 구하기 입니다. 아니 정확히는 두개의 point3 사이의 거리를 구하는 방법을 소개해 드릴까 합니다. 그리고 용용 편으로 두 점사

diy-dev-design.tistory.com

2019/12/16 - [DEV/MAX SCRIPT] - 3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

 

3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

개발이라 하면 두드러기가 나는 디자이너 들이 있습니다. 아니 대부분 그렇죠. 이글을 읽고 계신 본인도 그러하다면, 그런데 스크립트로 무언가를 하고 싶다면 어쩌겠습니까.. 배워야지요. 그래

diy-dev-design.tistory.com

 

 

 

 

 

반응형
반응형

오늘 다룰 주제는 맥스의 카메라 와 뷰포트 입니다.

3D 공간의 개체를 보여주기 위하여는 카메라 라고 하는 가상의 개체가 필요합니다. 카메라에 보여지는 대상을 이미지화 하여 사용자에게 보여주는 것(랜더링) 인데요. 실제 카메라가 있는 건 당연히 아니고 카메라라는 개념을 담은 것이죠.

일반적인 뷰포트 역시 가상의 카메라라고 할 수 있는데 화면을 보여주는 방식, 다시말하면 3D 공간의 개체를 랜더링 하는 방식에 따라 크게 orthogonal 또는 perspective 로 나눌 수 있습니다. 

이러한 카메라와 뷰포트를 다루는 예제를 몇가지 오늘 소개해 드릴까 합니다.

 

타겟 카메라 생성하고 위치 설정하기.

물론 카메라를 max UI 를 이용하여 수동으로 생성할수 있지만 스크립트 공부 중이므로 자동으로 생성해 봅니다. 수동으로 카메라를 설정하게 되면 손으로 생성한 뒤 z 축으로 이동하거나 타겟의 위치를 조정해 주어야 하지만 자동으로 생성하면 항상 원하는 각도와 위치에 생성할 수 있답니다.

예를 들면

Teapot01 이라는 개체가 있다고 했을 때 항상 카메라를 XY 평면에서 우하단, Z 위치로 약간 위에서 보는 각도에서 보도록 만들어 줄 수 있습니다. 어쩌면 Teapot 의 크기가 크건 작건 항상 적당한 위치에 생성하는 것도 가능하겠죠. 아래 코드를 봐주세요.

obj = $Teapot01

-- 타겟 카메라를 생성한다.
myCamera = Targetcamera fov:45  pos:[0,0,0] target:(Targetobject transform:(matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]))
myCameraTarget = myCamera.Target 

-- 대상물의 크기에 따라 카메라 위치를 자동으로 설정해 주기 위하여 tepot 의 radius 를 얻어 온다.
teapotRadius = obj.radius
	
-- 카메라의 위치를 티팟의 우하단으로 위치하고 위로 높이를 조정한다. 
myCamera.pos = [teapotRadius * 4, teapotRadius * -4, teapotRadius * 3] 

-- 카메라 타겟의 위치를 티팟의 중앙으로 설정한다.
myCameraTarget .pos = obj.pos 
	
-- 타겟이 너무 바닥에 있으므로 radius 만큼 올려준다.
myCameraTarget .pos.z += teapotRadius 
	

이렇게 해주고 실행하면 (ctrl+E) 카메라가 하나 자동으로 생성되는 것을 볼 수 있습니다.

자동으로 생성된 카메라

만약 Teapot 이 엄청 크거나 작더라도 아마 비슷한 각도에 생성이 될겁니다.

훨씬 큰 teapot 을 생성하였지만 역시 유사한 각도에 카메라가 생성되었다.

동일한 스크립트로 실행 하였지만 역시 teapot 에 묻히지 않는 위치에 카메라가 생성이 되었습니다.

각도와 거리까지 완전히 동일하게 만들 수도 있지만 약간 복잡한 코드가 필요하므로 나중에 설명 드리겠습니다.

 

 

카메라 회전하기!

카메라 개체 역시 node 에 속하므로 rotate, move 와 같은 일반적인 속성을 제어할 수 있습니다.

그런데 오늘 제가 소개해 드릴 코드는 조금 다릅니다. 

카메라를 대상 피사체가 될 오브젝트를 중심으로 빙글 돌릴 겁니다.

흔히 제품 랜더링 할때 많이 쓰일 법한 샷 인데요. 보통은 물체를 돌려서 360도 촬영을 합니다. 그런데 드라마 씬 처럼 카메라를 빙글 돌려야 한다면요? 손으로 예쁘게 돌게 세팅하기가 쉽지 않습니다. 

자 그럼 어떻게 해야 할까요?

 

중심은 타겟의 위치로 하겠습니다. 회전은 한바퀴 할거고요. 제가 소개해드릴 코드를 이용하면 한바퀴를 돌며 10장을 찍을 수도 있고 100장을 찍을 수도 있습니다.

여기서 삼각함수가 필요한데요.. 음.. 삼각함수라 하면 sin(),  cos() 기억 나시나요? 기억 안나시죠? 

sin 이 0~90 으로 가는동안 값은 0.0 ~ 1.0 으로 변하고요. cos 가 0 ~ 90 으로 가는동안 값은 1.0 ~ 0.0 으로 변한다는 것만 정확하게 기억하시면 됩니다. 또 90에서 180 까지 가는동안은 그 반대의 값이 됩니다.

sin 그래프를 보면 아래와 같습니다.

sin 함수의 그래프

저 구불 구불한 그래프 기억나시나요? 아직 안나신다고요?

네... 기억 못하셔도 상관 없고요. sin cos 을 붙여서 원을 그릴 수 있다는 것만 기억하시면 됩니다.

 

sin cos 을 이용하여 원을 그리는 방법

바로 이렇게요.

 

이해 되시나요? 

 

그래서 우리는 맥스에서 360도를 돌면서 sin cos 에서 받아지는 값에 카메라에서 타겟까지의 거리를 곱해주면 카메라가 원 운동을 하게 되겠죠.

코드를 한번 보실까요?스에서 360도를 돌면서 sin cos 에서 받아지는 값에 카메라에서 타겟까지의 거리를 곱해주면 카메라가 원 운동을 하게 되겠죠.

-- 아까 만들어 두었던 카메라를 이용하겠습니다.
myCamera = $Camera01
myCameraTarget = myCamera.Target 


center = myCameraTarget.pos
distanceFromCam = myCamera.targetDistance

-- 사진을 찍을 랜더링 장 수
step = 12

for xx = 0 to step do
(
          -- sin cos 를 이용하여 원형으로 회전된 위치를 각 단계마다 계산한다.
          camXpos = sin(360.0 / step * xx) * distanceFromCam
          camYpos = cos(360.0 / step * xx) * distanceFromCam
		
          -- 실제 카메라의 위치를 계산된 위치로 설정한다.
          myCamera.pos.x = center.x + camXpos
          myCamera.pos.y = center.y + camYpos
		
          -- 랜더링하여 이미지로 저장한다
          render camera:myCamera outputSize:[320, 240] vfb:false outputfile:("D:\\testRender" +(360.0 / step * xx) as string + ".png" )
)

코드에 생소한 개념 (ventor)이 들어가긴 했지만 크게 어렵지는 않습니다.  위에서 설명 드린 것처럼 sin cos 를 이용하여 카메라의 위치를 설정하고 매 프레임마다 랜더링을 해주는 스크립트 입니다. 

vector 와 render 에 대한 부분은 나중에 별도로 포스팅을 하도록 하겠습니다. 

이렇게 자동으로 랜더링된 이미지를 한번 볼까요? 

12 프레임으로 나누어 랜더링된 이미지들

 

저 코드의 step 개수만큼 랜더링이 되었는데요. 해당 숫자를 24로 하든 36 으로 하든 아니면 360으로 필요하신 만큼 변경하여 랜더링 하여도 아마 잘 랜더링이 될 것 입니다.

에니메이션 등을 주고 임의로 사용자가 회전하는 위치에 따라 랜더링을 한다는건 사실상 엄청나게 귀찮고 힘든 작업이므로 랜더 세팅만 잘 되었다면 이렇게 걸어 놓고 자고 오면 깔끔하게 원하는 만큼 랜더링이 되어 있을 거에요.

 

그럼 선택한 물체로 카메라를 이동 시키는 방법은? 

네.. 간단하죠. 선택한 물체의 pos 를 이용해서 target 을 이동 시키고 이동시킨 만큼 카메라도 이동시키면 됩니다.

objs = getCurrentselection()
obj = objs[1] -- 선택한 오브젝트

myCam = $Camera01
myCam_target = myCam.target

-- 선택한 오브젝트 까지 이동할 거리 
delta = obj.pos - myCam_target.pos

myCam_target.pos += delta
myCam.pos += delta

이렇게 하면 되는 것이죠. 이동할 거리 (delta) 를 구한뒤 타겟과 카메라의 위치에 더해주면 됩니다.

아주 간단하죠?

 

 

타겟은 그대로 두고 카메라 거리만 조정하는 방법

3DS Max 의 타겟 카메라에서 타겟 까지의 거리를 조정하면 카메라는 가만히 있고 타겟만 움직이지 않습니까? 그런데 이게 영 불편할때가 있습니다. 타겟은 가만히 두고 distance 를 조정하여 카메라를 움직이고 싶을때가 있지요.

스크립트로 한번 해당 기능을 만들어 볼까요?

myCam = $Camera01
myCam_target = myCam.target

-- 현재 카메라로부터 타겟까지의 거리
currentDistance = myCam.targetDistance 

-- 이동할 거리 (상대거리)
deltaDist = 50

-- 타겟으로 부터 카메라의 방향
vecCam = normalize(myCam.pos - myCam_target.pos)

--최종 이동될 위치
finalCamPos = myCam.pos + (vecCam * deltaDist)

myCam.pos = finalCamPos

역시 간단합니다. 아직 vector 개념이 없으신 분은 중간에 잘 이해가 안되는 부분이 있으실 텐데요. 역시 나중에 별도로 포스팅하도록 하겠습니다.

deltaDist 값을 음수를 넣게되면 카메라의 위치가 타겟 방향으로 가까워 질겁니다.

위의 코드에 deltaDist 를 바꾸어 테스트를 해본 모습입니다.

물론 UI 에서 이런 기능을 지원하기는 하지만 정확한 거리를 이동하기 위하여는 스크립트 만큼 정확하고 편리한 것이 없기 마련입니다.

 

 

그외의 기능들

물론 카메라의 각종 프라퍼티를 스크립트를 이용하여 조정하는 것도 가능합니다.

orthoProjection 을 true 또는 false 로 설정하여 원근감을 없애고 isomatric 이미지 처럼 만든다거나

FOV 를 조정한다거나 near, far range 를 변경하거나 하는 등의 변경은 아주 쉽습니다.

F1 키를 누르시고 camera 를 검색하시면 친절하게 설명이 되어 있답니다.

 

이상으로 카메라 관련한 스크립트 소개를 마치도록 하겠습니다.

 

감사합니다.

2022.05.31 - [DEV/MAX SCRIPT] - [3ds max script] ray 에 대하여 알아보기

 

[3ds max script] ray 에 대하여 알아보기

가끔 아니 어쩌면 자주 3D 공간안에서 물체의 위치를 지정할때 이 물체가 저쪽에 닿는 면에 딱 위치하고 싶은데... 할때가 있죠? 예를 들면 나무나 돌덩이 이런걸 랜덤하게 막 생성한 다음 굴곡진

diy-dev-design.tistory.com

2021/02/24 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트, 프라퍼티 와 매소드 이해하기

 

3DS MAX 스크립트, 프라퍼티 와 매소드 이해하기

오늘은 3DS MAX script 를 개발하면서 이해하면 도움이 될 용어 두가지를 설명 드릴까 합니다. 바로 property 와 method 입니다. 프라퍼티와 매소드 정도로 발음하시면 됩니다. 도대체 이게 뭐고 왜 이런

diy-dev-design.tistory.com

2020/04/29 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 개체 선택하기

 

3DS MAX 스크립트로 개체 선택하기

Max Script 를 이용하여 무엇인가를 하려면 필수 요소라고 할 수 있는 것 중의 하나가 개체를 선택하거나 지정하는 방법입니다. 여기서 개체는 3D Scene 안의 오브젝트, 스플라인, 헬퍼 등과 같은 사

diy-dev-design.tistory.com

2019/12/11 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 초간단 다이얼로그 창 , UI 버튼 만들기

 

3DS MAX 스크립트로 초간단 다이얼로그 창 , UI 버튼 만들기

3DS MAX 스트립트를 이용하여 스크립팅을 하기 시작하면 MAX 로 할 수 있는 일이 너무나 많고 빠르게 진행된다는 것을 알 수 있게 됩니다. 이 놀라운 기능들을 스크립트를 매번 실행시키는 것이 번

diy-dev-design.tistory.com

 

 

반응형
반응형

간단하게 포스팅을 남기려고 합니다. 

제목 그대로 버텍스 간 거리 구하기 입니다. 아니 정확히는 두개의 point3 사이의 거리를 구하는 방법을 소개해 드릴까 합니다. 

그리고 용용 편으로 두 점사이의 어떤 특정 위치의 점의 좌표를 구하는 방법도 함께 알려 드리도록 하겠습니다.

어떤 물체가 점 A 로 부터 점 B 까지 움직이거나 A,B 사이의 특정위치를 알기 위한 계산을 하려면 필수적인 연산인데요.

예를들면 점 A 와 점 B 의 한 가운데가 되는 위치, 또는 점 A 로부터 점 B 까지의 0.2 정도 의 위치를 계산 하는 방법을 소개해 드릴까 합니다.

 

 

점과 점사이의 거리 구하기

점과 점 사이의 거리는 max script 에서는 아주 간단하게 구할 수 있답니다. 기본 명령어가 있기 때문인데요.

 

그림과 같이 박스 2개가 있는 경우 정 가운데 새로운 박스를 하나 만들어야 할 경우 사용하면 됩니다.

물론 저는 예를 box 로 들었지만 개체 A 의 어떤 점과 개체 B 의 어떤 점 사이의 위치를 구할때 동일하게 사용할 수 있는 예제 입니다.

boxA = $Box01
boxB = $Box02

ptA = boxA.center
ptB = boxB.center

distAB = distance ptA ptB -- 두점 사이의 거리를 계산한다.

간단하져?

distance 라는 명령을 이용하여 간단하게 두 점 사이의 거리를 구할 수 있습니다.

 

이제 정 가운데의 위치를 알아 볼까요?

공간상에서 위치를 이동시킨 값을 얻는 방법은 아래와 같습니다.

  • 최초 시작위치 + (이동할 방향 * 이동할 거리)

여기서 이동할 방향은 vector 라는 생소한 개념인데요. 나중에 설명을 드리도록 하겠습니다. 일단 vector 라고 하면 방향+거리 라고 간단하게 생각하시면 되겠습니다.

위의 예제를 활용하여 정중앙의 위치를 찾아보겠습니다.

boxA = $Box01
boxB = $Box02

ptA = boxA.center -- boxA 의 중앙 위치 (point3)
ptB = boxB.center -- boxB 의 중앙 위치 (point3)

distAB = distance ptA ptB -- 두점 사이의 거리를 계산한다.

-- 두점 사이의 정 가운데 위치를 찾아보자.
-- ptA --> pt2 방향으로 distAB / 2 한만큼 이동한 위치를 찾아보자

vector = ptB - ptA -- ptA -> ptB 방향 : ptB - ptA

vector = normalize(vector) -- normalize 를 이용하여 벡터(방향+거리) 에서 거리 개념을 제거한다.

ptC = ptA + (vector * (distAB / 2)) -- 시작위치 + (방향 * 이동할 거리)
	
boxC = box()
	
boxC.pos = ptC -- 새로 만들어진 boxC 의 위치를 구해진 정중앙으로 변경

 

요렇게 실행해 보면 아래와 같이 새로운 박스가 생성 됩니다.

가운데 녹색 박스가 두개의 박스 정 중앙에 생성되었다.

 

네 간단하죠? 실제로 제가 아주 많이 사용하는 계산 식으로 사용자 함수로 만들어 놓고 사용한답니다. 물론 정중앙이 아닌 1/3 지점, 아니면 어떤 위치도 설정이 가능합니다.

-- ptA --> pt2 방향으로 ratio 한만큼 이동한 위치를 돌려주는 함수
fn getPointBy2Point ptA ptB ratio =
(
	distAB = distance ptA ptB
	vector = normalize(ptB - ptA) -- 벡터(방향+거리) 에서 거리 개념을 제거한다.
	ptC = ptA + (vector * (distAB / 2)) -- 시작위치 + (방향 * 이동할 거리)		
	return ptC
)

 

이런식으로 만들어서 사용하는데요. 실제 사용할 때는 아래와 같이 사용하게 됩니다.

-- ptA --> pt2 방향으로 ratio 한만큼 이동한 위치를 돌려주는 함수
fn getPointBy2Point p1 p2 ratio =
(
	distAB = distance p1 p2
	vector = normalize(p2 - p1) -- 벡터(방향+거리) 에서 거리 개념을 제거한다.
	p3 = p1 + (vector * (distAB * ratio)) -- 시작위치 + (방향 * 이동할 거리)		
	return p3
)


boxA = $Box01
boxB = $Box02

ptA = boxA.center
ptB = boxB.center

ptC = getPointBy2Point ptA ptB 0.75 -- 위에서 작성된 함수를 이용하여 간단히 위치 계산

boxC = box()
boxC.pos = ptC

실행해 보면 두 박스 사이의 0.75 정도의 위치에 새로운 박스가 생성된 것을 알 수 있습니다.

 

위에서 만들어 놓은 함수를 이용하여 점 A 로부터 점 B 방향으로 1.0 이 넘으로 B 보다 더 멀리에 위치한 점을 얻을 수 있고요. 코드를 조금 수정하면 ratio 대신 직접 거리를 넣는 것도 간단히 구현할 수 있습니다.

 

공간상의 자동화 작업을 할 때 아주 자주 사용되는 기능이므로 저처럼 함수로 만들어 놓고 사용하셔도 좋겠습니다.

 

이만 오늘의 포스팅을 마치도록 하겠습니다.

 

 

반응형
반응형

오늘은 3DS MAX script 를 개발하면서 이해하면 도움이 될 용어 두가지를 설명 드릴까 합니다.

바로 property 와 method 입니다. 프라퍼티와 매소드 정도로 발음하시면 됩니다.

도대체 이게 뭐고 왜 이런걸 설명하는 걸까요? 

사실 몰라도 그만이기는 하지만 본격적으로 스크립트 개발을 하시려면 이해하고 넘어가시면 도움이 될 것 같아 작성하기로 마음 먹었습니다.

 

Property - 속성, 어떤 개체가 가지고 있는 속성을 가져오거나 변경한다.

Method - 명령, 어떤 개체에 대하여 일반적으로 필요한 여러가지 기능을 수행하도록 명령을 보낸다.

이라고 쉽게 생각하시면 됩니다. 실제 의미와는 조금 차이가 있긴 하지만 어쨌든 위와 같이 이해하시면 크게 다르지는 않습니다.

 

Property

일반적으로 프라퍼티는 어떤 클래스의 속성을 정의하는 지시어 입니다. 예를 들면

obj = $Box01

obj.Height -- 모델링의 높이, 읽고 쓰기 가능
obj.Width -- 모델링의 가로 폭, 읽고 쓰기 가능
obj.Length -- 모델링의 세로 폭, 읽고 쓰기 가능

obj.pos.x -- 모델링의 x 위치 , 읽고 쓰기 가능
obj.pos.y -- 모델링의 y 위치 , 읽고 쓰기 가능
obj.pos.z -- 모델링의 z 위치 , 읽고 쓰기 가능

obj.max.x -- 모델링의 바운드 박스 (공간 영역)중 가장 큰 x 위치 , 읽기만 가능
obj.max.y -- 모델링의 바운드 박스 (공간 영역)중 가장 큰 y 위치 , 읽기만 가능
obj.max.z -- 모델링의 바운드 박스 (공간 영역)중 가장 큰 z 위치 , 읽기만 가능

obj.min.x -- 모델링의 바운드 박스 (공간 영역)중 가장 작은 x 위치 , 읽기만 가능
obj.min.y -- 모델링의 바운드 박스 (공간 영역)중 가장 작은 y 위치 , 읽기만 가능
obj.min.z -- 모델링의 바운드 박스 (공간 영역)중 가장 작은 z 위치 , 읽기만 가능

와 같이 정의 했을 때 Height 나 Width, Length 는 Box() 라는 클래스(엄연히 말하면 pos, max 는 node 클래스의 프라퍼티 임)의 속성(프라퍼티)이 됩니다. 대부분의 경우 read/wright 가 지원되지만 경우에 따라서는 read 만 지원되는 경우도 있습니다. 무슨 말인가 하면 read 만 지원된다 하면 해당 프라퍼티를 불러올 수 는 있지만 사용자가 변경하지는 못한다는 뜻입니다. Height 나 width, length 는 변경이 가능하죠? 한번 해보세요.

 

 

Methode

method 는 명령이라고 말씀 드렸는데요. 보통 클래스를 만들때 해당 클래스를 제어할 수 있는 여러가지 기능을 한꺼번에 만들게 됩니다. 맥스 스크립트에서는 프라퍼티와 매소드를 굳이 크게 구분하고 있지는 않지만 엄연히 개념적으로 다르므로 이해하시면 좀 더 복잡한 스크립트 코딩에 도움이 됩니다.

대표적으로 editable_poly  같은 클래스를 컨트롤 하기 위한 polyop 라는 오퍼레이션 전용 클래스가 있는데 해당 클래스에 getvert 와 setvert 가 있습니다.
getvert 는 polygon 모델링의 특정 vertex 의 위치를 받아오는 기능이며 setvert 는 특정 버텍스의 위치를 설정(변경) 해주는 기능입니다. getvert 는 사실 프라퍼티에 가까운 기능이지만 setvert 는 분명 매소드처럼 동작 되는 것이죠.
맥스스크립트에서는 get/set 이 대부분 쌍으로 존재합니다.

obj = $ -- editabel poly

pt = polyop.getvert obj 1 -- 1번 버텍스의 위치를 가져온다.
pt.z += 10 -- 가져온 위치의 z 값을 +10 해준다
polyop.setvert obj 1 pt -- +10 된 위치를 다시 원래 버텍스에 세팅한다.

위의 예제는 polyop 라는 폴리곤 전용 오퍼레이션 매소드를 이용하여 버텍스의 좌표를 변경하는 대표적인 간단한 사례 입니다.

for 구분과 연계하여 아래와 같이 할 수도 있죠.

obj = $ -- editabel poly

vNum = polyop.getnumverts obj -- 버텍스의 개수를 가져온다.

for i = 1 to vNum do
(
	pt = polyop.getvert obj i -- i 번쨰 버텍스의 위치를 가져온다.
	pt.z += 10 -- 가져온 위치의 z 값을 +10 해준다
	polyop.setvert obj i pt -- +10 된 위치를 다시 원래 버텍스에 세팅한다.
)

 

물론 editable poly 자체가 가지고 있는 method 와 property 도 있습니다.

obj = $ -- editabel poly

obj.selectByMaterial  1 -- select by material id 1

위의 코드는 머테리얼 ID 1번인 모든 폴리곤을 선택해주는 기능(method) 가 되겠습니다. 뒤의 숫자를 바꿔주면 해당 머테리얼 ID 가 적용된 모든 폴리곤이 선택이 되겠죠.

 

 

맥스 스크립트에서 언급되는 개체는 상위 / 하위 개념을 가지고 있습니다. 이는 일반적으로 계층구조의 프로그래밍을 할때 보여지는 구조인데요. 상위 클래스 > 하위 클래스와 같은 형태인데 하위 클래스는 상위 클래스의 프라퍼티와 매소드를 상속 받아 동일하게 사용할 수 있습니다.

 

맨위의 사례에서 보여드린 .pos 라든가 .max .min 같은 프라퍼티가 대표적인 예인데요, 이는 node 라는 3ds max 의 최상위 클래스를 상속했기 때문입니다.

node 라는 클래스는 우리가 알고 있는 선택가능한 거의 모든 대상이 포함되며 이는 geometry 뿐만 아니라 shape 이나 helper, camera 까지도 모두 node 의 하위 클래스 입니다.

즉 node 클래스에서 정의하고 있는 모든 속성 및 명령을 해당 하위 클래스에서도 사용이 가능한 것입니다.

스크립트 개발하실때 가장 많이 참고하는 것이 바로 help 파일인데요. help 파일 (3ds max script reference)의 특정 개체에 대한 페이지 (예를 들면 editable mesh) 에 나와 있지 않더라도 해당 개체가 node 클래스의 하위 클래스라면 node 클래스에서 정의한 모든 속성과 기능을 사용할 수 있다는 것이죠.

 

How to use

프라퍼티나 매소드는 보통은 아래와 같이 사용됩니다.

클래스.명령어 -- 위에서 보여드렸죠?

명령어 <클래스> -- 실제로는 이런 경우가 많습니다.

위에서 말씀드린 node 클래스의 property/methode 들을 볼까요? 

F1 키를 누르신 뒤 검색 창에 node 를 쳐보시면 node 개체에 대하여 상세하게 설명이 되어 있습니다.

move <node> <point3> -- mapped
scale <node> <point3> -- mapped
rotate <node> <angle> <axis_point3> -- mapped -- angle in degrees
rotate <node> <quat> -- mapped
rotate <node> <eulerangles> -- mapped

이런식으로 사용되는 것이죠. 

앞의 move, scale 등은 node 에 사용할 수 있는 method 라고 할 수 있겠습니다.

말하자면 

명령어 <오브젝트> 옵션

이런 경우가 대부분이고 자주 사용됩니다.

 

 

자 간단하게 설명을 드렸지만 개념에 대한 부분이므로 어려울 수 있습니다.

솔직히 몰라도 스크립트 개발에는 큰 영향은 없습니다. 하지만 개자이너로 거듭나기 위하여 이정도 개념은 가지고 있어야 하지 않겠습니까? ㅋ 개발자들 눈이 동그라미가 될거에요.

끝으로 맥스 스크립트의 node 계층 구조를 간단하게 보여드리겠습니다. reference 에서 Hierarchy를 검색 하시면 max script 의 모든 계층 구조를 보실 수 있답니다.

Value
--MAXWrapper
----node   
------camera  
--------Freecamera 
--------Missing_Camera 
--------Targetcamera 
------GeometryClass  
--------Apollo_Param_Container 
--------apolloParamContainer 
--------Blizzard 
--------BoneGeometry 
--------BoneObj 
--------Boolean2 
--------Box 
--------C_Ext 
--------Capsule 
--------ChamferBox 
--------ChamferCyl 
--------Cone 
--------Conform 
--------Connect 
--------ControlContainer 
--------CV_Surf 
--------Cylinder 
--------Damper 
--------Editable_mesh 
--------Editable_Patch 
--------Editable_Poly 
--------EditablePolyMesh 
--------Gengon 
--------GeoSphere 
--------Hedra 
--------Hose 
--------L_Ext 
--------Loft 
--------LoftObject 
--------Mesher 
--------meshGrid 
--------Missing_GeomObject 
--------Morph 
--------Nurbs 
--------NURBS_Imported_Objects 
--------NURBSSurf 
--------OilTank 
--------OldBoolean 
--------PArray 
--------particleMesher 
--------PCloud 
--------Plane 
--------Point_Surf 
--------Point_SurfGeometry 
--------PolyMeshObject 
--------Prism 
--------Pyramid 
--------Quadpatch 
--------RingWave 
--------RmModel 
--------RmModelGeometry 
--------Scatter 
--------ShapeMerge 
--------SlidingDoor 
--------SlidingWindow 
--------Snow 
--------Sphere 
--------Spindle 
--------Spray 
--------Spring 
--------SuperSpray 
--------Targetobject 
--------Teapot 
--------Terrain 
--------Torus 
--------Torus_Knot 
--------TriMeshGeometry 
--------Tripatch 
--------Tube 
------helper  
--------Anchor 
--------AudioClip 
--------Background 
--------Billboard 
--------Bone 
--------BoxGizmo 
--------CamPoint 
--------Compass 
--------Cone_Angle 
--------ConeAngleManip 
--------CylGizmo 
--------Dummy 
--------Falloff_Manipulator 
--------FalloffManip 
--------FogHelper 
--------grid 
--------Hotspot_Manip 
--------HotspotManip 
--------IK_Chain_Object 
--------IK_Swivel_Manip 
--------IKSwivelManip 
--------Inline 
--------LOD 
--------Missing_Helper 
--------NavInfo 
--------Plane_Angle 
--------PlaneAngleManip 
--------Point 
--------PointHelperObj 
--------Position_Manip 
--------PositionManip 
--------Protractor 
--------ProxSensor 
--------radiusManip 
--------Reactor_Angle_Manip 
--------Reactor_Vector_Handle_Manip 
--------ReactorAngleManip 
--------ReactorVectorHandleManip 
--------Rotation_--
--------Rotation_Valuehelper 
--------RotationValueManip 
--------Slider_Manip 
--------SliderManip 
--------sliderManipulator 
--------Sound 
--------SphereGizmo 
--------Tape 
--------TimeSensor 
--------TouchSensor 
--------uvwMappingHeightManip 
--------uvwMappingLengthManip 
--------uvwMappingUTileManip 
--------uvwMappingVTileManip 
--------uvwMappingWidthManip 
------light  
--------Directionallight 
--------freeSpot 
--------Missing_Light 
--------Omnilight 
--------TargetDirectionallight 
--------targetSpot 
------NodeObject  
------shape  
--------Arc 
--------Circle 
--------CV_Curve 
--------CV_Curveshape 
--------Donut 
--------Ellipse 
--------Helix 
--------line 
--------LinearShape 
--------Lines 
--------Missing_Shape 
--------Ngon 
--------NURBSCurveShape 
--------Point_Curve 
--------Point_Curveshape 
--------Rectangle 
--------section 
--------Simple_Shape 
--------Simple_Spline 
--------SplineShape 
--------Star 
--------text 
------SpacewarpObject  
--------BendModWSM 
--------Bomb 
--------CameraMapSpaceWarp 
--------ConformSpaceWarp 
--------Deflector 
--------Drag 
--------gravity 
--------MapScalerSpaceWarp 
--------Missing_WSM_Object 
--------Motor 
--------Path_Follow 
--------PathDeformSpaceWarp 
--------PBomb 
--------PDynaFlect 
--------PDynaflector 
--------POmniFlect 
--------PushSpaceWarp 
--------SDeflector 
--------SDynaFlect 
--------SDynaflector 
--------SOmniFlect 
--------SpaceBend 
--------Spacedisplace 
--------SpaceFFDBox 
--------SpaceFFDCyl 
--------SpaceNoise 
--------Spaceripple 
--------SpaceSkew 
--------SpaceStretch 
--------SpaceTaper 
--------SpaceTwist 
--------Spacewave 
--------UDeflector 
--------UDynaDeflector 
--------UDynaFlect 
--------UOmniFlect 
--------Vortex 
--------Wind 
------System  
--------Bones 
--------Missing_System 
--------Ring_Array 
--------Sunlight 
--------XRefObject 

그럼 이만 오늘 포스팅을 마칩니다.

감사합니다.

 

2020/04/29 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 개체 선택하기

2019/12/11 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 초간단 다이얼로그 창 , UI 버튼 만들기

2019/06/01 - [DEV/MAX SCRIPT] - 3DS MAX Script 에 대하여

반응형
반응형

Max Script 를 이용하여 무엇인가를 하려면 필수 요소라고 할 수 있는 것 중의 하나가 개체를 선택하거나 지정하는 방법입니다. 여기서 개체는 3D Scene 안의 오브젝트, 스플라인, 헬퍼 등과 같은 사용자가 직접 선택할 수 있는 개체를 말합니다. 물론 오늘 강좌에서의 선택은 마우스를 클릭하여 선택하는 select의 개념만을 말하는 것은 아닙니다. 

예를 들어 A 라는 모델링 개체의 스케일을 2배로 변경한다고 했을 때 일반적인 사용자의 입장에서는 마우스로 해당 모델링을 클릭하거나 레이어 리스트에서 선택하거나 개체 리스트에서 해당 모델링을 선택 (select) 한 뒤 속성 등을 변경하게 되는데요. 스크립트에서는 굳이 select 의 상태를 만들 필요는 없습니다. 물론 동일하게 select 상태를 만들 수 있긴 하지만 성능 관점에서는 굳이 select 상태여야 할 필요가 없다면 바로 진행을 하면 됩니다.

참고로 본 강좌 진행을 위해 알아야 할 것은 이제부터는 개체를 노드(Node)라고 부를 것 입니다. 3DS MAX Script 에서 공식적으로 개체를 Node 라고 지정하였기 때문이고요. 레퍼런스 등을 보실때도 그렇게 이해하고 계신 것이 혼선이 없을 것 입니다.

우선 기본적인 방식을 살펴 보겠습니다.

  • selection 상태를 만드는 방법
  • 현재 선택된 개체를 가져오는 방법
  • selection 상태가 아닌 상태에서 개체를 지정하는 방법
    • 지정된 이름을 기준으로 지정하는 방법 (단수 개체)
    • 이름의 일부를 기준으로 지정하는 방법 (복수 개체)
    • 레이어 단위로 지정하는 방법
    • 모델링 클래스 단위로 지정하는 방법 (geometry, spline, ...)

 

이런 것들을 소개해 드릴 까 합니다.

이번 강좌의 내용만 잘 이해하셔도 3D Scene 내의 대부분의 개체를 선택하거나 지정하는 것이 가능합니다.

 

 

Selection 상태를 만드는 방법

먼저 기본형은 Select <Node> 의 형태로 되어 있습니다.

Node 는 $ 표시를 붙인 뒤에 개체의 이름을 적어주면 해당 노드를 지정하게 됩니다.

만약 $Box01 이라 하면 "Box01" 이라는 이름을 갖는 노드(개체)를 지칭하게 됩니다. 이녀석을 선택 (Select) 상태로 만드시려면 아래와 같은 방법을 사용하면됩니다.

Select $Box01

요 코드를 스크립트 에디터 또는 리스너(F11) 창 아래 하얀색 창에 적어주고 실행하면 "Box01" 이라는 이름을 갖는 모델링이 선택된 상태가 됩니다. 물론 Box01 이라는 개체가 존재해야 하지요.

A 라는 오브젝트를 선택한 뒤 B 라는 오브젝트를 추가로 선택하고 싶으신 경우 아래와 같이 코드를 작성하시면 됩니다.

select $Box01
selectmore $Box02

selectmore 라는 명령어를 이용하여 셀렉션을 추가할 수 있습니다.

 

 

 

현재 선택된 개체를 가져오는 방법

코드 작성을 하다보면 모든 기능이 시작부터 끝까지 자동화가 어려운 경우가 있습니다. 그런 경우 사용자에 의해 특정 개체를 선택한 뒤 부터 코드가 실행이 된다거나 하는 경우가 종종 있을 수 있습니다. 이럴때 현재 선택된 개체를 가져오는 스크립트가 필요한데요. 바로 아래와 같이 사용하시면 됩니다.

myObject = getCurrentSelection()

이렇게 하면 현재 선택된 개체들을 myObject 라는 변수로 가져올 수 있는데요. 아래와 같이 실재로 사용할 수 있습니다.

myObject = getCurrentSelection()

for obj in myObject do
(
	-- 선택된 개체에 대하여 수행해야 하는 코드를 작성한다.
    print (obj.name)
)

-- 또는

for i = 1 to myObject.count do
(
	obj = myObject[i]
    print (obj.name)
)

 


selection 상태가 아닌 상태에서 개체를 지정하는 방법

스크립트를 이용하여 자동화 업무를 하다보면 항상 선택이라는 액션이 발생되는 것은 아닙니다. 선택이라는 액션이 이루어 지는동안 속도가 많이 저하되기 때문에 자동화의 대상이 많을 수록 선택 과 같은 액션은 생략하는 것이 좋습니다. 개체가 선택될 때 마다 맥스에서는 UI 를 업데이트 해주어야 하는데요, 이때 성능이 많이 느려지게 됩니다. 아래의 내용에서는 선택 과정 없이 특정 개체에 직접 접근하는 간단한 사례를 설명하겠습니다.

 

지정된 이름을 기준으로 지정하는 방법 (단수 개체)

오브젝트의 이름을 알고 있는 경우 가장 손쉽게 개체를 지정할 수 있습니다. 보통은 코드 작성의 편의를 위하여 변수에 담아서 사용하는것이 일반적인 방법입니다. 위에 select 예제와 유사한 방식으로 지정하게 됩니다.

obj = $Box01
print (obj.name)

Box01 이라는 모델링 개체의 이름을 프린트 창에 출력하는 코드죠. 위와 같이 첫줄을 적어주면 obj 라는 개체가 갖는 다양한 속성들이나 명령들을 적용할 수 있게 됩니다. 예를 들어 해당 개체가 Box 라는 class 인 경우 아래와 같이 속성을 변경할 수 있게 됩니다.

obj = $Box01
print (obj.name)

-- 박스의 크기를 현재의 두배로 만들자
obj.width = obj.width * 2
obj.height = obj.height * 2
obj.length = obj.length * 2

-- 높이를 50 만큼 올려보자
obj.pos.z += 50 

 

요런식으로 사용하는 것이지요.

 

 

 

이름의 일부를 기준으로 지정하는 방법 (복수 개체)

이번에는 이름의 일부분만을 이용하여 개체를 지정하는 방법을 소개해보겠습니다.

예를 들어 "box01" , "box02",... "box99" 이런식으로 동일한 이름 구조를 갖는 복수개의 개체가 있는 경우에 해당됩니다. 

objs = execute ("$box*")

print objs.count

위에 보시면 execute 라는 명령어가 있는데요. 뒤쪽에 나오는 문자열을 실행 가능한 문장처럼 해석하는 것입니다. 문자열에는 "$box*" 이라는 형태로 씌어져 있는데 여기서 * 은 와일드 카드라고 불리는 글자 입니다. 다시말하면 box + 어떤 것이든 해당되는 문자열 이라고 보시면 됩니다. scene 내에 box 로 시작하는 모든 개체가 objs 라는 변수에 담기는 것이죠. objs 는 배열형 변수가 되어 실제 사용하실 때는 아래와 같이 하나씩 꺼내 쓸 수 있게 됩니다.

objs = execute ("$box*")

print objs.count -- 전체 담겨져 있는 개체의 수를 출력한다

for o in objs do
(
	print o.name -- 개체의 이름을 출력한다.
    -- 여기서 개체별로 하고 싶은 액션을 작성하면 됩니다.
)

-- 다른 방법으로는
for i = 1 to objs.count do
(
	print objs[i].name

)

 

위와 같은 형식으로 각각의 개체에 대하여 어떤 작업을 하는 것이 가능합니다.

 

 

레이어 단위로 지정하는 방법

그럼 이번에는 레이어 단위로 개체를 지정하는 방법을 알아보겠습니다. 

3DS MAX 작업을 하다보면 레이어를 기준으로 개체를 생성하고 관리하는 경우가 종종 있습니다. 물론 레이어 창을 열어서 해당 레이어 안의 개체를 선택해 줄 수 있겠지만 레이어가 많은 경우, 또는 특정 레이어에 항상 같은 작업이 반복되는 경우 레이어의 개체를 지정하여 액션을 만들어 주는 것이 유용할 때가 있습니다.

레이어 이름을 아는 경우 아주 간단하게 적용이 가능합니다.

myLayer = LayerManager.getLayerFromName "myObjects"

myLayer.nodes &objs

for  o in objs do
(
	print o.name
)

myObjects 라는 이름을 갖는 레이어의 모든 개체를 objs 라는 변수에 담는 코드 입니다. 

레이어.nodes 라는 명령어가 뒤에 따라오는 참조형 변수에 해당 레이어의 모든 노드를 담아주는 기능을 수행합니다. 

참조형 변수는 반드시 & 기호를 붙여 주어야 하며 미리 정의를 해줄 필요는 없습니다.

 

 

모델링 클래스 단위로 지정하는 방법 (geometry, spline, ...)

scene 내에 위에서 정의한 방식 외에도 여러 레이어에 포함되어 있고 다양한 이름으로 존재하는 개체를 지정해야 하는 경우도 많이 있습니다. 예를 들면 scene 내의 모든 geometry 나 spline, helper 등을 선택해야 할 때도 있기 마련입니다.

이럴 때 사용할 수 있는 간단한 방법이 있습니다.

for  o in objects do
(
	print o.name
)

scene 내의 모든 오브젝트에 대한 처리가 가능하게 하는 간단한 방법입니다.

여기서 사용된  objects 와 같은 개체를 오브젝트 셋이라 부를수 있는데요 다음과 같은 종류가 있습니다.

objects  --all the objects
geometry  --the standard 3ds Max categories... 
lights
cameras
helpers
shapes
systems
spacewarps
selection  --the current selection

어떤 변수에 위에 해당되는 셋을 선언해주면 scene 내의 모든 해당 클래스의 개체가 대상이 됩니다.

아주 간단하지만 강력한 기능이죠.

 

이렇게 다양한 방법으로 화면 내의 개체를 지정하고 지정된 개체에 대하여 필요한 어떤 작업을 수행하는 것이 가능합니다. 어렵지 않죠?

다음번에는 어떤 조건을 붙여서 개체를 지정하거나 피하는 방법을 소개해 드리겠습니다.

 

그럼 이만~

2022.05.31 - [DEV/MAX SCRIPT] - [3ds max script] ray 에 대하여 알아보기

 

[3ds max script] ray 에 대하여 알아보기

가끔 아니 어쩌면 자주 3D 공간안에서 물체의 위치를 지정할때 이 물체가 저쪽에 닿는 면에 딱 위치하고 싶은데... 할때가 있죠? 예를 들면 나무나 돌덩이 이런걸 랜덤하게 막 생성한 다음 굴곡진

diy-dev-design.tistory.com

2019/12/11 - [DEV/MAX SCRIPT] - 3DS MAX 스크립트로 초간단 다이얼로그 창 , UI 버튼 만들기

 

3DS MAX 스크립트로 초간단 다이얼로그 창 , UI 버튼 만들기

3DS MAX 스트립트를 이용하여 스크립팅을 하기 시작하면 MAX 로 할 수 있는 일이 너무나 많고 빠르게 진행된다는 것을 알 수 있게 됩니다. 이 놀라운 기능들을 스크립트를 매번 실행시키는 것이 번�

diy-dev-design.tistory.com

 

2019/12/16 - [DEV/MAX SCRIPT] - 3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

 

3DS MAX SCRIPT 강좌?? 무작정 시작하기 - 디자이너 추천

개발이라 하면 두드러기가 나는 디자이너 들이 있습니다. 아니 대부분 그렇죠. 이글을 읽고 계신 본인도 그러하다면, 그런데 스크립트로 무언가를 하고 싶다면 어쩌겠습니까.. 배워야지요. 그래

diy-dev-design.tistory.com

 

반응형

+ Recent posts