반응형

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 에 대하여

반응형
반응형

코로나로 인하여 아이들이 집밖에 나가지도 못하고 집안에서 게임만 하고 있는 것을 보고 아이들을 위해 놀이거리를 하나 만들어 주어야겠다고 생각하고 시작한 동물의 숲 카드 만들기 입니다.

일단 물고기 카드를 만들려고 시작했는데 종류가 80 개나 되다 보니 만만치가 않았습니다.

그래서 가능하면 쉽게 빠르게 만들 수 있고 필요하면 나중에 수정하기도 쉽도록 코딩을 좀 하는 방향으로 제작 방안을 결정했습니다.

 

포토샵 자동화 과정이 이루어지는 전체 과정을 엿볼 수 있는 좋은 기회이니 관심 있으신 분은 주의 깊게 보시면 도움이 될 것이라 생각합니다.

 

 

 

어떻게 만들지?

 

일단 디자인을 결정해야 겠죠? 몇가지 구상 끝에 아래와 같이 만들기로 합니다.

이름과 가격, 잡히는 곳을 적고 그림자를 표시한뒤 프린트 해서 접으면 끝

만들어진 이미지를 출력하여 반으로 접어 붙이면 앞면은 물고기 그림자, 뒷면은 물고기 정보가 담겨있는 카드가 만들어 집니다.

 

제작은 다음과 같이 진행하기로 하였습니다.

  • 모든 동물의 이름, 사는곳, 위치를 물고기 이미지와 함께 레이어 명에 남긴다.
  • 배경의 타입에 맞게 배경이미지를 제작한다 (연못, 강, 바다 등)
  • 물고기의 그림자의 크기별로 그림자 이미지를 별도로 만든다.
  • 스크립트를 작성한다.
    • 물고기 레이어를 탐색하면서 레이어 명을 분석한다.
    • 레이어명에서 추출된 배경, 그림자 레이어를 on 한다
    • 정보에 맞도록 텍스트 레이어의 내용을 변경한다
    • 이미지를 파일로 저장한다
    • 물고기 레이어, 배경, 그림자 레이어를 숨긴다.

요런 과정을 통하여 만들기로 합니다.

 

 

먼저 포토샵으로 자동화를 위한 데이터 파일을 제작합니다.

먼저 물고기 이미지를 취득합니다.

일단 닌텐도에서 캡쳐한 이미지와 아직 잡지 못한 물고기는 인터넷에서 구한 뒤 레이어별로 이미지를 적재합니다.

레이어의 이름은 위에서 정의한 것 처럼 물고기의 정보를 담도록 합니다.

레이어별 정보로 설정한 명칭

 

그 다음 물고기 그림자 세트를 shadow 라는 레이어 셋 안에 만들어 줍니다.

물고기 그림자 크기별 모양

 

그리고 화면 레이아웃에 맞도록 텍스트 및 텍스트 박스, 기타 디자인을 완성합니다.

텍스트 레이아웃

 

강, 연못, 바다 등과 같이 배경에 맞도록 상단의 배경을 레이어로 구분하여 구성합니다.

잡히는 곳에 해당하는 이미지

 

총 6개의 배경이 구성이 되었습니다.

각각 물고기 레이어에서 정의한 장소와 동일하게 레이어 명칭을 설정해 줍니다.

그리고 물고기 레이어, shadow, 등을 레이어 셋 (폴더)로 구성합니다.

최종 레이어 구성

일단 이렇게 하면 PSD 파일은 준비가 완료된 셈 입니다.

 

 

 

 

이제 코딩을 해볼까요? 

먼저 저장할 경로와 파일 옵션을 설정해야 하는데요. 저는 출력용이므로 eps 포멧을 사용하였습니다.

var sPath = "C:\\Users\\cindy\\Pictures\\animal_tree\\eps\\"

var epsOption = new EPSSaveOptions()
epsOption.embedColorProfile = true

 

그 다음 현재 도큐먼트와 각 타입별 레이어 셋을 변수에 할당해 줍니다.

var cDoc = app.activeDocument;

var fLayer = cDoc.layers["fishs"].layers
var sLayers = cDoc.layers["shadow"].layers
var tLayer = cDoc.layers["text"].layers

 

이제 물고기 레이어 (fLayers) 를 한바퀴 돌며 저장을 할겁니다. 이때 레이어의 명칭을 parsing 해야 하는데요. 저는 _ 를 이용하여 구분자를 만들어 놓았으므로 아래와 같은 방법으로 문자열을 분리합니다.

