Project Icon

sceneform-android

Android增强现实开发框架Sceneform

Sceneform-android是基于ARCore的Android增强现实开发框架,采用Google Filament作为3D渲染引擎。该框架支持AR模型查看、增强图像、人脸特效、视频纹理、深度感知、云锚点、即时放置和光线估计等功能。作为Google Sceneform的延续项目,它集成了最新的ARCore SDK和Filament,支持直接使用gltf和glb格式的3D模型。Sceneform-android简化了OpenGL开发难度,同时兼容Java和Kotlin语言,为开发者提供便捷的AR应用开发体验。

Maven Central Discord

Android 平台的 Sceneform 维护版 SDK


⚠️ 本框架已不再更新。请考虑在您的项目中使用 Sceneview 替代。


Sceneform 维护版是一个以 Google Filament 为 3D 引擎的 ARCore Android SDK。这是 已归档的 Sceneform 的延续

Android 增强现实库:AR 模型查看器、增强图像、增强人脸、视频、深度、云锚点、即时放置、光线估计等,支持 Kotlin 和 Java


与我们交流

Discord 频道

(请不要在此提出问题,请转到 GitHub Issues 区域)


Sceneform 维护版和后继者:

与 Google Sceneform(1.15.0、1.16.0、1.17.0 和 1.17.1)的区别

  • 无需插件:直接使用 assets、res/raw、本地文件或 http/https 链接中的 gltf 和 glb 3D 模型文件,代替 sfa、sfb、fbx、obj 等
  • 最新版本的 ARCore SDKGoogle Filament
  • 最新的 gradle 依赖,包括 AndroidX、LifecycleScope/Coroutines(仅限 SceneView)等
  • 可作为 mavenCentral() 依赖使用
  • 支持增强图像
  • 支持增强人脸
  • 使用 glbgltf 作为 3D 模型(支持动画
  • 使用 hdrktx 作为环境(间接光 + 天空盒)
  • 支持纯 3D 使用,无需 ARCore 的单一依赖(仅限 SceneView
  • VideoNode 用于 MediaPlayer(mp4、avi 等)视频 3D 节点
  • 水平/垂直平面放置
  • 深度遮挡和放置(仅限 SceneView
  • 即时放置仅限 SceneView
  • HDR 光线估计,可在更加壮观或真实之间调整
  • 简单的模型查看器,仅需 ArSceneView 参数即可实现基本用途(仅限 SceneView
  • 减少对 OpenGL 知识的需求

本仓库最初是 Sceneform 的一个分支。版权所有 (c) 2021 Google Inc. 保留所有权利。

依赖

app/build.gradle

dependencies {
     implementation "com.gorisse.thomas.sceneform:sceneform:1.23.0"
}

更多...

使用方法(简单模型查看器)

更新您的 AndroidManifest.xml

AndroidManifest.xml

<uses-permission android:name="android.permission.CAMERA" />

<application>
    ...
    <meta-data android:name="com.google.ar.core" android:value="optional" />
</application>

更多...

View 添加到您的 layout

res/layout/main_activity.xml

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/arFragment"
    android:name="com.google.ar.sceneform.ux.ArFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

示例...

编辑您的 ActivityFragment

src/main/java/.../MainActivity.java


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // 从 assets 文件夹或 http 链接加载 model.glb
    (supportFragmentManager.findFragmentById(R.id.arFragment) as ArFragment)
        .setOnTapPlaneGlbModel("model.glb")
}

src/main/java/.../MainFragment.java

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    // 从 assets 文件夹或 http 链接加载 model.glb
    (childFragmentManager.findFragmentById(R.id.arFragment) as ArFragment)
        .setOnTapPlaneGlbModel("https://storage.googleapis.com/ar-answers-in-search-models/static/Tiger/model.glb")
}

Kotlin 示例...

Java 示例...

示例

带动画的 glTF

完整视频
完整视频...

arFragment.setOnTapArPlaneListener { hitResult, plane, motionEvent ->
    // 创建锚点
    arFragment.arSceneView.scene.addChild(AnchorNode(hitResult.createAnchor()).apply {
        // 创建可变换模型并将其添加到锚点
        addChild(TransformableNode(arFragment.transformationSystem).apply {
            renderable = model
            renderableInstance.animate(true).start()
        })
    })
}

Kotlin 示例项目...

Java 示例项目...

深度遮挡

深度遮挡 01深度遮挡 02深度遮挡 03
arFragment.apply {
    setOnSessionConfigurationListener { session, config ->
        if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
            config.depthMode = Config.DepthMode.AUTOMATIC
        }
    }
    setOnViewCreatedListener { arSceneView ->
        // 可用模式:DEPTH_OCCLUSION_DISABLED, DEPTH_OCCLUSION_ENABLED
        arSceneView.cameraStream.depthOcclusionMode =
            CameraStream.DepthOcclusionMode.DEPTH_OCCLUSION_ENABLED
    }
}

文档...

示例项目...

增强图像

增强图像 01

示例项目...

增强人脸

增强人脸 01增强人脸 02增强人脸 03

这里提供了一个可用于创建自己模型的Blender文件增强人脸模板:点击这里

骨骼中的四个骨头在运行时会移动到相应的ARCore姿势。可以将物体附加到骨头上或为顶点分配权重,以根据ARCore姿势定位物体或修改更大的网格。Blender文件中骨头的位置给出了最终结果的大致外观,因此附加对象的相对变换很重要。

图片

面部纹理应作为单独的文件准备。可以使用此模板创建面部纹理:canonical_face.png

你还可以根据骨骼和分配给顶点的权重来改变模型形状,移动头部周围的一些小物体,缩放它们等...

你甚至可以为所有这些制作动画。

示例项目...

云锚点

图片图片
// 创建一个新的锚点 = ARCore将尝试使用ARCore云锚点服务和提供的cloudAnchorId来解析其姿态
sceneView.session?.resolveCloudAnchor(cloudAnchorId)?.let { resolvedAnchor ->
  sceneView.scene.addChild(AnchorNode(resolvedAnchor).apply {
      addChild(VideoNode(context, MediaPlayer.create(context, R.raw.restaurant_presentation).apply {
                  this.start()
              },null)
      )
  })
}

环境光照

环境光照 01环境光照 02环境光照 03
环境光照 04环境光照 05环境光照 06

https://user-images.githubusercontent.com/83349532/144654379-a4476baf-8a22-45aa-8088-4f5e3fc7384b.mp4

// 如果你希望你的对象更接近真实效果,请使用此模式
arSceneView.lightEstimationConfig = LightEstimationConfig.REALISTIC
// 如果你希望你的对象效果更加壮观,请使用此模式
arSceneView.lightEstimationConfig = LightEstimationConfig.SPECTACULAR
// 如果你只想应用ARCore光照的颜色和强度,请使用此模式
arSceneView.lightEstimationConfig = LightEstimationConfig.AMBIENT_INTENSITY
// 如果你想禁用所有ARCore光照估计,请使用此模式
arSceneView.lightEstimationConfig = LightEstimationConfig.DISABLED

示例项目...

视频纹理

视频纹理 01视频纹理 02视频纹理 03
arFragment.setOnTapArPlaneListener { hitResult, plane, motionEvent ->
    // 创建锚点
    arFragment.arSceneView.scene.addChild(AnchorNode(hitResult.createAnchor()).apply {
        addChild(VideoNode(context, MediaPlayer.create(context, R.raw.video).apply {
            start()
        }, chromaKeyColor, null))
    })
}

示例项目...

动态材质/纹理

动态材质 01动态材质 02

示例项目...

非AR用途

非AR用途 01

示例项目...

演示

在Google Play上获取

模拟器

已知可用配置

图片

更多...

贡献 - 提交拉取请求

复刻仓库或在 Discord 上申请贡献者权限

图片

安装 GitHub Android Studio 插件

图片

直接从 Android Studio 创建 Pull Request

图片

更多...

深入探讨

AR 必需 vs AR 可选

如果你的应用需要 ARCore(AR 必需)而不仅仅是(AR 可选),请使用此清单来表明该应用需要 Google Play Services for AR(AR 必需),这将导致该应用仅在支持 ARCore 的设备上的 Google Play 商店中可见:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.ar" android:required="true"/>

<application>
    ...
    <meta-data android:name="com.google.ar.core" android:value="required" />
</application>

更多...

节点

要在用户点击平面时向场景添加一个或多个节点,你可以重写 BaseArFragment.OnTapArPlaneListeneronTapPlane 函数:

arFragment.setOnTapArPlaneListener(::onTapPlane)
arFragment.setOnTapArPlaneListener { hitResult, plane, motionEvent ->
    // 创建锚点
    arFragment.arSceneView.scene.addChild(AnchorNode(hitResult.createAnchor()).apply {
        // 创建可变换模型并将其添加到锚点
        addChild(TransformableNode(arFragment.transformationSystem).apply {
            renderable = model
            renderableInstance.animate(true).start()
            // 添加相对于父模型的子模型
            addChild(Node().apply {
                // 定义相对位置
                localPosition = Vector3(0.0f, 1f, 0.0f)
                // 定义相对缩放
                localScale = Vector3(0.7f, 0.7f, 0.7f)
                renderable = modelView
            })
        })
    })
}

示例...

移除或隐藏节点

从场景中移除锚点节点

anchorNode.anchor = null

从场景中移除模型节点、视频节点、增强人脸节点等

node.parent = null

显示/隐藏节点 = 不渲染它

node.enabled = false

文档...

帧率(FPS 限制)

上限

渲染的更新率受 ARCore 使用的相机配置限制。对大多数智能手机来说是 30 fps,对 Pixel 智能手机来说是 60 fps。用户可以手动更改这个值(你应该知道你在做什么)。

arFragment.setOnViewCreatedListener { arSceneView ->
    // 设置更高的帧率上限
    arSceneView.setMaxFramesPerSeconds(60)
}

默认值是 60

文档...

动画

到目前为止,只有 RenderableInstance 是可动画的。下面的 model 对应于从 node.getRenderableInstance() 返回的 RenderablaInstance

基本用法

对于一个非常基础的 3D 模型,比如一个单一的无限旋转球体,你可能不需要使用 ModelAnimator,而只需调用:

model.animate(repeat).start();

单一模型与单一动画

如果你想将单个模型动画化到特定的时间线位置,请使用:

ModelAnimator.ofAnimationFrame(model, "AnimationName", 100).start();
ModelAnimator.ofAnimationFraction(model, "AnimationName", 0.2f, 0.8f, 1f).start();
ModelAnimator.ofAnimationTime(model, "AnimationName", 10.0f)}.start();

