本页包含有关构建 Scene
并与之互动的常见提示
在不使用 AR 的情况下渲染场景
您可以利用 SceneView
类渲染 3D 场景,无需使用设备的摄像头或 AR 会话。 这在没有 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));
互动
处理用户触摸
当用户触摸屏幕时,Sceneform 会将触摸事件传递至连接到节点与场景的事件处理程序和侦听器。 此行为类似于触摸事件传递至 Android 中视图和视图组的方式。 下面是传递顺序:
事件发送至
scene.setOnPeekTouchListener()
(如果设置)。这类似于
viewGroup.intercept()
,不过,场景的快速触摸侦听器无法消费事件。事件传递至与射线相交的第一个节点。
- 通过定义一个能够返回
true
的onTouchEvent()
函数集,节点可以消费事件。 - 如果
onTouchEvent()
函数返回false
,或者未定义侦听器,事件将传递至节点的父级。 在事件被消费或者到达场景之前,这个过程将持续进行。
- 通过定义一个能够返回
最后,如果没有任何侦听器消费事件,事件将传递至
scene.onTouchListener()
。
检测手势
ArFragment
已添加对点按(选择)、拖动(移动)、双指张合(缩放)和倾斜(旋转)手势的支持。
如需了解示例,请参见 HelloSceneform 示例应用中的 HelloSceneformActivity.java
。
创建自定义节点
与创建自定义 Android 视图类似,您可以通过将 Node
子类化的方式创建自定义节点。 下面是一些您可能需要创建自定义节点的情况:
- 您希望在节点生命周期中访问事件,例如
onUpdate()
、onActivate
和onDeactivate()
。 - 您希望创建一个由一组节点组成的节点。
- 您正在重复许多代码,并且可以将节点分解成子类。
如需了解示例,请参见 solarsystem 示例应用中的 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()
,在帧与帧之间将其以动画形式呈现。
以下示例(来自 solarsystem 示例应用中的 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
连接至场景中的任何节点。 默认情况下,每一个 Sceneform 场景都包含一个 Sun
节点,该节点具有一个方位灯。
您可以修改太阳,或者向场景添加自己的灯。 以下示例可以添加一个聚光灯:
Light spotLightYellow =
Light.builder(this, Light.Type.FOCUSED_SPOTLIGHT)
.setColor(new Color(android.graphics.Color.YELLOW))
.setShadowCastingEnabled(true)
.build();
然后调用 setLight()
,将聚光灯连接到节点。
自定义平面可视化
默认情况下,场景有一个 PlaneRenderer
,它可以在 ARCore 检测到 Planes
时将其突出显示。 如下所示:
您可以修改用于渲染检测到的平面的默认材料和纹理。 下面这段代码可以更改纹理:
Texture.Sampler sampler =
Texture.Sampler.builder()
.setMinMagFilter(Texture.Sampler.MagFilter.LINEAR)
.setWrapMode(Texture.Sampler.WrapMode.REPEAT)
.build();
Texture.builder()
.setSource(this, R.drawable.custom_texture)
.setSampler(sampler)
.build()
.thenAccept(texture -> {
arSceneView
.getPlanerRenderer()
.getMaterial()
.setTexture(PlaneRenderer.MATERIAL_TEXTURE, customTexture);
});
阴影
阴影可以让可渲染对象看起来贴近现实世界,并为用户提供一种层次和空间感。
Sceneform 中存在可以投射阴影的物体和可以接收阴影的物体。
Lights
和Renderables
可以投射阴影默认情况下,太阳已启用阴影投射,但灯未启用。 调用
setShadowCastingEnabled()
可以打开阴影投射。Renderables
和PlaneRenderer
可以接收阴影。默认情况下,阴影接收已启用。 调用
setShadowReceiver()
可以将其关闭。
如果可渲染对象可以同时投射和接收阴影,则它可以在自己身上投射阴影。