Sceneform
Sceneform是google的ARCore开发团队提供的一个方便使用ARCore进行开发的框架(目前已停止更新),利用Sceneform,无需学习OpenGL即可轻松的在AR和非AR应用中渲染逼真的3D场景,其提供了ArFragment来显示可以渲染虚拟物体的场景,以及相关的一些如模型导入、平面处理、材质自定义、手势控制等功能。
使用说明
ARCore由于对性能的要求较高,而且需要针对不同机型的相机做出适配来提高AR的水平,所以并不是所有手机都是支持的,官网有支持机型的列表,而且需要android版本至少为24。由于华为被封锁的原因,华为的新机型均不支持。此外,运行ARCore的必须软件为Google Play Services for AR,手机应用商店可下载,如无,则需要Google Play.
项目配置
1.build.gradle(project)中需要有google的maven仓库
allprojects {
repositories {
google()
…
2.在build.gradle(app)中添加ARCore和Sceneform的依赖项
android {
…
defaultConfig {
// Sceneform 最低android adk的版本为24(N)
minSdkVersion 24
…
}
// Sceneform libraries use language constructs from Java 8.
// Add these compile options if targeting minSdkVersion < 26.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
…
// arcore的版本,如仅使用sceneform可不导入
implementation 'com.google.ar:core:1.5.0'
// sceneform库,1.7.1为最新版本但是与1.5功能一致,支持通过插件导入obj文件,1.6版本支持gltf格式的导入
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.5.0'
implementation 'com.google.ar.sceneform:core:1.5.0'
}
引入ArFragment
在需要用到AR的页面的xml文件中引入ArFragment。ArFragment是Sceneform自带的用于显示虚拟场景的Fragment,封装好了apk请求安装、权限请求、找平动画、平面显然、手势控制、点击事件等。
<fragment android:name="com.google.ar.sceneform.ux.ArFragment"
android:id="@+id/ux_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
...//可以添加相关工具组件,如返回按钮、拍照按钮、分享按钮等。
几行代码就算是完成了一大步了,这里事实上可以直接使用了,进去会请求相机权限,请求安装 Google Play Services for AR 的APK,会进行找平,但是因为没有导入模型以及设置监听,并不能点击放置模型。
模型导入
如使用1.5版本的Scenefomr或者1.7版本的Sceneform,模型的源文件是obj、fbx、gltf等格式时,是无法直接使用的,需要转化为sfb二进制文件才能引入项目使用。对此,sceneform提供了一个很方便的AS插件。
1.导入Google Sceneform Tools(Beta)插件
在Android Studio中,打开Plugins导入方式:
- windows : File > Settings > Plugins > MarketPlace
- macOS : Android Studio > Preferences > Plugins 2.导入文件 在app目录下创建sampledata文件夹,右键点击app文件夹,然后选择:New > Sample Data Directory。 如右键没有也可建立一个directory命名为sampledata。 然后将模型相关的所有文件,如mtl、bin、png、jpg等都复制到sampledata文件夹中
3.Gradle 配置
在build.gradle(app)中添加如下代码
apply plugin: 'com.google.ar.sceneform.plugin'
sceneform.asset('sampledata/models/andy.obj', // 'Source Asset Path' specified during import.
'default', // 'Material Path' specified during import.
'sampledata/models/andy.sfa', // '.sfa Output Path' specified during import.
'src/main/res/raw/andy') // '.sfb Output Path' specified during import.
4.点击build
编译完成后在相应目录下会生成*.sfa和*.sfb文件,sfa文件时sfb的说明文件,修改sfa里的相应配置然后再编译的话可以修改生成的sfb文件的内容,这个之后再说
UI文件编写
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!checkIsSupportedDeviceOrFinish(this)) {
return;
}
setContentView(R.layout.activity_ux);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
// 创建Renderable
ModelRenderable.builder()
.setSource(this, R.raw.andy) //通过id读取raw下的sfb文件,也可通过Uri读取网络或本地文件
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Toast toast =
Toast.makeText(this, "Unable to load andy renderable",
Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});
//顾名思义,只有你点击平面才会触发这个监听
arFragment.setOnTapArPlaneListener(
(HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
if (andyRenderable == null) {
return;
}
// 创建锚点,确定在空间中的坐标以及姿态
Anchor anchor = hitResult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
// 创建TransformableNode,其封装了缩放、移动、旋转等手势
TransformableNode andy = new TransformableNode(
arFragment.getTransformationSystem());
// 每一个点都需要设置父节点
andy.setParent(anchorNode);
andy.setRenderable(andyRenderable);
andy.select();
});
}
// android 版本检查以及OpenGL版本检查
public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
if (Build.VERSION.SDK_INT < VERSION_CODES.N) {
Log.e(TAG, "Sceneform requires Android N or later");
Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
String openGlVersionString =
((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
.getDeviceConfigurationInfo()
.getGlEsVersion();
if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
return true;
}
PS
到这里其实已经初体验AR了,这是官方的Demo,接下来我会说明一些自定义的方式。