3D 장면
Three.js (라이브 레이어)
/engines/three.js에서threeLayer(el, { update(t), background, fov })를 사용합니다.three에 대한 import map을 추가하세요 (examples/engines-demo/index.html참조).update(t)는t로부터 모든 트랜스폼을 설정합니다. 카메라 움직임: 일반 객체에 GSAP 트윈으로 키프레임을 지정하고 (tl.to(cam, { x: 4, z: 8, duration: 2 }, 3))update에서camera.position에 복사합니다.- 모델:
three/addons/loaders/GLTFLoader.js에서GLTFLoader를 사용합니다 (import map에"three/addons/": "/core/node_modules/three/examples/jsm/"추가). 로드를Studio.wait(...)로 래핑합니다. 모델 파일은 브랜드의assets/models/또는 프로덕션의composition/에 넣습니다. - 룩 (
looks/README.md)이 렌더링 스타일을 결정합니다. 동일한 모델도 다음 중 어떤 방식으로든 표현될 수 있습니다:- 카툰 (
looks/toon-3d):toon(color, { steps })+outline(mesh, { thickness }). 하드 라이트: 하나의DirectionalLight+ 낮은AmbientLight. - 사실적 (
looks/photoreal):await realistic(renderer, scene)(Studio.wait로 래핑: ACES 톤 매핑, 반사를 위한 스튜디오 환경, 부드러운 그림자) +pbr(color, { metalness, roughness, clearcoat }). 키 라이트 (castShadow사용), 뒤에서 오는 차가운 림 라이트, CSS 그라데이션 위의ShadowMaterial바닥. 카메라는 얕은 각도 이상으로 유지하고 (광택 면이 흰색으로 변함), 천천히 움직이며, 최종 렌더링은Studio.setup({ motionBlur: true })로 수행합니다. - 네온 (
looks/neon-noir):emissive(color, intensity)+threeLayer(el, { post: bloom({ strength, threshold }) }),scene.fog.threshold≥ 0.2 및 emissive ≤ 2로 유지하지 않으면 모든 것이 흰색으로 번집니다.
- 카툰 (
- 애니메이션 GLB 클립:
AnimationMixer를 생성한 다음update에서mixer.setTime(t - start)를 호출합니다. 절대mixer.update(delta)를 사용하지 마십시오. - 3D 지점을 따르는 HTML 태그:
update(t)에서camera.updateMatrixWorld()와 부모의updateMatrixWorld()를vector.applyMatrix4(obj.matrixWorld).project(camera)전에 호출합니다. Three.js는render()내부에서만 이를 새로고침하므로, 이 호출 없이는 태그가 이전 프레임을 따릅니다. 예시:productions/bike-logger/REEL-002-engines. - CAD 메시를 JSON(정점 + 인덱스)으로:
toNonIndexed()+computeVertexNormals()는 선명한 평평한 면을 제공합니다. 슈퍼샘플링된 가장자리를 위해threeLayer(..., { pixelRatio: 2 })로 렌더링합니다. - 물리: 베이크합니다 (첫 번째 프레임 전에 고정 1/120초 단계로 배열에 시뮬레이션) 그리고
t로 조회합니다. - 말하는 캐릭터:
/engines/lipsync.js와 라인의.visemes.js를 (scripts/lipsync.sh에서 생성) 고전적인<script>태그로 로드한 다음update(t)에서:LipSync.paramsAt(cues, t, "mouth", { offset })→{ open, wide, round }(0…1)을 형태 보간 대상 (mesh.morphTargetInfluences) 또는 입 메시의 스케일에 적용합니다.engines/README.md, 립 싱크 참조.
Blender (플레이트)
- 장면 스크립트는
build(ctx)를 정의합니다;engines/blender/example_scene.py를 복사합니다.ctx는toon(rgb),key(obj, "location", t, value),size,fps,duration,frames,scene을 제공합니다. - 렌더링:
engines/blender/render.sh scene.py composition/plates/<name>.mp4 --size 1080x1920 --duration 4 [--engine EEVEE|CYCLES|WORKBENCH]. 초안은--size 540x960, 최종은 전체 크기로 렌더링합니다. - 배경색: 카메라에만 표시하고 (Light Path "Is Camera Ray" 믹스, 예시 참조), 그렇지 않으면 장면을 비추고 툰 밴드를 평평하게 만듭니다.
- 색상 관리는 Standard로 설정되어 브랜드 16진수 색상이 입력 그대로 출력됩니다. 포토리얼 플레이트의 경우,
build에서ctx["scene"].view_settings.view_transform = "AgX"로 전환하고,--engine CYCLES로 렌더링하며, 영역 조명과 카메라 피사계 심도를 사용합니다. - 물리 및 시뮬레이션: 렌더링 전에 장면 스크립트에서 베이크합니다.
- 말하는 캐릭터: 장면 스크립트에서
import lipsync as L을 수행하고 (run.py는engines/blender/와 스크립트 자체 폴더를 경로에 추가함),cues = L.load("productions/…/audio/vo.visemes.json")로 큐를 로드한 후,L.key_shape_keys(head, cues, ctx, offset=VO_START)로 모든 프레임의open,wide,round형태 키를 키잉합니다 (names={"open": "Jaw"}로 다른 이름을 매핑 가능). 그 외: 프레임별로L.params_at(cues, t, offset=…)을ctx["key"]와 함께 사용합니다. - 합성에서:
<video src="plates/<name>.mp4">+Studio.video(el, { start }). 플레이트에는 알파가 없습니다. 텍스트와 캐릭터는 HTML 레이어를 사용하여 위에 배치합니다.
확인
주요 비트를 정지 이미지로 렌더링하여 확인합니다. Three.js의 경우, 한 프레임을 두 번 렌더링하고 md5를 비교합니다. 프로덕션 로그에 렌더링 시간을 기록합니다.