[익스프레션] 반응형 박스 자막 만들기(3)

반응형 박스 자막에서 포인트 텍스트 설정하기

After Effect Blender expression Premiere 모션 그래픽 템플릿 애프터이펙트 익스프레션 프리미어

영상에서 자막 작업을 할 때 강조하고 싶은 단어나 구절 등을 포인트로 디자인하는 경우가 많이 있습니다. 이번에는 텍스트에 포인트를 주고 싶은 부분이 하나 있는 경우에 대해 만들어보겠습니다.

모션 그래픽 템플릿으로 프리미어에서 자막 작업을 할 때 텍스트 입력란을 프리미어로 빼더라도 텍스트의 컬러를 컨트롤 할 수가 없습니다.

그래서 애프터 이펙트에서 별도로 컬러를 컨트롤 할 수 있도록 속성을 빼줘야 하는데 텍스트의 컬러 속성을 빼는 방법부터 이야기 해보죠.

애프터 이펙트 텍스트 레이어의 컬러 속성

1. style과 setFillColor()

텍스트 레이어에서 텍스트의 속성들을 익스프레션으로 정의할 때는 style을 붙여야 합니다. 텍스트 레이어의 Source Text에 다음과 같이 익스프레션을 작성해보세요.

text.sourceText.style.setFontSize(90).setFillColor([1,0,0]);
//텍스트의 소스텍스트의 스타일을 정의하겠다고 선언한 뒤 정의하고자 하는 스타일들을 set합니다.

이 코드는 현재 입력된 텍스트의 스타일을 폰트 사이즈는 90pt, 텍스트 컬러는 RGB컬러 [1, 0, 0] 즉, 빨간색으로 바꾸는 코드입니다.
애프터 이펙트의 setFillColor에서는 RGB의 각 채널의 값 0~255를 0~1로 치환하고, 각 채널의 값을 배열로 만든 값을 받습니다. 배열로 값을 받기 때문에 이미 적용된 컬러에서 R, G, B 채널에 해당하는 각각의 값들을 fillColor[0], fillColor[1], fillColor[2]로 불러와서 다른 작업들을 진행할 수도 있습니다.

RGB에 대한 간단한 내용(궁금하신 분만 펼쳐보세요)

RGB는 빛의 삼원색을 이용해서 색을 표현하는 방식으로 빨강(RED), 초록(GREEN), 파랑(BLUE) 세 종류의 빛을 혼합해서 색을 만들어내는 방식인데 색을 섞을수록 밝아지기 때문에 ‘가산 혼합’이라고 합니다.
R,G,B 각 채널의 값이 0~255까지 있으며, 모든 채널이 0인 경우 빨간색, 초록색, 파란색 빛이 모두 없으므로 검정색을 나타내게 되죠.
따라서 (0, 0, 0)은 검정색을 뜻합니다. 반대로 모든 채널의 값이 255라면(255, 255, 255) 흰색을 표현하게 됩니다.

HEX에 대한 간단한 내용(궁금하신 분만 펼쳐보세요)

HEX는 간단하게 RGB를 16진법으로 바꾸고 #을 붙여서 표현하는 방법입니다.

예를 들어 #F326FF에서 각 2개씩이 R, G, B 채널의 값을 가집니다. 여기에서 R 채널의 값은 F3(16)=15*16+3*1=243이 되고, G채널의 값은 26(16)=2*16+6*1=38, B채널의 값은 FF(16)=15*16+15*1=255이 됩니다. 따라서 #F326FF는 RGB로 표현하면 (243, 38, 255)라는 값이 되겠죠. 그리고 setFillColor에 입력하기 위해 배열로 표현하면 [243, 38, 255]라는 값으로 바꿀 수 있고, 범위를 0~1로 치환하면 [243/255, 38/255, 255/255]=[0.952941…, 0.149019…, 1]이렇게 바꿀 수 있습니다.

만약 #F326FF를 setFillColor에 적용한다면 이렇게 쓸 수 있습니다.

text.sourceText.style.setFontSize(90).setFillColor(hexToRgb("F326FF"));
//hexToRgb는 hex코드로 표현된 값을 RGB 배열로 바꿔줍니다. 그리고 이때 HEX코드는 문자열(""붙여서)로 넣어줍니다.

그럼 이렇게 색이 바뀝니다.