我在哪里可以找到 "AnimationName"?

动画名称是在 3D 模型级别定义的。 你可以将其比作播放与模型中特定行为相对应的轨道。

例如,在 Blender 中,"AnimationName" 可以对应:

  • 非线性动画视图端口 中定义的动作
  • 时间线视图端口 中的单个对象行为

要知道 glb/gltf 文件的实际动画名称,你可以将其拖到 glTF 查看器上,比如这里,然后在动画列表中找到它。

  • 单一的时间、帧或分数值将从实际位置到达所需值
  • 两个值意味着从值1到值2
  • 超过两个值意味着从值1到值2然后到值3

单一模型与多个动画

如果模型是一个角色,例如,可能有一个用于行走循环的 ModelAnimation,第二个用于跳跃,第三个用于横向移动,等等:

顺序播放

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(ModelAnimator.ofMultipleAnimations(model, "walk", "run"));
animatorSet.start();

自动取消

这里你可以看到不需要调用animator.cancel(),因为animator.setAutoCancel(boolean)默认设置为true

ObjectAnimator walkAnimator = ModelAnimator.ofAnimation(model, "walk");
walkButton.setOnClickListener(v -> walkAnimator.start());

ObjectAnimator runAnimator = ModelAnimator.ofAnimation(model, "run");
runButton.setOnClickListener(v -> runAnimator.start());