for (var k = 0 ; k < fLayers.length; k++)//fLayer.layers.length
{
   
    var cLyr = fLayers[k]
    var tmpName = cLyr.name
    var nameSet = tmpName.split("_")
    
}

이렇게 하면 모든 fishs 레이어 안의 레이어에 대하여 nameSet 이라는 변수에는 현재 물고기 레이어 이름을 "_" 로 구분하여 배열로 담게 됩니다.

각 반복시마다 cLyr 라는 변수는 현재 레이어를 지칭하게 되죠.

이제 각 설정들을 변경하고 필요한 레이어를 켜거나 끄는 동작을 넣어야 합니다.

for (var k = 0 ; k < fLayers.length; k++)//fLayer.layers.length
{
   
    var cLyr = fLayers[k]
    var tmpName = cLyr.name
    var nameSet = tmpName.split("_")
    var bglayerName = nameSet[3]
    
    if (bglayerName == "바다(비)")
    {
        bglayerName = "바다"
    }
    //물고기 레이어 켜기
    cLyr.visible = true
    
    // 그림자 레이어 켜기
    sLayers[nameSet[2]].visible = true
    
    // BG 레이어 켜기
    cDoc.layers[bglayerName].visible = true
    
    // 텍스트 레이어 내용 변경
    tLayers[0].textItem.contents = nameSet[1]
    tLayers[1].textItem.contents = nameSet[3]
    tLayers[2].textItem.contents = nameSet[4]
    
    // eps 저장
    var dFile = new File(sPath + nameSet[0] + "_" + nameSet[1] + ".eps")
    cDoc.saveAs(dFile, epsOption, true, Extension.LOWERCASE)  
    // 그림자 레이어 끄기
    sLayers[nameSet[2]].visible = false
    
    //물고기 레이어 끄기
    cLyr.visible = false
    
    // BG 레이어 끄기
    cDoc.layers[bglayerName].visible = false
}

현재 물고기 레이어와 각 설정에 맞는 그림자 레이어를 켜고, 배경을 켠다음 텍스트 정보를 업데이트 합니다.

그리고 저장하기로 한 파일로 저장을 하게되죠. 

저장을 마치면 다시 켜주었던 레이어들은 꺼주면 한 번의 반복문이 완성되는 것이죠.

전체 코드를 보면 아래와 같습니다.

var sPath = "C:\\Users\\cindy\\Pictures\\animal_tree\\"
var pngOption = new PNGSaveOptions()
    pngOption.embedColorProfile = true;
    pngOption.formatOptions = FormatOptions.STANDARDBASELINE;
    pngOption.matte = MatteType.NONE;
    pngOption.quality = 100;
    pngOption.PNG8 = false; //24 bit PNG
    pngOption.transparency = true;
    pngOption.interlaced = true;
    
var sPath = "C:\\Users\\cindy\\Pictures\\animal_tree\\"

var epsOption = new EPSSaveOptions()
epsOption.embedColorProfile = true




var cDoc = app.activeDocument;


var fLayers = cDoc.layers["fishs"].layers
var sLayers = cDoc.layers["shadow"].layers
var tLayers = cDoc.layers["text"].layers

//alert(fLayer.layers.length);

for (var k = 0 ; k < fLayers.length; k++)//fLayer.layers.length
{
   
    var cLyr = fLayers[k]
    var tmpName = cLyr.name
    var nameSet = tmpName.split("_")
    var bglayerName = nameSet[3]
    
    if (bglayerName == "바다(비)")
    {
        bglayerName = "바다"
    }
    //물고기 레이어 켜기
    cLyr.visible = true
    
    // 그림자 레이어 켜기
    sLayers[nameSet[2]].visible = true
    
    // BG 레이어 켜기
    cDoc.layers[bglayerName].visible = true
    
    // 텍스트 레이어 내용 변경
    tLayers[0].textItem.contents = nameSet[1]
    tLayers[1].textItem.contents = nameSet[3]
    tLayers[2].textItem.contents = nameSet[4]
    
    // png 저장 - png 저장을 하려면 모드를 RGB 로 바꾸어 주어야 한다.
    //var dFile = new File(sPath + nameSet[0] + "_" + nameSet[1] + ".png")
    //cDoc.saveAs(dFile, pngOption, true, Extension.LOWERCASE)  
    
    // eps 저장 - eps 저장을 하려면 모드를 CMYK 로 바꾸어 주어야 한다.
    var dFile = new File(sPath + nameSet[0] + "_" + nameSet[1] + ".eps")
    cDoc.saveAs(dFile, epsOption, true, Extension.LOWERCASE)  
    
    // 그림자 레이어 끄기
    sLayers[nameSet[2]].visible = false
    
    //물고기 레이어 끄기
    cLyr.visible = false
    
    // BG 레이어 끄기
    cDoc.layers[bglayerName].visible = false
}