결론적으로 setFillColor를 적용할 때 일일히 다 계산해서 원하는 색을 입력하기는 매우 어렵습니다. 그래서 우리는 Effects에 있는 Color Control을 사용해서 간단하게 작업해보겠습니다.

2. Color Control

먼저 첫 시간에 작업했던 파일을 열고 새롭게 조정 레이어를 추가해보겠습니다. 이름은 TEXT_Control이라고 해보겠습니다.

그리고 Effects에서 control을 입력해서 Color Control을 찾아서 조정레이어에 넣겠습니다. (처음 들어갈 때는 빨간색으로 들어갈텐데 색은 적당히 바꿔주세요. 그리고 이름도 FontColor라고 바꿔주세요.)

그리고 텍스트 레이어의 익스프레션으로 방금 만든 FontColor를 변수로 만들고 setFillColor에 넣어줍니다.

const fontColor = thisComp.layer("TEXT_Control").effect("FontColor")("Color");
//text.sourceText.style.setFontSize(90).setFillColor(hexToRgb("F326FF"));
//fontColor 값이 RGB로 자동 계산되어서 들어갑니다.
text.sourceText.style.setFontSize(90).setFillColor(fontColor);

제대로 적용되었으면 이제 FontColor의 컬러를 한 번 바꿔보세요.

컬러가 잘 바뀌는 것을 볼 수 있습니다. 그리고 FontColor의 Color값을 Essential Graphics 패널에 추가해서 템플릿을 만든다면 프리미어에서도 컬러를 컨트롤할 수 있습니다.

텍스트에서 포인트 텍스트 컬러 바꾸기 기본 원리

애프터 이펙트 2025부터는 텍스트 레이어의 소스텍스트의 익스프레션에 메소드가 생겼습니다. 따라서 이 메소드를 이용해서 텍스트의 특정 부분의 컬러를 바꿀 수가 있습니다.

방법은 매우 심플합니다. setFillColor에서 value뒤에 시작 값과, 색칠할 텍스트의 개수를 입력하면 됩니다.

const fontColor = thisComp.layer("TEXT_Control").effect("FontColor")("Color");
//setFillColor(value, s = start index, n = number of characters)로 입력해 텍스트 색을 바꾸는 시작 문자열과 몇 개의 글자를 색칠할 지를 입력해주면 됩니다.
text.sourceText.style.setFontSize(90).setFillColor(fontColor, 4, 3);
//전체 텍스트 중에 5번째 글자부터 3개의 글자에만 setFillColor를 적용합니다.
//start는 index값이므로 0부터 카운트됩니다. 즉, 첫 글자의 인덱스 값은 0입니다.

우리가 지정한 부분만 색이 바뀐 것을 확인할 수 있습니다.

애프터 이펙트 2025 아래 버전(클릭해서 숨겨진 내용을 확인해보세요.)

애프터 이펙트 2024 버전까지는 익스프레션으로 텍스트의 특정 부분만 선택해서 컬러를 바꾸는 방법이 없었습니다. 그래서 애니메이트를 이용해서 바꿨습니다.
애니메이터를 하나 추가해보겠습니다.

이렇게 에니메이터를 추가하면 Fill Color와 레인지 셀렉터가 하나 추가됩니다.

에니메이터의 레인지 셀렉터를 열고, Advanced에서 유닛을 인덱스로 바꾼 뒤, 덫니메이터의 레인지 셀렉터를 열고, Advanced에서 유닛을 인덱스로 바꾼 뒤, 덧칠할 색을 바꾸고, 레인지 셀렉터의 Start와 End 값을 바꿔보세요. 그러면 레인지 셀렉터에 지정된 위치의 폰트 컬러가 바뀌게 됩니다.

하나의 에니메이터에서 추가할 수 있는 속성들이 무엇이 있는지 살펴보세요.

Add버튼으로 에니메이터에 다른 속성을 추가할 수 있습니다.
에니메이터에 추가할 수 있는 속성들
에니메이터에 추가할 수 있는 셀렉터

에니메이터에서 Fill Color외에 스트로크, 스트로크 컬러, Tracking(자간)등 다양한 속성들을 추가할 수 있고, 셀렉터에서는 레인지 셀렉터를 추가할 수도 있습니다. 레인지 셀렉터를 추가하면 두 개 이상의 포인트 텍스트를 작업할 수도 있겠죠? 하지만 폰트 사이즈의 경우 추가할 수 없고, 대신에 Scale과 Tracking을 추가해서 포인트 텍스트들을 디자인해서 사용했었습니다.

