스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
공간 컴퓨팅을 위한 렌더링 살펴보기
RealityKit 렌더링을 제대로 파악해서 visionOS 앱과 게임의 룩 앤드 필을 어떻게 개선할 수 있을지 알아보세요. 콘텐츠에 들어가는 조명을 사용자화하고 지면 그림자를 추가하며 톤 매핑을 제어하는 방법을 알려 드립니다. 이 플랫폼의 두 가지 핵심 처리 방식인 래스터화 레이트 맵과 동적 콘텐츠 스케일링의 모범 사례도 살펴보겠습니다.
챕터
- 0:00 - Introduction
- 1:15 - Lighting and shadows
- 5:05 - Materials
- 10:09 - Rasterization rate maps
- 13:13 - Dynamic content scaling
- 16:01 - Wrap-up
리소스
관련 비디오
WWDC23
-
다운로드
♪ 감미로운 인스트루멘탈 힙합 ♪ ♪ 안녕하세요 저는 아이번입니다 RealityKit 팀 엔지니어죠 지금부터 보실 제 세션은 '공간 컴퓨팅을 위한 렌더링 살펴보기'입니다 RealityKit는 3D 모델 렌더링과 애니메이팅 그리고 시뮬레이션을 위한 프레임워크입니다 RealityKit의 강력한 장점 한 가지는 사실적인 렌더링을 콘텐츠에 적용한다는 겁니다 RealityKit의 렌더링 기능을 최대한으로 활용해서 콘텐츠의 외관을 개선하는 데 도움이 되도록 공간 컴퓨팅에 맞춰서 앱을 개발할 때 렌더링에서 고려하실 사항을 몇 가지 공유하겠습니다 3D 콘텐츠의 조명과 그림자에 대해 먼저 알아보고 RealityKit 머티리얼에서 무엇이 새로워졌는지 살펴보죠 이어서 래스터화 레이트 맵을 소개하겠습니다 이걸로 시스템 성능이 대폭 개선됩니다 최적화된 기능과 잘 어울리도록 콘텐츠를 조정하는 방법도 추천해 드리겠습니다 마지막으로 소개할 기술은 동적 콘텐츠 스케일링입니다 언제나 선명한 UI를 보장하는 기술이죠 먼저 조명과 그림자를 살펴보겠습니다 iOS와 macOS의 RealityKit가 익숙하다면 그 지식의 대부분이 공간 경험 빌드에도 적용된다는 걸 알게 되실 겁니다 RealityKit에 도입된 이미지 기반 조명은 콘텐츠를 더욱 사실적으로 보이게 하는데요 IBL이라고도 하는 이미지 기반 조명은 오른쪽과 같은 텍스처로 사실적인 반사를 생성합니다 그림자가 들어가면 객체가 서로에 대해 어떤 위치에 있는지를 파악할 수 있죠 새로운 기능을 살펴보기 전에 이미지 기반 조명의 컴포넌트를 빠르게 훑어봅시다 IBL에는 주요 컴포넌트가 두 가지 있습니다 Environment 프로브 텍스처는 ARKit에서 제공되며 방의 물리적 공간에 특정되고 시스템 IBL 텍스처는 OS와 패키지로 제공됩니다 시스템 IBL 텍스처는 하이라이트를 더 추가해서 콘텐츠가 어떤 환경에서든 멋지게 보이도록 합니다 두 컴포넌트가 함께 추가되면 결합 IBL 텍스처가 만들어집니다 활성화된 환경에서는 결합 IBL 텍스처에도 효과가 들어가죠 올해 RealityKit에는 조명을 사용자화하기 위해서 시스템 IBL 텍스처를 재정의하는 기능이 추가되었습니다 예시를 살펴보죠 이건 Hello World라는 경험으로 태양계를 보여 줍니다 RealityKit의 기본값은 시스템 IBL을 쓴 조명인데요 새 이미지 기반 조명 컴포넌트에 IBL을 새로 부여하면 시스템 IBL이 그걸로 대체되어 객체의 조명에 주변의 몰입형 환경이 사용됩니다 어떻게 되는지 보여 드리죠 우선 3D 콘텐츠를 로드합니다 여기서는 위성 모델로 하죠 다음으로 Sunlight라는 환경 리소스를 로드합니다 지구 주위의 태양과 별 이미지가 들어 있죠 모델과 환경 리소스가 모두 있어야 IBL을 설정할 수 있으니 두 로딩 작업이 끝났는지를 반드시 확인해 주세요 ImageBasedLightComponent를 이어서 추가합니다 이건 방금 로드한 환경 리소스를 참조하죠 끝으로 ImageBasedLightReceiver Component를 위성 엔티티에 추가합니다 이런 리시버 컴포넌트를 다른 엔티티에도 추가해서 동일한 IBL로 조명을 넣을 수 있습니다 RealityKit에서 조명을 사용자화하는 방법은 이렇게 간단합니다 다음으로는 여러분의 응용 프로그램에 그림자를 더하는 법을 알아보겠습니다 3D 객체가 배치된 간단한 예시를 생각해 봅시다 플로팅 평면 위에 있는 이 꽃병처럼요 그림자가 켜져 있지 않으면 꽃병과 평면의 상대 위치는 파악하기가 어려울 겁니다 하지만 RealityKit에서 지면 그림자만 추가해도 꽃병이 평면 가운데에 있다는 게 한층 분명해지죠 이걸 코드로 하는 방법을 알아봅시다 먼저 꽃병 모델을 로드합니다 이 프로젝트에서 쓸 3D 모델의 이름은 flower_tulip입니다 이어서 지면 그림자 컴포넌트를 추가하고 castsShadow 플래그를 true로 설정했는지 확인하세요 이걸로 끝입니다 꽃병 엔티티가 지면 그림자를 드리우게 됐습니다 간단하죠? 지면 그림자는 3D 모델 위는 물론이고 물리적 환경의 객체 위에도 나타납니다 사용자 지정 IBL로 씬에 조명을 설정하고 지면 그림자를 넣으면 여러분의 콘텐츠가 더 좋아 보일 뿐 아니라 머티리얼을 수정하는 식으로 객체의 외관에 직접 작업하는 것도 가능해집니다 macOS와 iOS에서 사용할 수 있는 RealityKit 머티리얼 대부분은 xrOS에서도 쓸 수 있는데요 이를 빠르게 검토해 봅시다 가장 흔히 사용되는 머티리얼은 PhysicallyBasedMaterial입니다 RealityKit의 PhysicallyBasedMaterial은 조명에 반응하고 플라스틱과 금속 같은 다양한 현실 머티리얼을 표현하는 데도 쓰입니다 SimpleMaterial 역시 조명에 반응하지만 더 작은 매개변수 부분집합을 사용합니다 빠르게 실험하기에 특히 좋죠 UnlitMaterial은 조명에 반응하지 않습니다 조명 조건이 달라져도 외관에는 변함이 없죠 VideoMaterial은 UnlitMaterial을 변형한 것으로 엔티티 표면에 무비 파일을 매핑할 수 있습니다 RealityKit는 이런 머티리얼과 더불어 ShaderGraphMaterial이라는 새로운 머티리얼을 도입했습니다 ShaderGraphMaterial은 Reality Composer Pro에서 새로 작성하거나 MaterialX 파일에서 로드하세요 ShaderGraphMaterial에 대해 더 알아보려면 다음 세션을 보시죠 'Reality Composer Pro 머티리얼 살펴보기'입니다 모든 머티리얼의 색상 출력은 톤 매핑이라는 특별한 단계를 거칩니다 톤 매핑은 RealityKit가 머티리얼의 색상 출력에 기본으로 적용하는 변환입니다 다양한 기술이 사용되어서 색상이 한층 자연스럽게 인식되죠 1을 초과하는 값을 가시역 내에서 재매핑하는 게 그 기술 중 하나입니다 예시로 시연하겠습니다 톤 매핑이 비활성화된 TV의 3D 렌더링입니다 밝깃값이 아주 높은 텍스처를 디스플레이에 지정해 뒀는데요 톤 매핑을 활성화하면 밝기가 높은 영역이 더 상세하게 보입니다 이 꽃잎도 그렇죠 톤 매핑은 대체로 잘 작동하며 아름다운 비주얼을 렌더링하지만 일부 사용 예에서는 객체의 정확한 색상을 나타내고 싶을 때도 있을 겁니다 이때는 톤 매핑을 빼야 합니다 예시를 살펴보죠 신호등을 보여 주는 간단한 응용 프로그램입니다 '정지', '대기', '출발' 레이블이 세 버튼에 들어가 있습니다 신호등 자체는 3D 모델이지만 세 버튼은 SwiftUI로 추가했습니다 등의 색상을 버튼 색상에 정확히 매칭하려면 등에 UnlitMaterial을 사용하면 됩니다 UnlitMaterial은 객체의 외관을 변함없이 유지하니까요 조명 조건에 영향을 받지 않죠 하지만 UnlitMaterial로 출력된 결과는 모든 RealityKit 머티리얼에 기본적으로 켜져 있는 톤 매핑에 여전히 영향을 받습니다 그래서 SwiftUI 버튼과 등 머티리얼에 동일한 색상이 지정되어도 둘은 살짝 다르게 보일 수 있습니다 보고 계시는 스크린샷은 톤 매핑을 활성화하고 찍었습니다 어떻게 되는지 보시도록 등 머티리얼에 톤 매핑을 비활성화하겠습니다 등과 버튼의 색상이 정확히 매칭되는 걸 확인하실 수 있죠 등 머티리얼의 톤 매핑을 다시 한번 토글하겠습니다 톤 매핑을 활성화했을 때와 비활성화했을 때입니다 이제 샘플 코드를 살펴보시죠 코드에서 톤 매핑을 토글하는 법을 보여 드리겠습니다 우선 신호등 모델을 로드합니다 이 프로젝트에서 쓸 3D 모델의 이름은 traffic_light입니다 이어서 red_light라는 엔티티를 찾겠습니다 신호등 맨 위의 등에 해당하는 엔티티입니다 엔티티를 찾았으면 모델 컴포넌트에 접근합니다 다음으로는 UnlitMaterial을 새로 만듭니다 희망하는 색상과 applyPostProcessToneMap이라는 새 불리언 매개변수를 패스합니다 이 불리언 매개변수는 false로 설정해서 이 머티리얼의 톤 매핑 변환을 비활성화합니다 끝으로 모델 컴포넌트 머티리얼을 대체하고 그 모델 컴포넌트를 엔티티에 다시 지정합니다 이 작업을 등 세 개에 각각 수행합니다 이제 버튼과 등의 색상이 밀접하게 매칭될 겁니다 applyPostProcessToneMap 플래그는 씬에 색상을 정확히 표현하고자 할 때 유용하게 쓰입니다 RealityKit를 사용해서 메뉴나 헤드업 디스플레이를 빌드할 때 도움이 되죠 Reality Composer Pro의 머티리얼 에디터에도 이 새로운 프로퍼티가 표시됩니다 이제 질적으로 고려할 사항을 살펴봅시다 공간 컴퓨팅의 래스터화 레이트 맵부터 이야기해 보죠 헤드셋에 사용된 디스플레이는 해상도가 높고 OS는 이런 디스플레이 업데이트를 1초에도 여러 번 수행해야 합니다 시각 자료로 설명하겠습니다 아시겠지만 헤드셋에는 시선이 향하는 곳을 정확히 감지하는 기능이 있습니다 이 시뮬레이션에서는 사람이 눈을 오른쪽으로 움직였다가 중앙으로 되돌립니다 노란 원이 표시하는 건 초점의 중심입니다 그 점을 둘러싼 영역은 발광 효과로 하이라이트되고 주변부는 어둡게 보입니다 래스터화 레이트 맵은 이런 식으로 어둡게 보이는 영역에서 수행되는 계산의 양을 줄입니다 어떤 시점에 확인하든 하이라이트된 영역은 주변부보다 작습니다 이렇게 해서 시스템은 메모리와 성능을 대폭 아낄 수 있습니다 RealityKit에서는 이런 최적화가 자동으로 활성화됩니다 이걸로 시스템 성능이 크게 개선되지만 수행 중인 최적화와 같이 작동하기 좋게 콘텐츠를 조정해야 할 상황도 있을 겁니다 야자수잎 에셋을 예시로 들어 보겠습니다 화면 중앙에 배치된 잎은 선명하고 상세하게 보입니다 그런데 객체를 왼쪽으로 옮기고 안구 움직임 시뮬레이션을 다시 적용하면 야자수잎에서 깜박임이 보입니다 눈 방향을 표시하는 노란 원이 화면 오른쪽 가장자리에 가까워지면 깜박임이 유독 강해지는데요 깜박임이 발생하는 건 래스터화 레이트 맵으로 사람이 보고 있는 지점 주변에서는 디테일이 더 선명해지고 눈이 멀어질수록 야자수잎 주변 픽셀이 디테일이 떨어지는 상태로 렌더링되기 때문입니다 깜박임을 줄이려면 콘텐츠 매개변수 몇 가지만 조정하면 됩니다 함께 보시죠 동일한 야자수잎 에셋을 나타내면서 빨간 와이어프레임을 오버레이했습니다 자잘한 빨간 삼각형이 많이 보이는데요 이 작은 삼각형 때문에 주변부에서 깜박임이 생긴 겁니다 삼각형의 크기를 키우고 미세 디테일을 투명 텍스처에 저장해서 깜박임을 간단히 줄일 수 있습니다 에셋을 조정한 뒤의 시뮬레이션입니다 조정 후의 3D 모델이 훨씬 나아 보이죠 에셋이 로드될 때 RealityKit가 저해상도 버전 투명도 맵을 자동으로 생성하기 때문입니다 이런 텍스처의 저해상도 버전은 밉맵이라 불리며 GPU에서 자동으로 사용되어서 디테일이 떨어지는 영역의 외관을 개선합니다 래스터화 레이트 맵을 더 자세히 알아보려면 다음 문서를 참고하세요 '다른 래스터화 레이트로 렌더링하기'입니다 래스터화 레이트 맵과 유사하게 동적 콘텐츠 스케일링이라는 기술도 있습니다 SwiftUI로 작성된 콘텐츠의 외관을 자동으로 개선하는 기술이죠 함께 살펴봅시다 이건 달의 이름을 격자에 넣어 보여 주는 응용 프로그램입니다 텍스트 레이블로 매달이 표시되는데요 눈으로 6월을 보면 시스템은 해당 영역의 텍스트를 최고 수준의 디테일로 래스터화합니다 6월 주위에 파란색으로 표시된 영역은 디테일이 조금 흐려져서 래스터화되지만 전체적으로는 고품질을 유지합니다 하지만 보라색으로 표시된 영역은 디테일이 훨씬 흐려진 채로 래스터화됩니다 인간의 시야는 주변부에서 디테일을 훨씬 적게 인지해서 차이가 눈에 띄지 않거든요 눈이 보고 있는 대상을 기반으로 디테일 수준을 변경하는 이런 유형의 래스터화를 동적 콘텐츠 스케일링이라고 부릅니다 시스템은 동적 콘텐츠 스케일링에 의존해서 UI 콘텐츠를 적절한 스케일로 드로우하고 항상 선명하게 유지합니다 동적 콘텐츠 스케일링은 래스터화된 콘텐츠의 메모리에 있는 상대 크기에 영향을 미칩니다 텍스트 레이블의 크기가 눈이 보고 있는 지점과 레이블의 거리에 따라서 확대되거나 축소된다는 말이죠 보시다시피 6월이라고 쓰인 레이블이 제일 커졌습니다 해상도가 가장 높고 디테일도 가장 선명하죠 다음으로 보실 그룹에는 여덟 달이 있습니다 여기에 있는 1월, 2월, 3월 등은 디테일이 살짝 떨어집니다 마지막 그룹에는 석 달이 있는데요 눈이 보는 방향에서 제일 멀리 떨어져 있는 4월, 8월, 12월입니다 마지막 그룹은 메모리에서 더 작은 이미지로 표시될 겁니다 동적 콘텐츠 스케일링을 활성화하는 법을 알아봅시다 UIKit와 SwiftUI를 사용한다면 여러분의 응용 프로그램은 이 기술을 자동으로 이용합니다 Core Animation 프레임워크에 의존해서 UI를 빌드하고 있다면 새로운 API로 동적 콘텐츠 스케일링을 활성화할 수 있는데요 이 API를 살펴봅시다 동적 콘텐츠 스케일링을 활성화하려면 CALayer의 프로퍼티인 wantsDynamicContentScaling을 true로 설정하면 됩니다 이 기술은 더 높은 해상도의 래스터화에 의존하니 비트맵 기반 위주인 콘텐츠에 사용하는 용도로는 추천하지 않는다는 걸 알아 두세요 동적 콘텐츠 스케일링과 관련한 추천 사항은 developer.apple.com에서 모두 확인하실 수 있습니다 지금까지 알아본 내용을 요약해 보죠 먼저 이미지 기반 조명과 지면 그림자를 RealityKit 응용 프로그램에 어떻게 추가하는지를 살펴봤습니다 이어서 공간 경험에서 사용 가능한 머티리얼을 검토하면서 새 ShaderGraphMaterial도 이야기했죠 UnlitMaterial의 톤 매핑을 제어하는 방법도 알아봤습니다 래스터화 레이트 맵이 공간 컴퓨팅에서 어떻게 쓰이는지 배웠고 주변부의 깜박임이 줄도록 3D 모델을 조정하는 방법도 예시와 함께 익혔습니다 마지막으로는 동적 콘텐츠 스케일링이 시스템에서 어떻게 작동하며 어떻게 활용할지도 살펴봤고요 올해의 릴리즈가 정말 기대됩니다 여러분이 xrOS에 빌드하실 멋진 공간 경험을 얼른 보고 싶네요 감사합니다 ♪
-
-
3:05 - Image based lighting
RealityView { content in async let satellite = Entity(named: "Satellite", in: worldAssetsBundle) async let environment = EnvironmentResource(named: "Sunlight") if let satellite = try? await satellite, let environment = try? await environment { content.add(satellite) satellite.components.set(ImageBasedLightComponent( source: .single(environment))) satellite.components.set(ImageBasedLightReceiverComponent( imageBasedLight: satellite)) } }
-
4:28 - Grounding shadows
RealityView { content in if let vase = try? await Entity(named: "flower_tulip") { content.add(vase) vase.components.set(GroundingShadowComponent(castsShadow: true)) } }
-
8:48 - Disable tone mapping
RealityView { content in if let trafficLight = try? await Entity(named: "traffic_light") { content.add(trafficLight) if let lamp = trafficLight.findEntity(named: "red_light") { if var model = lamp.components[ModelComponent.self] { let material = UnlitMaterial(color: .init(color), applyPostProcessToneMap: false) model.materials = [material] lamp.components[ModelComponent.self] = model } } } }
-
15:34 - Dynamic content scaling
// Enable dynamic content scaling on CALayer with: var wantsDynamicContentScaling: Bool { get set }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.