이 페이지에는 Scene
를 빌드하고 상호작용하기 위한 일반적인 팁이 포함되어 있습니다.
AR 없이 장면 렌더링
SceneView
클래스를 사용하면 기기의 카메라나 AR 세션을 사용하지 않고도 3D 장면을 렌더링할 수 있습니다. 이 기능은 AR 없이 앱의 3D 객체를 미리 보거나 AR을 지원하지 않는 기기에서 대체 기능을 제공할 때 유용합니다.
기본적으로 SceneView
는 AR 카메라의 이미지를 표시하지 않으며 검은색 배경을 사용합니다. 배경 색상을 변경하려면 아래와 같이 view.setBackgroundColor()
을 호출하거나 레이아웃에서 배경 색상을 정의하면 됩니다.
<com.google.ar.sceneform.SceneView
android:id="@+id/scene_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/deep_teal"/>
장면의 Camera
노드가 원점 (위치 0,0,0)에 있고 앞쪽 (방향 0,0,-1)에 배치됩니다. 카메라의 위치와 회전은 AR 모션 추적에 연결되어 있지 않으므로 다른 노드처럼 위치를 변경하거나 애니메이션을 적용할 수 있습니다.
Camera camera = sceneView.getScene().getCamera();
camera.setLocalRotation(Quaternion.axisAngle(Vector3.right(), -30.0f));
상호작용 수
사용자 터치 처리
사용자가 화면을 터치하면 장면 형태가 노드와 장면에 연결된 이벤트 핸들러와 리스너에 터치 이벤트를 전파합니다. 이 동작은 터치 이벤트가 Android의 뷰 및 뷰 그룹에 전파되는 방식과 비슷합니다. 적용 순서는 다음과 같습니다.
이벤트는
scene.addOnPeekTouchListener()
에 추가된 모든 리스너로 전송됩니다.미리보기 터치 리스너의 장면이 이벤트를 사용할 수 없다는 점을 제외하면
viewGroup.intercept()
와 유사합니다.이 이벤트는 레이가 교차하는 첫 번째 노드에 전달됩니다.
- 노드는
true
를 반환하는onTouchEvent()
메서드 세트를 정의하여 이벤트를 사용할 수 있습니다. onTouchEvent()
메서드가false
를 반환하거나 리스너가 정의되지 않으면 이벤트가 노드의 상위 요소에 전파됩니다. 이 프로세스는 이벤트가 소비되거나 장면에 도달할 때까지 계속됩니다.
- 노드는
마지막으로 리스너가 이벤트를 사용하지 않으면 이벤트가
scene.onTouchListener()
로 전달됩니다.
동작 감지
ArFragment
에서는 탭 (선택), 드래그 (이동), 손가락 모으기 (크기 조정), 트위스트 (회전) 동작을 기본적으로 지원합니다.
예를 들어 Hello sceneform 샘플 앱에서 HelloSceneformActivity.java
을 참고하세요.
커스텀 노드 만들기
맞춤 Android 뷰 만들기와 마찬가지로 Node
의 서브클래스를 만들어 맞춤 노드를 만들 수 있습니다. 다음과 같은 경우에 커스텀 노드를 만들어야 할 수 있습니다.
- 노드 수명 주기의 이벤트(예:
onUpdate()
,onActivate
,onDeactivate()
)에 액세스하려고 합니다. - 노드 그룹으로 구성된 노드를 만들려고 합니다.
- 코드가 많이 복제되며 서브클래스에 분해할 수 있습니다.
예는 태양계 샘플 앱에서 Planet.java
을 참고하세요.
노드 애니메이션 처리
노드에 애니메이션을 적용하는 방법에는 두 가지가 있습니다.
- 표준 Android Animation API의
ObjectAnimator
를 사용합니다. - 커스텀 노드 클래스를 만들고
onUpdate()
를 재정의합니다.
ObjectAnimator로 애니메이션 처리
스포트라이트의 강도를 애니메이션으로 보여주는 예는 다음과 같습니다.
final int durationInMilliseconds = 1000;
final float minimumIntensity = 1000.0f;
final float maximumIntensity = 3000.0f;
ValueAnimator intensityAnimator =
ObjectAnimator.ofFloat(
spotlightNode.getLight(), "intensity", minimumIntensity, maximumIntensity);
intensityAnimator.setDuration(durationInMilliseconds);
intensityAnimator.setRepeatCount(ValueAnimator.INFINITE);
intensityAnimator.setRepeatMode(ValueAnimator.REVERSE);
intensityAnimator.start();
자세한 내용은 ObjectAnimator로 애니메이션 적용을 참고하세요.
onUpdate에서 애니메이션 처리
노드의 onUpdate()
를 재정의하여 프레임에 애니메이션을 적용합니다. 다음 예에서는 태양계 샘플 앱의 Planet.java
에서 행성이 회전하더라도 사용자를 향하도록 프레임마다 정보 카드를 조정합니다.
@Override
public void onUpdate(FrameTime frameTime) {
Vector3 cameraPosition = getScene().getCamera().getWorldPosition();
Vector3 cardPosition = infoCard.getWorldPosition();
Vector3 direction = Vector3.subtract(cameraPosition, cardPosition);
Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up());
infoCard.setWorldRotation(lookRotation);
}
조명 추가
Lights
는 장면의 모든 노드에 연결할 수 있습니다. 기본적으로 모든 장면 양식에는 방향 빛이 연결된 Sun
노드가 포함되어 있습니다.
태양을 수정하거나 장면에 나만의 조명을 추가할 수 있습니다. 다음 예시에서는 스포트라이트를 추가합니다.
Light spotLightYellow =
Light.builder(this, Light.Type.FOCUSED_SPOTLIGHT)
.setColor(new Color(android.graphics.Color.YELLOW))
.setShadowCastingEnabled(true)
.build();
그런 다음 setLight()
를 호출하여 노드에 연결합니다.
평면 시각화 맞춤설정
기본적으로 장면에는 ARCore에서 감지되면 Planes
를 강조표시하는 PlaneRenderer
이 있습니다. 다음 그림과 같습니다.
감지된 평면을 렌더링하는 데 사용되는 기본 머티리얼과 텍스처를 수정할 수 있습니다. 텍스처를 변경하는 방법은 다음과 같습니다.
Texture.Sampler sampler =
Texture.Sampler.builder()
.setMinFilter(Texture.Sampler.MinFilter.LINEAR)
.setWrapMode(Texture.Sampler.WrapMode.REPEAT)
.build();
// R.drawable.custom_texture is a .png file in src/main/res/drawable
Texture.builder()
.setSource(this, R.drawable.custom_texture)
.setSampler(sampler)
.build()
.thenAccept(texture -> {
arSceneView.getPlaneRenderer()
.getMaterial().thenAccept(material ->
material.setTexture(PlaneRenderer.MATERIAL_TEXTURE, texture));
});
그림자
그림자는 렌더링 가능한 세계를 기반으로 하고 사용자에게 깊이와 공간에 대한 느낌을 줍니다.
장면 양식에는 그림자를 전송할 수 있는 객체와 그림자를 받을 수 있는 객체가 있습니다.
Lights
및Renderables
가 그림자를 드리울 수 있음기본적으로 그림자 전송은 햇빛에 사용되지만 조명에는 사용되지 않습니다.
setShadowCastingEnabled()
를 호출하여 사용 설정합니다.Renderables
및PlaneRenderer
는 그림자를 수신할 수 있습니다.기본적으로 그림자 수신 기능이 사용 설정되어 있습니다.
setShadowReceiver()
를 호출하여 사용 중지합니다.
렌더링 가능 섀도우와 드리우는 그림자가 있다면 그림자를 드리울 수 있습니다.