이렇게 물고기 레이어만큼 반복을 한뒤 코드는 종료 됩니다.

80개 레이어를 각각 설정하고 저장하는데 1분도 채 걸리지 않습니다. ^^

 

자동으로 추출된 동물의 숲 카드 이미지들

출력을 위하여 eps 포멧으로 저장하긴 했지만 윈도우에서 미리보기를 위하여 png 파일로도 한번 저장해 봤습니다.

예상 하였던 것처럼 잘 저장이 되었습니다.

 

 

 

출력용 레이아웃 파일 제작하기

끝으로 이제 출력용으로 레이아웃을 만들어 주어야 하는데요. 

일러스트 레이터에서 대지를 만들고 배치할 위치에 맞도록 가이드 선을 잡아 줍니다. 물론 png 로 저장한 뒤 파워 포인트 등으로 작업하셔도 됩니다.

그리고 이미지 하나하나 앉혀주면 됩니다.

번거로운 작업이지만 이렇게 딱 1회성 작업이 이루어지는 경우 그냥 손으로 하는게 나은 경우도 많습니다.

일러스트레이터에서 배치한 모여라 동물의 숲 카드 인쇄용 파일

여기서 중요한 것은 일러스트에서 이미지를 가져올 때 place(가져오기) 기능을 이용해야 하며 link (연결) 된 이미지로 불러와야 한다는 점 입니다.

link 된 이미지로 가져오게 되면 아래와 같이 선택 시 이미지에 X 표시가 되며 수정이 불가능한데요. 원본 eps 파일이 수정되는 경우 자동으로 이미지가 업데이트 되는 특징이 있습니다. 연결된 파일이 아닌 경우 수정이 되면 모든 이미지를 다시 가져와야 하는 불상사가 일어날 수 있습니다.

link 된 이미지(좌측)와 포함된 이미지(우측) 차이

 

이렇게 해서 모든 이미지를 앉히고 출력도 성공적으로 마칠 수 있었습니다.

만들어진 ai 파일을 이용하여 pdf 를 만들어 보았습니다.

동물의숲카드_물고기.z01
10.00MB
동물의숲카드_물고기.z02
10.00MB
동물의숲카드_물고기.zip
6.19MB

 

용량 관계상 분할 압축을 하였는데요. 다운 받으시고 압축을 해제하여 보시면 pdf 로 예쁘게 만들어져 있는 것을 보실 수 있습니다.

 

짧지 않은 시간이었지만 이렇게 해서 아이들이 가지고 놀 수 있는 동물의 숲 물고기 놀이 카드가 완성이 되었습니다.

아이들과 너무 재미있게 놀았기에 고생한 보람을 느낍니다.

이제 자동화를 위한 틀이 만들어 졌으므로 해산물 카드라든지, 다른 것들도 쉽게 추가 할 수 있을 것으로 생각합니다.

꼭 동물의 숲 카드 만들기가 아니더라도 포토샵을 이용하여 다양한 속성과 정보를 변경해 가면서 이미지를 제작해야 하는 경우라면 참고하실만한 레퍼런스가 되기를 바랍니다.

 

감사합니다.

 

실제 동물의 숲 카드 놀이를 하는 내용은 아래 포스트를 참고해 주세요

2021/01/02 - [DIY] - [아빠가 만든][집콕놀이] '동물의 숲' 카드 놀이 만들기

 

[아빠가 만든][집콕놀이] '동물의 숲' 카드 놀이 만들기

코로나로 인해 수업도 온라인으로 하고 저 역시 재택근무를 하고 있습니다. 요즘 코로나 감염 수준이 높아져 2.5 단계로 거리두기가 격상 되면서 아이들이 집안에만 머무르게 되고 날씨까지 추

diy-dev-design.tistory.com

2019/12/04 - [DEV/Adobe Script] - [포토샵스크립트] Instagram 용 파노라마 사진 자르기

 