에니메이터는 사실 이름처럼 텍스트에 에니메이션을 주기 위해 만들어진 기능입니다. 노래방에서 반주에 따라 텍스트 컬러가 점차 바뀐다던가 하는 텍스트 에니메이션을 주기 위해 만들어진 기능이죠. 근본적으로 좋은 방법은 아니었습니다. 하지만 애프터 이펙트 2024까지는 익스프레션으로 텍스트의 부분에 접근할 수 없었으므로 유일한 방법이기도 했습니다.

포인트 텍스트 자동화 익스프레션 만들기

그런데 포인트 텍스트가 있을 때마다 익스프레션 코드를 수정해야 하는 단점이 있습니다. TEXT_Control레이어에 슬라이더 콘트롤을 두 개 추가해서 시작 값과, 문자 수를 변수로 만들어 다음과 같이 연결해 주는 방법도 있습니다.

const fontColor = thisComp.layer("TEXT_Control").effect("FontColor")("Color");
//포인트 텍스트의 시작값과 색칠할 문자열의 수를 변수화하여 적용
//TEXT_Control레이어에 슬라이더 콘트롤 두개 넣어서 적용
s = thisComp.layer("TEXT_Control").effect("PointTextStartIndex")("Slider");
n = thisComp.layer("TEXT_Control").effect("PointTextLength")("Slider");

text.sourceText.style.setFontSize(90).setFillColor(fontColor, s, n);

그런데 이 방법도 포인트 텍스트가 있을 때마다 시작 값과 몇 글자를 색칠할 지 일일히 계산해서 값을 바꿔줘야 한다는 단점이 있습니다.

자바스크립트 indexOf() 사용해서 자동화하기

자바스크립트의 indexOf() 메서드는 배열 또는 텍스트에서 특정 문자열과 일치하는 부분을 찾아 있으면 특정 문자열이 나타나는 첫 번째 인덱스 값을 반환해주고, 만약 특정 문자열이 없다면 -1을 반환해줍니다.

const beasts = ["ant", "bison", "camel", "duck", "bison"];
beasts.indexOf("bison");
//배열의 2번째 원소에 "bison"이 있으므로 1을 반환합니다.
//배열의 첫번째 원소의 index는 0입니다.

cosnt totalText = "포인트 텍스트를 찾아볼까요?";
totalText.indexOf("텍스트를");
//전체 텍스트 중에서 '텍스트를'은 5번째 글자부터 시작합니다.
//이때 인덱스는 4입니다.(인덱스는 0부터 시작합니다.)
//그러므로 4를 반환합니다.

const totalText = "포인트 텍스트가 이 문장에 없다면?";
totalText.indexOf("여기에");
//전체 텍스트 중에 '여기에'라는 텍스트는 없습니다.
//그러므로 -1을 반환합니다.

자바스크립트의 length는 배열의 길이(배열의 원소의 개수) 또는 문자열의 길이(문자열의 텍스트 개수)를 알려줍니다.

const beasts = ["ant", "bison", "camel", "duck", "bison"];
beasts.length;
//5
//beasts 배열의 원소가 5개 들어 있습니다.
const totalText = "포인트 텍스트가 이 문장에 없다면?";
totalText.length;
//19
//totalText의 문자가 19개 있습니다.
//띄어쓰기나 줄바꿈도 카운트 됩니다.

이번에는 자바스크립트의 indexOf 메서드를 이용해서 작업을 하겠습니다.
먼저 텍스트 레이어를 2개 추가하고, 가이드 처리한 뒤, 레이어 이름을 바꿔보겠습니다.

1. 기존에 있던 텍스트 레이어는 RendeText로 이름을 바꿨습니다.
2. control을 담당했던 조정 레이어의 이름도 RenderText_Control로 바꿨습니다.
3. 텍스트 레이어를 2개 추가하고 이름을 바꿨습니다.
4. 레이어 2개가 가이드 처리되어 실제 렌더링을 하거나 모션 그래픽 템플릿으로 Export 시킬 때 텍스트가 화면에서 숨겨집니다.
레이어를 선택하고 마우스 우클릭으로 가이드 레이어 처리를 합니다.

