포맷 전 필수!
홈페이지 접속 후 Resistration 항목에서 삭제


1 Activated Seats에서 2 컴퓨터 이름 확인 후 3 디엑티브 나우를 클릭!
포맷 전 필수!
홈페이지 접속 후 Resistration 항목에서 삭제
1 Activated Seats에서 2 컴퓨터 이름 확인 후 3 디엑티브 나우를 클릭!
표시부에 그림자 추가하는 방법
2. 디테일 패널
Shadow Catcher 표시
짠!
블렌더 파일이 오픈되지 않는 경우는 2가지
대처법
1. Blender 실행
2. 폴더에서 파일을 드래그하여 블렌더로 이동 후 오픈
3. Save as 기능으로 다시 저장
애셋 이동 방법
2. Migrate를 할 수 없는 경우나 많은 양의 데이터를 옮길 경우
– Create Level Instance 사용하여 레벨을 만든 후 Migrate
저장 후 Migrate 실행
이동한 파일에서 Level Instance 배치 후 Level Break로 해제
GenLock(Generator Lock) – 동기 신호 발생기(Sync Generator)에 고정(Lock)시킨다는 뜻
언리얼 엔진의 타임코드를 작업 중인 비디오 피드의 타임코드와 일치시키는 작업
2. BP_BM_Timecode_Provider와
BP_BM_TimeStep 생성 및 각각 Detail 설정
3. 프로젝트 설정 입력
1) TimeCode
2) TimeStep
입력란에 위에서 만든 BP 선택
4. 프로젝트 재시작 (권장)
5. stat time code
확인
한글 타이핑 자막 효과의 시작 시간을 정할 수 있도록 개선
let cCho = ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"],
cJung = ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"],
cJong = ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"]
let toStringFromCharCode = (cho, jung, jong) =>
String.fromCharCode(44032 + cho * 588 + jung * 28 + (jong || 0));
let seperateChar = (char) => {
let cCode = char.charCodeAt() - 0xac00;
let jong = cCode % 28;
let jung = ((cCode - jong) / 28) % 21;
let cho = ((cCode - jong) / 28 - jung) / 21;
return []
.concat(cCho[cho])
.concat(toStringFromCharCode(cho, jung))
.concat(cJong[jong] !== "" ? toStringFromCharCode(cho, jung, jong) : []);
};
let toKorChars = (char) => {
let cCode = char.charCodeAt();
return [].concat(
(!cCode && []) ||
(cCode === 32 && " ") ||
((cCode < 0xac00 || cCode > 0xd7a3) && char) ||
seperateChar(char)
);
};
let typing = (str) =>
str
.split("")
.map((char) => toKorChars(char))
.reduce(
(pre, cur) =>
pre.concat(
cur.map((v) => (pre.length !== 0 ? pre[pre.length - 1] : "") + v)
),
[""]
);
let p = thisLayer.effect("Speed")("Slider");
let strList = typing(thisLayer.text.sourceText);
if (time > 2) {
let adjustedTime = time - 2;
let strListIndex = Math.round(adjustedTime*p);
[strList[strList.length > strListIndex ? strListIndex : strList.length-1]]
} else {
[]
}
//------------초성, 중성 종성 글자 수 세기--------------
/*let countCharComponents = (str) => {
return str.split("").reduce((count, char) => {
let components = toKorChars(char);
return count + components.length;
}, 0);
};
[countCharComponents(thisLayer.text.sourceText)]*/
//------------초성, 중성 종성 글자 수 세기--------------
const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""));
const totalText = thisComp.layer("Text_" + layerNameNum).text.sourceText;
const pointTextArray = thisComp.layer("PointText_" + layerNameNum).text.sourceText.split("$$");
function splitTextByWords(text, words) {
let currentIndex = 0;
const result = [];
for (const word of words) {
const index = text.indexOf(word, currentIndex);
if (index !== -1) {
const preWord = text.substring(currentIndex, index).trim();
if (preWord !== '') result.push(preWord);
result.push(word);
currentIndex = index + word.length;
}
}
// 마지막 단어 이후의 텍스트를 결과에 추가
if (currentIndex < text.length) {
const lastText = text.substring(currentIndex).trim();
if (lastText !== '') result.push(lastText);
}
return result;
}
const thisLayerRenderText = splitTextByWords(totalText, pointTextArray);
[thisLayerRenderText]
const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""));
const totalText = thisComp.layer("Text_" + layerNameNum).text.sourceText;
const pointTextArray = thisComp.layer("PointText_" + layerNameNum).text.sourceText.split("$$");
// splitTextByWords 함수 정의
function splitTextByWords(text, words) {
let result = [];
let currentIndex = 0;
for (let i = 0; i < words.length; i++) {
const word = words[i];
const index = text.indexOf(word, currentIndex);
if (index !== -1) {
// 단어 이전의 텍스트를 결과에 추가
if (index > currentIndex) {
result.push(text.substring(currentIndex, index).trim());
}
result.push(word);
currentIndex = index + word.length;
}
// 해당 단어가 발견되지 않았을 때는 다음 단어를 찾기 위해 현재 인덱스를 유지
}
// 마지막 단어 이후의 텍스트를 결과에 추가
if (currentIndex < text.length) {
result.push(text.substring(currentIndex).trim());
}
// 결과 배열에서 빈 문자열을 필터링하여 반환
return result.filter(word => word !== "");
}
// 결과 계산
const thisLayerRenderText = splitTextByWords(totalText, pointTextArray);
[thisLayerRenderText]
const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""))-1;
const totalText = thisComp.layer("Text_1").text.sourceText.toString();
const thisLayerText = thisLayer.text.sourceText.toString();
baseTextLayer = thisComp.layer("SecondLine_Render_Text_" + layerNameNum);
baseTextXPosition = baseTextLayer.transform.position[0];
baseTextWidth = baseTextLayer.sourceRectAtTime().width;
spaceBlankWidth = thisComp.layer("Control_Text_1").effect("Space_Blank_Width")("Slider");
spaceDefaultWidth = thisComp.layer("Control_Text_1").effect("Space_Default_Width")("Slider");
const checkSpaceBefore = (totalCheckText, word) => {
const thisTextindex = totalCheckText.indexOf(word);
return thisTextindex > 0 && totalCheckText[thisTextindex - 1] === ' ';
};
const spaceBefore = checkSpaceBefore(totalText, thisLayerText);
if (spaceBefore === true) {
x = baseTextXPosition + baseTextWidth + spaceBlankWidth;
} else {
x = baseTextXPosition + baseTextWidth + spaceDefaultWidth;
}
[x, baseTextLayer.transform.position[1]]
2. Mixamo Converter로 UE에서 사용할 수 있게 변환
3. UE에서 파일 Import
4. MetaHuman BP –> Root —> Body에서 Animation 적용
Disable Post Process Blueprint 체크
5. 얼굴 Animation Import
Face Anim 파일을 Montage 파일로 변환
5. MetaHuman BP에서 Play_Montage 추가
-끝-
Unreal에서 Chroma Rectangle Area를 설정하고 Mask Area를 2개 설정한다. 또한 영상의 Crop 범위를 설정한다.
2. UVCropping 머터리얼 수정
3. M_SinglePassChromakeyer 머터리얼 수정
4. Radial_SQ 머터리얼 수정 (GenerateRoundRect로 대제 가능)