[포토샵스크립트] Instagram 용 파노라마 사진 자르기

Instagram, 요즘 가장 핫한 SNS 가 아닐까 싶습니다. 지하철에서 무심코 주변을 보니 눈에 보이는 핸드폰 화면 마다 Instagram 화면이 보이는 것을 보고 깜짝 놀랐습니다. 난 안하는데... 어쨌든 Instagram

diy-dev-design.tistory.com

2019/06/10 - [DEV/Adobe Script] - [포토샵 스크립트] 강좌, 무작정 따라해보기

 

[포토샵 스크립트] 강좌, 무작정 따라해보기

어도비 포토샵은 자체 스크립트를 이용하여 다양한 기능을 수행할 수 있는 툴을 지원합니다. 언어는 자바 스크립트 이며 작성된 자바스크립트를 포토샵에서 실행하는 방법과 Extend Script Tool Kit

diy-dev-design.tistory.com

2019/12/13 - [DEV/Adobe Script] - [포토샵스크립트] PSD 모든 레이어 자동 저장, 하위 폴더 포함 (레이어 크기로 이미지 저장)

 

[포토샵스크립트] PSD 모든 레이어 자동 저장, 하위 폴더 포함 (레이어 크기로 이미지 저장)

안녕하세요. 제가 포토샵 스크립트를 이용하여 PSD 파일내의 모든 레이어를 자동으로 하위폴더 구조를 유지하며 저장할 수 있는 스크립트를 만들어서 올렸었는데요. 바로 아래 링크에서요. https:

diy-dev-design.tistory.com

 

2020/12/17 - [DIY] - [아빠의요리] 코로나 집콕 간식 '감동란' 만들어 주기

 

[아빠의요리] 코로나 집콕 간식 '감동란' 만들어 주기

TV 를 켜면 맨날 쉐프들이 나와서 멋들어진 말솜씨와 요리솜씨로 눈을 자극하는데요, 요즘 시대엔 아빠들도 약간의 요리쯤 할수 있어야 하지 않을까? 싶어서 포스팅을 합니다. 요즘 코로나로 인

diy-dev-design.tistory.com

 

반응형
반응형

내 컴퓨터에 생각지도 못하였던 드라이브 용량을 잡아먹는 괴물이 있다면 어떠신가요? 

디자이너분들이라면 한번쯤 점검을 해봐야 하는 부분인데요.

바로 포토샵 임시파일입니다.

 

무려 2.3GB 에 달하는 포토샵 임시파일

 

저는 저 파일을 늘상 관리를 하고 있기 때문에 사실상 문제가 되지 않는데요. 별 생각없이 사용하다보면 저녀석이 temp 폴더 안에 마구잡이로 늘어나게 됩니다.

어떤 경우에는 저 파일이 누적되어 몇십 GB 씩 차지하기도 하니 적당히 넘어갈 녀석이 아닌건 확실합니다.

일단 photoshop temp 파일은 포토샵의 특성상 막을 수 없는 파일입니다. 포토샵은 빠른 그래픽 처리를 위하여 이미지 정보 및 각종 포토샵 실행중 기록을 저 임시파일안에 저장하게 됩니다. 그러니 포토샵을 실행하고 작업을 하다보면 당연히 생기는 파일입니다. 물론 포토샵이 종료될때 해당 파일도 함께 사라지게 됩니다.

문제는 포토샵이 정상 종료 되지 않을때 입니다.

포토샵이 늘 사용하는 입장에서는 안정적인 프로그램이라고 보기는 어렵거든요. 물론 최근 CC 버전 이후로는 성능이나 안정성이나 상당히 좋아졌기는 합니다만 어쨌든 원하지 않게 컴퓨터를 비정상 종료해야 하는 경우가 포토샵이 원인이 아니더라도 언제나 발생할 수 있지 않겠습니까?

포토샵이 비정상 종료되면 해당 파일은 삭제 되지 않은 채 다음번 포토샵 실행 시 또다른 임시파일을 생성하게 됩니다. 

이렇게 몇차례 반복되면 임시파일의 개수가 많아지며 C 드라이브의 용량을 많이 차지하게 됩니다.

 

오늘은 간단한 배치파일을 하나 만들어서 주기적으로 실행하는 것으로 해당 파일을 삭제하여 C 드라이브에 죽치고 있는 대용량 임시파일인 photoshop temp 파일을 제거하는 배치파일 스크립트를 하나 소재해 드릴까 합니다.