Text 레이어에 입력된 텍스트를 RenderText레이어에서 출력할 것이고, PointText에 입력된 단어를 RenderText에서 출력하기 전에 찾아서 다른 색을 적용해서 출력할 것입니다.
이때, RenderText는 Text레이어에 입력한 텍스트를 출력할 것이므로 setText()로 텍스트를 출력해야 합니다.

const fontColor = thisComp.layer("RenderText_Control").effect("FontColor")("Color");
//s는 Text레이어에 입력된 텍스트(text.sourceText)에서 indexOf로 PointText에 입력된 텍스트를 찾아 인덱스 값을 출력합니다.
s = thisComp.layer("Text").text.sourceText.indexOf(thisComp.layer("PointText").text.sourceText);
//n은 PointText에 입력된 텍스트의 글자 수(length)로 정의합니다.
n = thisComp.layer("PointText").text.sourceText.length;
//setFillColor(value, s = start index, n = number of characters)에서 s와 n값을 적용합니다.
text.sourceText.style.setFontSize(90).setFillColor(fontColor, s, n).setText(thisComp.layer("Text").text.sourceText);
//다른 레이어의 텍스트를 출력할 때는 setText()를 호출합니다.

RenderText의 Source Text의 익스프레션을 이렇게 바꿔주세요. 그리고 PointText에 입력된 텍스트를 바꿔가면서 확인해보세요.

만약 PointText에 입력된 텍스트를 Text에서 찾을 수 없다면 s=-1을 출력하고 n=PointText의 문자열 수를 출력하므로 예기치 못한 오류가 발생하게 됩니다.
따라서 코드에서 예외 처리를 해주어야 합니다. 만약 s가 -1을 출력한다면 n=0으로 고정시켜서 색칠되는 부분이 없도록 코드를 수정해주면 됩니다.

const fontColor = thisComp.layer("RenderText_Control").effect("FontColor")("Color");
s = thisComp.layer("Text").text.sourceText.indexOf(thisComp.layer("PointText").text.sourceText);
//만약 s가 -1이면(포인트 텍스트와 일치하는 텍스트가 없다면) n=0, 그 외의 경우는 PointText 레이어에 입력한 글자 수를 출력
if (s === -1) {
	n = 0;
} else {
	n = thisComp.layer("PointText").text.sourceText.length;
}

//if~else 구절에서 중괄호로 값을 출력해야합니다.
//if(조건문){조건문이 참일 때}else{조건문이 거짓일 때}
text.sourceText.style.setFontSize(90).setFillColor(fontColor, s, n).setText(thisComp.layer("Text").text.sourceText);

예외 처리를 하지 않더라고 사용하는 데는 크게 문제는 없습니다. 짧은 영상이나 이 자막을 많이 쓰지 않는다면 작업할 때 신경을 조금 더 쓰면 되니까요.
작업을 잘하면 되는거죠. 다만 검수를 보다가 놓치는 부분이 발생할 수 있으니 많은 양의 작업을 할 때는 신경을 조금 덜 쓸 수 있도록 예외 처리를 해두는 것이 좋습니다.

이 코드를 보니 중복된 부분이 많아서 코드를 가독성 있게 정리를 조금하겠습니다.

간단하게 값을 출력하는 if~else 구절의 경우 삼항연산자로 간단하게 표현할 수도 있습니다.

조건문 ? A : B
//조건문이 참이면 A, 거짓이면 B를 출력합니다.
const fontColor = thisComp.layer("RenderText_Control").effect("FontColor")("Color");
//중복해서 입력했던 부분 변수로 바꾸기
const renderText = thisComp.layer("Text").text.sourceText;
const pointText = thisComp.layer("PointText").text.sourceText;

s = renderText.indexOf(pointText);

//if~else구절 삼항연산자로 표현
(s === -1) ? n = 0 : n = pointText.length;

text.sourceText.style.setFontSize(90).setFillColor(fontColor, s, n).setText(renderText);

코드가 보기 좋게 정리되었습니다. 이제 다시 테스트 해보면 잘 동작하는 것을 확인할 수 있습니다. setFontSize에도 동일한 구간에만 적용해보겠습니다.

const fontColor = thisComp.layer("RenderText_Control").effect("FontColor")("Color");
//중복해서 입력했던 부분 변수로 바꾸기
const renderText = thisComp.layer("Text").text.sourceText;
const pointText = thisComp.layer("PointText").text.sourceText;