多个模型的多个动画

对于同步动画集,如动画化包含多个模型的完整场景,请考虑使用带有每个步骤参数化的ModelAnimatorAnimatorSet

AnimatorSet completeFly = new AnimatorSet();

ObjectAnimator liftOff = ModelAnimator.ofAnimationFraction(airPlaneModel, "FlyAltitude",0, 40);
liftOff.setInterpolator(new AccelerateInterpolator());

AnimatorSet flying = new AnimatorSet();
ObjectAnimator flyAround = ModelAnimator.ofAnimation(airPlaneModel, "FlyAround");
flyAround.setRepeatCount(ValueAnimator.INFINITE);
flyAround.setDuration(10000);
ObjectAnimator airportBusHome = ModelAnimator.ofAnimationFraction(busModel, "Move", 0);
flying.playTogether(flyAround, airportBusHome);

ObjectAnimator land = ModelAnimator.ofAnimationFraction(airPlaneModel, "FlyAltitude", 0);
land.setInterpolator(new DecelerateInterpolator());

completeFly.playSequentially(liftOff, flying, land);

变形动画

假设一个角色对象有一个骨骼,一个关键帧轨道可以存储下臂骨骼随时间变化的位置数据,另一个轨道存储同一骨骼的旋转变化数据,第三个轨道存储另一个骨骼的位置、旋转或缩放,以此类推。显然,ModelAnimation可以作用于许多这样的轨道。