참고로 임시파일의 경로는 아래와 같습니다.

C:\Users\사용자\AppData\Local\Temp\

 

1. 메모장을 연다

2. 아래의 코드를 복사하여 메모장에 넣는다
del "C:\Users\사용자\AppData\Local\Temp\Photoshop Temp*.*"

3. c:\사용자\ 아래에 있는 본인 계정의 이름을 위 코드의 "사용자" 부분에 넣는다.
제컴퓨터의 사용자 이름은 cindy 인데요. 아래와 같이 보이게 되겠죠?

현재 사용자의 이름을 확인하여 넣어준다.

4. 해당 파일을 적당한 이름으로 저장한 뒤 맨뒤에 확장자를 .bat 로 변경한다.

5. 생각날때 마다 한번씩 더블클릭!

바탕화면에 해당 배치파일을 두고 사용중임

간단하지 않습니까? 

이렇게 하면 포토샵 임시파일을 temp 폴더내에서 실행할때마다 싹 지울 수 있습니다.

 

참고로 temp 폴더는 photoshop 뿐만 아니라 윈도우에서 실행되는 아주 많은 프로그램들이 자주 사용하는 임시 저장공간 입니다. photoshop 외의 다른 많은 프로그램들이 임시파일을 저장하기 때문에 용량이 쉽게 차게 되는데요. 디스크 정리를 간간히 실행해 주시는 것도 좋은 방법입니다. 

임시파일을 정리하는 방법은 C:\ 드라이브 에서 마우스 우클릭 --> 속성

위 사진에서 디스크 정리를 눌러 주시고요

스크롤을 내려보면 임시파일 이라는 항목이 있습니다. 저는 며칠전에 포멧을 하였기 때문에 하당 용량이 얼마 없지만 오랜시간 디스크 정리를 하지 않으셨다면 상당한 용량이 저장되어 있을 수 있습니다.

 

이상으로 포토샵 임시파일을 삭제하는 간단한 배치파일을 만드는 방법을 소개해 드렸습니다

 

2020/12/03 - [DEV/Adobe Script] - [illustrator script] 일러스트도 스크립트가 되나요?

 

[illustrator script] 일러스트도 스크립트가 되나요?

네! 당연히 됩니다. 일러스트레이터에서 스크립트를 사용할 수 있게 되면 진정 놀라운 결과들을 만들어 낼 수 있습니다. 사람이 손으로 하기에는 정말 귀찮은 작업들을 가능하게 만들어 줍니다.

diy-dev-design.tistory.com

2019/06/10 - [DEV/Adobe Script] - [포토샵 스크립트] 강좌, 무작정 따라해보기

 

[포토샵 스크립트] 강좌, 무작정 따라해보기

어도비 포토샵은 자체 스크립트를 이용하여 다양한 기능을 수행할 수 있는 툴을 지원합니다. 언어는 자바 스크립트 이며 작성된 자바스크립트를 포토샵에서 실행하는 방법과 Extend Script Tool Kit

diy-dev-design.tistory.com

2019/12/13 - [DEV/Adobe Script] - [포토샵스크립트] PSD 모든 레이어 자동 저장, 하위 폴더 포함 (레이어 크기로 이미지 저장)

 

[포토샵스크립트] PSD 모든 레이어 자동 저장, 하위 폴더 포함 (레이어 크기로 이미지 저장)

안녕하세요. 제가 포토샵 스크립트를 이용하여 PSD 파일내의 모든 레이어를 자동으로 하위폴더 구조를 유지하며 저장할 수 있는 스크립트를 만들어서 올렸었는데요. 바로 아래 링크에서요. https:

diy-dev-design.tistory.com

2020/01/20 - [분류 전체보기] - Excel Automate , 엑셀 자동화 프로그램

 

 

반응형
반응형

네! 당연히 됩니다.

일러스트레이터에서 스크립트를 사용할 수 있게 되면 진정 놀라운 결과들을 만들어 낼 수 있습니다. 사람이 손으로 하기에는 정말 귀찮은 작업들을 가능하게 만들어 줍니다.

이런 이미지를 손으로 만들어 본다고 치면요. 일단 배치되는 모든 사각형의 각도도 랜덤이고, 사각형의 색상이 하나도 연속으로 동일한게 없다면요.. 머리가 벌써 아파오죠?

하지만 스크립트를 이용하면 저것보다 수백배 복잡한 것도 손쉽게 해낼 수 있답니다.