s = renderText.indexOf(pointText);

//삼항연산자 좀 더 간결하게 변수로 만들기
const n = (s === -1) ? 0 : pointText.length;

text.sourceText.style.setFontSize(90, s, n).setFillColor(fontColor, s, n).setText(renderText);

이렇게 포인트 텍스트만 색칠되고 폰트 사이즈가 90으로 바뀌는 것을 확인할 수 있습니다. 이제 남은 것은 포인트 텍스트를 어떻게 디자인할 지 정해서 포인트 텍스트 구간에 set하는 것입니다. 스트로크를 넣을 것인지, 스트로크를 넣는다면 어느 정도 굵기로 넣을 것인지 등등을 세팅하면 됩니다.

이렇게 스트로크도 추가했습니다. 그런데 스트로크가 먹지 않는 것을 볼 수 있습니다. 그 이유는 렌더텍스트 레이어 자체의 Character 설정에서 스트로크 설정이 빠져있기 때문입니다.

이렇게 스트로크를 어떤 스타일로 입힐 것인지를 지정해주면 스트로크가 제대로 들어가는 것을 확인할 수 있습니다.
나머지 속성들은 필요한 것들을 직접 추가해보시기 바랍니다.

애프터 이펙트 2025 아래 버전(숨겨진 내용을 펼쳐서 확인하세요.)

애프터 이펙트 2024까지는 익스프레션으로 텍스트의 부분을 디자인할 수 없기 때문에 에니메이터를 사용한다고 했습니다. 앞에서 만들어 놓은 에니메이터를 열고 레인지 셀렉터의 start 값과 end 값에 indexOf와 length로 값을 계산하면 됩니다.

//Animator 1 Range Selector 1 Start에 들어갈 코드
const renderText = thisComp.layer("Text").text.sourceText;
const pointText = thisComp.layer("PointText").text.sourceText;

s = renderText.indexOf(pointText);
//값이 하나라 대괄호 없어도 무방하지만 그냥 출력은 대괄호 안에 넣어서 출력하는 것이 편합니다.
[s]

에니메이터의 End값은 2025와 다르게 끝나는 점이므로 Start 값에서 포인트 텍스트의 글자수를 더해줘야 합니다.

익스프레션에 어떻게 입력해야할지 모를 때는 소용돌이 모양을 클릭하고 연결하려는 속성에 드래그 합니다.

익스프레션은 블록별 코딩이므로 Start에서 만든 변수를 End에서 재사용할 수 없습니다. 새로 만들어 줘야 합니다.

//Animator 1 Range Selector 1 End에 들어갈 코드
const pointText = thisComp.layer("PointText").text.sourceText;
//s는 같은 레인지 셀렉터의 Start 값으로 정의합니다.
s = text.animator("Animator 1").selector("Range Selector 1").start;
//s 값에 따라 삼항연산자로 다른 값을 출력합니다.
[(s === -1) ? 0 : s + pointText.length]

에니메이터에서 Add를 눌러 다른 속성들도 추가합니다.

아래와 같이 우리가 지정한 속성이 잘 반영된 것을 확인할 수 있습니다.

다음에는 포인트 텍스트가 2개 이상인 경우 어떻게 익스프레션 코드를 작성하는 지에 대해 다뤄보도록 하겠습니다.

그럼 이만~

P.S 포스팅을 하면서 템플릿들을 하나씩 정리하며 업로드 하는 사이트를 만들고 있습니다. 다운 받으시는 분들이 늘어나고 반응이 괜찮으면 회원 가입을 받고 서로의 자료를 공유하는 식으로 발전시키면 어떨까 생각됩니다. 편하게 구경해보시고 템플릿 다운받아 가세요.

코멘트

“[익스프레션] 반응형 박스 자막 만들기(3)” 에 하나의 답글

  1. do you need a visa for egypt 아바타

    I think what you said made a lot of sense. But, think on this, suppose you typed a catchier post title?

    I am not suggesting your content is not good, but what
    if you added something that makes people desire more?
    I mean [익스프레션] 반응형 박스 자막 만들기(3) – Raonolje
    studio is kinda vanilla. You ought to look at Yahoo’s home page
    and note how they create article titles to get people interested.

    You might add a video or a related picture or two to grab readers interested about what you’ve written. In my opinion, it might bring your
    posts a little livelier.

do you need a visa for egypt에 답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다