如今,对于提供沉浸式虚拟现实或增强现实体验的Android应用程序有巨大的需求。 作为开发人员,可以使用许多不同的框架来创建此类应用程序。

但是,除非您也是熟练的3D美术师,否则如何创建将在这些应用程序中显示的3D对象? 您准备好花几个月的时间学习如何与3D建模程序(例如Blender或Maya)一起使用吗? 如果不是这样,则应考虑使用Google Poly ,这是一个在线存储库,其中包含数千种带有Creative Commons许可的3D资源。

您今天可以在Poly上找到的大多数资产都是具有简单材料的低多边形。 这是因为普通的移动GPU尚未强大到足以实时显示具有高多边形数的3D对象。

在本教程中,我将向您介绍Poly API。 我还将向您展示如何使用Android的Processing处理您下载的3D资源。

先决条件

要充分利用本教程,您需要:

1.获取API密钥

您对Poly API发出的所有HTTP请求都必须带有属于您的API密钥。 要获取密钥,请先登录Google Cloud 控制台并导航至API仪表板。



android应用的模型 android 3d模型_java


接下来,按启用API和服务按钮,展开其他类别,然后选择Poly API

android应用的模型 android 3d模型_python_02

现在,您可以按启用按钮来启用Poly API。



android应用的模型 android 3d模型_js_03


启用API后,会自动为其生成一组API密钥。 您可以打开“ 凭据”选项卡来查看它们。



android应用的模型 android 3d模型_android应用的模型_04


对于本教程,您只需要Android key即可 。 记下它,以便以后使用。

2.项目设置

由于Poly当前没有适用于Android平台的官方工具包,因此您必须直接通过其REST接口使用Poly API。 通过使用针对Kotlin语言优化的Fuel网络库,您可以节省大量时间和精力。 因此,在app模块的build.gradle文件中添加以下implementation依赖

implementation 'com.github.kittinunf.fuel:fuel-android:1.13.0'

为了能够显示从Poly资料库下载的3D资源,您还需要一个渲染引擎。 Android的处理程序附带一个,因此将其添加为另一个依赖项。

implementation 'org.p5android:processing-core:4.0.1'

最后,不要忘记在项目的清单文件中请求INTERNET权限。

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

3.上市资产

要下载Poly资产,您必须知道其唯一ID。 通过使用支持WebGL的浏览器,您可以轻松确定任何资产的ID。 在地址栏中。



android应用的模型 android 3d模型_java_05


但是,如果要允许用户在运行时动态确定他们要使用的资产,则可以使用assets.list REST方法确定这些资产的ID。 该方法允许您使用各种参数(例如关键字,类别和3D文件格式)查找资产。

为了举例说明,现在让我们尝试查找属于animals类别的一些资产的ID。 当然,您可以自由选择任何其他有效类别,例如architecturefoodpeople

在编写HTTP请求之前,最好将API密钥和Poly API的基本URL声明为活动中的常量。

companion object {
    const val key = "Abcdefghabcdefgh1234567810"
    const val baseURL = "https://poly.googleapis.com/v1"
}

使用基本URL,可以构建assets.list REST方法的URL,如下所示:

val listURL = "$baseURL/assets"

此时,您可以通过调用httpGet()方法并将API密钥和所需的类别作为查询参数传递给它来创建有效的HTTP GET请求。 (可选)您可以使用format查询参数来指定所需的资产格式。 Poly支持OBJ,FBX,TILT和其他几种流行的3D格式。

因为该方法异步运行,并且其结果是JSON文档,所以您必须使用responseJSON()方法将事件处理程序附加到该方法。 以下代码向您展示了如何:

listURL.httpGet(listOf(
        "category" to "animals",
        "key" to key,
        "format" to "OBJ"
)).responseJson { _, _, result ->

    // More code here
   
}

在事件处理程序内部,如果请求成功,则可以访问Asset对象的列表。 每个此类对象的name字段均指定其ID。

此外,每个对象都将具有诸如displayNamelicenseauthorName ,您可能会发现它们有用。 现在,让我们简单地打印所有对象的namedisplayName 。 以下代码向您展示了如何:

result.fold({
    // Get assets array
    val assets = it.obj().getJSONArray("assets")

    // Loop through array
    for(i in 0 until assets.length()) {
        // Get id and displayName
        val id = assets.getJSONObject(i).getString("name")
        val displayName = 
                assets.getJSONObject(i).getString("displayName")

        // Print id and displayName
        Log.d("POLY", "(ID: $id) -- (NAME: $displayName)")
    }
}, {
    // In case of an error
    Log.e("POLY", "An error occurred")
})

如果您现在运行应用程序,则应该能够在Android Studio的Logcat窗口中看到以下输出。



android应用的模型 android 3d模型_java_06


4.下载资产

拥有资产的唯一ID后,您可以将其直接附加到Poly API的基本URL上以创建资产URL。

// some asset id
val assetID = "assets/3yiIERrKNQr"

// its url
val assetURL = "$baseURL/$assetID"

再次使用httpGet()方法对资产URL进行HTTP GET请求时,您将获得一个仅包含一个Asset对象的JSON文档。

assetURL.httpGet(listOf("key" to key))
        .responseJson { _, _, result ->
            result.fold({
                val asset = it.obj()
        
                // More code here
        
            }, {
                Log.e("POLY", "An error occurred")
            })
        }