막상 해보면 일러스트야 말로 진정한 노가다 툴이 아닐 수 없습니다. 

패스 하나하나 손으로 그려야 하며 그려야 하는 패스가 정형화 된 스타일일 수록 피곤해 집니다.

 

 

 

자 그럼 일러스트 스트립트 어떻게 해야 할까요?

일단 포토샵스크립트와 동일하게 javascript 를 기반으로 동작합니다. MAC OS 에서는 apple script 를 지원하고 WindowOS 에선 VBA 도 지원하지만 공용으로 사용할 수 있는 javascript 가 적당해 보입니다. 문법도 포토샵 스크립트와 크게 다르지 않으니 일단 javascript 의 기본을 알고 계시면 금방 시작하실 수 있습니다.

 

일러스트는 기반이 벡터 그래픽이다 보니 어쩌면 스크립트라는 형식 자체가 포토샵보다 적용 가능한 부분이 많습니다. 포토샵이 이미지를 메모리에 얹어 놓고 메모리 안의 이미지를 이미지 프로세싱을 통해 변화를 주다 보니 스크립트와 같이 성능에 제약적인 개발언어로 할 수 있는게 많이 없습니다. 하지만 일러스트는 모든 데이터가 벡터 그래픽이다 보니 아주 많은 영역에 대하여 스크립트로 할수 있는 여지가 있는 것이죠.

 

먼저 extend script toolkit 을 준비하시고요. 

그 다음은 전과 마찬가지로 필요한 액션을 작성해 나가시면 됩니다. 포토샵 스크립트와 비슷 한 느낌 입니다.

var cDoc = app.activeDocument;
alert(cDoc.name)

비슷하지요? 다만 태생이 포토샵과 다르다 보니 스크립트를 작성하는 방식이 약간은 다릅니다.

포토샵은 app 안에 document 개체를 찾고 그 안에 layer 또는 Artlayer 로 접근하여 layer 안의 오브젝트의 속성을 조정하는 것이 일반적인 방식인데요. 일러스트는 app 안에 document 를 찾는 것 까지는 같지만 레이어로 접근하지 않고도 스크립트에서 바로 개체로 접근이 가능합니다.

var cDoc = app.activeDocument;
var mItem_01 = cDoc.pageItems[0]
var mItem_02 = cDoc.layers[0].pageItems[0]

 

또 레이어 안에 shape 의 종류만 해도 pageItem, pathItem, compoundPathItem, GroupItem 과 같이 다양한 개체가 있으며 그외에도 textItem 이나 다양한 개체가 존재합니다. 

또 위에서 설명드린 개체들 중 pageItem 은 모든 개체를 통털어 일컬을 수 있는 녀석이기도 합니다.

예를들면 layer 안에 두개의 groupItem 과 한개의 pathItem 이 있다고 했을때 이것은 3개의 pageItem 이 있는 것으로 처리되기도 합니다. 즉 pageItem 이라는 개념은 종류를 불문하고 어떤 하나의 속성을 갖는 개체로 정의되는 것이지요. 그래서 코딩할 때도 각각의 개체의 타입이 무엇인지 정확히 파악하여 코딩을 해야 합니다.

var cDoc = app.activeDocument;
s = cDoc.selection

for (var i = 0; i < s.length; i++)
{
    var cItem = s[i];
    if (cItem.typename == "pathItem")
    {
        alert("pathItem")
    }
    else if (cItem.typename == "GroupItem")
    {
        alert("groupItem")
    }
    else
    {
        alert("another Item")
    }
 }

선택한 개체들이 어떤 종류의 개체인지 확인하는 간단한 코드 예제.

위에 열거한 개체들 중 가장 하위 개념인 pathItem 은 그안에 PathPoints 라는 Pathpoint 들의 그룹을 갖습니다. PathPoint 는 예상하신 것처럼 우리가 알고 있는 점 을 말하지요. PathPoint 안에도 anchor 와 leftDirection, rightDirection 과 같은 속성들도 구성되므로 상당히 체계적으로 코드를 작성해야 정상적으로 동작이 됩니다.

예를 들면 패스 내에 있는 하나의 점은 다음과 같이 정의 되는 것이죠.