假设模型有变形目标(例如一个变形目标显示友好的面部表情,另一个显示愤怒的面部表情),每个轨道都保存了在动画片段执行过程中某个变形目标的影响如何变化的信息。

在glTF上下文中,这个{@link android.animation.Animator}根据glTF动画和蒙皮定义更新矩阵。

ModelAnimator可用于两个用途

  • 根据模型动画定义更新TransformManager组件中的矩阵。
  • 更新RenderableManager组件中的骨骼矩阵。

动画

每个修改动画时间位置的PropertyValuesHolder必须使用ModelAnimation.TIME_POSITION而不是自己的Property,以便可能取消在同一ModelAnimation上操作时间修改的任何ObjectAnimator。

更多...

许可证

请查看LICENSE文件。

品牌指南

Sceneform商标是Google的商标,不受GitHub上Apache 2.0许可的Sceneform存储库中包含的版权或专利许可授权的约束。除这些指南中允许的使用外,任何使用Sceneform商标的行为都必须事先得到Google的批准。

品牌指南的目的

这些指南的存在是为了确保Sceneform项目可以在开源许可下共享其技术,同时确保"Sceneform"品牌作为一个有意义的来源标识符得到保护,符合商标法。通过遵守这些指南,你有助于促进使用和开发高质量Sceneform技术的自由。

可接受的使用

由于我们开源了Sceneform技术,你可以在未经事先书面许可的情况下使用Sceneform商标来指代该项目。这些批准的引用示例包括:

  • 指代Sceneform项目本身;
  • 指代GitHub上Sceneform存储库共享的未经修改的源代码或其他文件;
  • 准确地表明你的设计或实现是基于、用于或与Sceneform技术兼容。

示例:

  • "[你的产品]用于Sceneform。"
  • "[你的产品]是Sceneform项目的一个分支。"
  • "[你的产品]与Sceneform兼容。"

使用指南

  • Sceneform名称绝不能以可能导致对Google赞助、附属或认可产生混淆的方式使用或注册。
  • 不要将Sceneform名称或类似的容易混淆的术语用作你的公司名称、产品名称、域名或社交媒体资料的一部分。
  • 除这些指南允许的情况外,Sceneform名称不应与其他商标、术语或来源标识符组合使用。
  • 不要删除、扭曲或更改Sceneform名称。这包括修改Sceneform名称,例如通过连字符、组合或缩写。不要缩短、缩写或创造Sceneform名称的首字母缩写词。
  • 不要以与周围文本不同的样式、颜色或字体显示Sceneform名称。
  • 不要将Sceneform一词用作动词,也不要使用其所有格形式。

条款和条件

通过下载Android版Sceneform SDK,你同意Google API服务条款管理你对其的使用。

用户隐私要求

你必须在应用程序中突出显示并方便用户访问Google Play Services for AR (ARCore)的使用情况以及它如何收集和处理数据。你可以通过在主菜单或通知屏幕上添加以下文字来实现这一点:"本应用程序运行在Google Play Services for AR (ARCore)上,该服务由Google LLC提供,并受Google隐私政策管理"。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

稿定AI

稿定设计 是一个多功能的在线设计和创意平台,提供广泛的设计工具和资源,以满足不同用户的需求。从专业的图形设计师到普通用户,无论是进行图片处理、智能抠图、H5页面制作还是视频剪辑,稿定设计都能提供简单、高效的解决方案。该平台以其用户友好的界面和强大的功能集合,帮助用户轻松实现创意设计。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号