正如您在上面的代码中可能已经注意到的那样,此请求也必须具有提及您的API密钥的查询参数。

在上一步中,您已经学习了如何使用Asset对象中存在的某些字段。 现在,您所需要做的就是使用对象中存在的formats数组确定与资产关联的文件的URL和名称。 数组中的每个项目将具有三个重要字段:

  • formatType ,它使您可以确定资产的类型
  • root ,其中包含与资产关联的主文件的名称和URL
  • resources ,其中包含有关与资产关联的所有辅助文件的详细信息,例如材质和纹理

如果使用OBJ格式,则主文件将是包含顶点和面数据的.obj文件,而辅助文件通常将是包含有关所用材质数据的.mtl文件。 以下代码显示了如何确定主文件和辅助文件的URL:

var objFileURL:String? = null
var mtlFileURL:String? = null
var mtlFileName:String? = null

val formats = asset.getJSONArray("formats")

// Loop through all formats
for(i in 0 until formats.length()) {
    val currentFormat = formats.getJSONObject(i)

    // Check if current format is OBJ
    if(currentFormat.getString("formatType") == "OBJ") {
        // Get .obj file details
        objFileURL = currentFormat.getJSONObject("root")
                                .getString("url")

        // Get the first .mtl file details
        mtlFileURL = currentFormat.getJSONArray("resources")
                        .getJSONObject(0)
                        .getString("url")

        mtlFileName = currentFormat.getJSONArray("resources")
                        .getJSONObject(0)
                        .getString("relativePath")
        break
    }
}

在上面的代码中,除了.mtl文件的URL外,我们还使用relativePath字段确定其名称。 这样做很重要,因为名称被硬编码到.obj文件的mtllib元素中,并且不应更改。

一旦获得了两个文件的URL,就可以使用Fuel库的httpDownload()方法下载它们。 将它们下载到应用程序的专用存储目录中的方法如下,其绝对路径可以使用filesDir属性确定:

// download and store obj file as asset.obj
objFileURL!!.httpDownload().destination { _, _ ->
    File(filesDir, "asset.obj")
}.response { _, _, result ->
    result.fold({}, {
        Log.e("POLY", "An error occurred")
    })
}

// download and store mtl file without
// changing its name
mtlFileURL!!.httpDownload().destination { _, _ ->
    File(filesDir, mtlFileName)
}.response { _, _, result ->
    result.fold({}, {
        Log.e("POLY", "An error occurred")
    })
}

5.显示资产

您将需要3D画布来绘制下载的Poly资产。 要创建一个,您必须扩展Processing for Android库提供的PApplet类。 但是,默认情况下,以这种方式创建的画布仅支持2D形状。 要将其配置为也绘制3D形状,请覆盖settings()方法并将P3D作为参数传递给fullScreen()方法,这也会使画布与用户的屏幕一样大。

val canvas = object : PApplet() {
    override fun settings() {
        fullScreen(PConstants.P3D)
    }

    // More code here
}

接下来,在类内部创建一个新属性,将Poly资产表示为PShape对象。

var myPolyAsset: PShape? = null

要初始化该属性,请覆盖setup()方法并调用loadShape()方法,将下载的.obj文件的绝对路径作为参数传递给它。

override fun setup() {
    myPolyAsset = loadShape(File(filesDir, "asset.obj").absolutePath)
}

现在,您可以通过重写draw()方法开始在画布上draw() 。 在该方法内部,您需要做的第一件事是调用background()方法,以确保始终在空白画布上绘制。

override fun draw() {
    background(0)
        
    // More code here
}

直接绘制时,大多数Poly资产看起来很小而且倒置。 您可以通过使用自定义相机或使用画布转换来解决此问题。 为了使本教程简单直观,让我们使用画布转换。

要增加资产的大小,请使用scale()方法并将较大的负值传递给它。 该值必须为负,以确保资产垂直翻转。 (可选)您可以使用translate()方法沿X和Y轴调整其位置。 以下代码向您展示了如何:

scale(-50f)
translate(-4f,-14f)

现在,您可以继续通过调用shape()方法来绘制资产。

shape(myPolyAsset)

画布当前不属于活动的视图层次结构的一部分。 因此,如果您尝试立即运行应用程序,将无法看到资产。 要解决此问题,请首先将一个新的FrameLayout小部件添加到活动的布局XML文件中。

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/canvas_holder">
</FrameLayout>

然后,使用画布创建一个新的PFragment实例,并将其指向FrameLayout小部件。

val fragment = PFragment(canvas)
fragment.setView(canvas_holder, this)

此时,您可以再次运行该应用程序以查看资产。



android应用的模型 android 3d模型_python_07


结论

现在,您知道如何使用Poly API搜索和下载3D资源。 在本教程中,您还学习了如何使用Android的Processing处理和渲染这些资产。

值得注意的是,Poly上的许多资产都是使用Google Blocks创建的,Google Blocks是HTC Vive和Oculus Rift用户可以使用的应用程序。 如果您拥有这些VR耳机,请考虑创建并提交自己的模型。

要了解有关Poly API的更多信息,可以参考官方文档

翻译自: https://code.tutsplus.com/tutorials/how-to-use-free-3d-models-from-google-poly-in-android-apps--cms-31356