var cDoc = app.activeDocument;
var cLyr = cDoc.layers[0]; // layer 개체
var cItem = cLyr.pageItems[0]; // pageItem 개체
var cPath = cItem.pathItems[0]; // pageItem 이 GroupItem 이라는 가정하에.. pathItem 개체
var firstPoint = cPath.pathPoints[0]; // pathPoint 개체
var cPt = firstPoint.anchor; // Array (x, y) = [x, y] 와 같은 2개 짜리 1차원 배열
var cPt_leftHandle = cPt.leftDirection; // Array (x, y) = [x, y] 와 같은 2개 짜리 1차원 배열
var cPt_rightHandle = cPt.rightDirection; // Array (x, y) = [x, y] 와 같은 2개 짜리 1차원 배열

 

일러스트는 벡터 그래픽이다 보니 자동으로 뭔가를 그리려면 벡터 연산이 필수 입니다.

중고등학교 수학을 열심히 했다면 할만 하지만 놀았다면 어려운 수준의 수학적 지식이 필요합니다. 간단한 삼각함수와 2차원 평면에서의 함수와 도형 등의 주제에 대한 이해가 조금은 필요합니다.

어쩌면 선형 대수학과 같은 고급 수학에 정통한 분들은 아주 빠르게 습득이 가능할 겁니다.

프로그래밍을 배우려면 어쩔 수 없는 부분이니 이참에 공부해 보시는 것도 괜찮습니다. 너도 예체능계를 나왔기 때문에 수학은 완전 잼병이었는데요, 막상 필요하니 하게 되더랍니다.

 

어쨌든 일러스트 스크립트 크게 어려울 것은 없으니 이번에 마음 잡고 도전해 보시기 바랍니다.

저도 본 블로그를 통해 틈틈히 요긴한 강좌를 올리도록 하겠습니다.

 

그럼 이만~

 

2019/06/12 - [DESIGN] - 일러스트 이미지 소스

 

일러스트 이미지 소스

일러스트레이터 스크립트로 만들어진 이미지 몇장 올린다. 다각형을 화면에 배치한 이미지이며 필요한 경우 마음 껏 사용해도 됨 원본 벡터 이미지도 올리니 필요하면 가져가시고 커스터 마이

diy-dev-design.tistory.com

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

 

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

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

diy-dev-design.tistory.com

2019/06/10 - [DEV/Adobe Script] - [포토샵 스크립트] 강좌, 무작정 따라해보기

 

[포토샵 스크립트] 강좌, 무작정 따라해보기

어도비 포토샵은 자체 스크립트를 이용하여 다양한 기능을 수행할 수 있는 툴을 지원합니다. 언어는 자바 스크립트 이며 작성된 자바스크립트를 포토샵에서 실행하는 방법과 Extend Script Tool Kit

diy-dev-design.tistory.com

 

반응형
반응형

안녕하세요. 오늘은 엑셀 리스트로 가지고 있는 웹 이미지 경로를 이용하여 일괄 다운로드 하는 방법을 소개해 드릴까 합니다. 

인터넷에 찾아보면 이런저런 다운로더들이 있는데요. 입맛에 맞는 프로그램을 찾는 것도 일이고 프로그램이 원하는 형식으로 다운로드용 이미지 리스트를 작성하는것도 번거롭더군요.

이미 엑셀로 이미지 리스트의 웹 주소가 있는데 그냥 엑셀만으로 다운로드 할 수 있을까 해서 좀 찾아 보았습니다. 찾아보니 괜찮은 레퍼런스들이 좀 있었는데요. 사용하기 번거로워 보여 직관적으로 손쉽게 사용할 수 있도록 코드를 좀 손보았습니다.

사실 제가 필요했던 상황이기도 해서 당장 급하게 찾았던 것인데 시간도 없고 별도 프로그램 찾는것 보다 레퍼런스를 이용해서 직접 수정해서 코딩하는게 더 빠르더군요.

저의 경우에는 무려 7000 장 이상의 이미지를 로컬로 내려받아서 확인을 해야 하는 상황이었는데요. 개발팀에 요청하니 4일이나 걸린다고 하더군요. 물론 그 분들도 다른 일정이 있었기 때문이었겠지만 저는 그렇게 기다릴 수는 없었습니다.

 

일단 저의 경우를 기준으로 설명드릴 수 는 없고 일반적인 상황을 가정해 보겠습니다.

엑셀의 A열에 이미지 7000장의 인터넷 경로가 있습니다. 

엑셀의 B 열에는 로컬에 저장되어야 할 이미지 파일명을 준비해 놓았다고 하면 아래의 코드로 간단하게 다운로드 할 수 있습니다.

 

 

엑셀을 이용하여 일괄 이미지 다운로드 하는 방법

 

alt + F11 을 눌러 vba 창을 열어준 뒤 아래 코드를 현재 통합 문서의 스크립트 창에 붙여 넣어 주세요.

그런다음 이미지 주소가 들어있는 열의 첫번째 셀의 이름, 저장할 이미지가 들어있는 열까지의 offset 등을 설정해 준뒤 F5 키를 눌러 실행해 주면 됩니다. 이때 키보드 커서가 Sub 함수 안에 있어야 바로 실행이 되고요, 그렇지 않은 경우 실행할 함수를 한번 선택해주는 창이 뜰텐데 downloadAllImage 를 선택해 주시면 됩니다.

Option Explicit

Sub downloadAllImages()

    Dim asht As Worksheet
    Dim rngA As Range
    Dim c As Range
    Dim sPath As String
    Dim extensions() As String
    
    Set asht = ActiveSheet
    Set rngA = asht.Range("a2") ' 이미지 리스트가 존재하는 첫번째 셀 '
    
    Set rngA = asht.Range(rngA, rngA.End(xlDown))
    
    sPath = "d:\ImageAutoDownload_test\\" ' 저장할 경로를 넣으세요'
    
    For Each c In rngA
        Dim myURL As String
        If Len(c.Value) Then
            Dim imgName As String
            
            imgName = c.Offset(0, 1).Value   ' 이미지별 저장할 이름이 기록된 열 '
            
            myURL = c.Value
            extensions = Split(myURL, ".") ' 확장자가 3글자가 아닐수도 있으므로 확장자를 판별해내기위한 배열 생성
                
            imgName = imgName & "." & extensions(UBound(extensions)) '위에서 구한 배열에서 확장자를 꺼내자
            
            WebFileDownload myURL, imgName, sPath
            
        End If
    
    Next c

End Sub


Public Function WebFileDownload(ByVal strURL As String, ByVal saveFileName As String, ByVal savepath As String) As Boolean
    Dim Buf() As Byte, oWinHttp
On Error GoTo Err_Sub
    Set oWinHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
    With oWinHttp
        .Open "GET", strURL, 0
        .Send
        Buf = .ResponseBody
    End With
    Open savepath & saveFileName For Binary Access Write As #1
    Put #1, , Buf
    Close #1
       
    Set oWinHttp = Nothing
       
Err_Sub:
    If Err Then MsgBox Err.Description
    If Not oWinHttp Is Nothing Then Set oWinHttp = Nothing
    
End Function

 

어떠신가요? 복잡하지 않죠? 정상적으로 코드를 옮기고 세팅을 하셨다면 아마 잘 동작하실 겁니다.

 

이미지 7000 장을 하나하나 링크 복사해서 브라우저에 붙여넣고 다른이름으로 저장하고... 또 복사하고 붙여넣고 다른이름으로 저장하고... 했을걸 생각하면 정말 토나오는 일이지요. 만약 정말 일일이 수동으로 위와 같이 진행했다면 몇 일을 해야 했을 지도 모릅니다.

저의 경우엔 7000장 내려받는데 코딩하는 시간을 포함해서 20분만에 끝났습니다. ^^

이런게 바로 디자이너면서 개발하는 맛이지요. 

 

어쨌든 다운로드할 이미지 리스트를 가지고 계신데 적당한 툴이 없어 고민이셨던 분이 있으시다면 도움이 되었길 바랍니다.

 

2022-2-24일 수정

확장자가 3글자가 아닌 경우도 있을 수 있어 주소에서 유동적으로 확장자를 가져올 수 있도록 수정하였습니다.

'선택적 인수가 아닙니다.' 라는 오류가 나는 부분이 있어 내용 수정하였습니다. 함수 호출 시 저장할 경로인 sPath 가 누락되어 있었네요. 

 

 

2020/08/27 - [DEV/VBA] - 재택근무 필수 엑셀 "자리안비움" - 윈도우 꺼짐 방지

2020/06/22 - [DEV/VBA] - [vba] 초등학교 연산 자동 문제집 - 곱셈 추가

2020/01/08 - [DEV/c#] - Excel Automate, 엑셀 자동화 프로그램

2019/10/01 - [DEV/VBA] - [VBA] 엑셀 VBA로 포토샵 연동이 가능할까?

 

반응형

+ Recent posts