Skip to content

Instantly share code, notes, and snippets.

@bgigle
Created September 3, 2019 18:21
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save bgigle/60cf502c87fc22e9621b4514392c07c9 to your computer and use it in GitHub Desktop.
Augmented Marble reference code
<!--
Copyright 2018 Google LLC.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HelloSceneformActivity">
<fragment
android:id="@+id/ux_fragment"
android:name="com.google.ar.sceneform.ux.ArFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom|center_horizontal"
android:background="#80000000">
<TextView
android:id="@+id/tv_scale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
android:layout_weight="0"
android:text="Scale" />
<SeekBar
android:id="@+id/sb_scale"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
android:layout_weight="1"
android:max="110" />
<TextView
android:id="@+id/tv_scale_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="8dp"
android:layout_weight="0"
android:text="mm" />
</LinearLayout>
</FrameLayout>
/*
* Copyright 2018 Google LLC. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.ar.sceneform.samples.hellosceneform
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.Gravity
import android.view.MotionEvent
import android.widget.SeekBar
import android.widget.Toast
import com.google.ar.core.HitResult
import com.google.ar.core.Plane
import com.google.ar.sceneform.AnchorNode
import com.google.ar.sceneform.collision.Box
import com.google.ar.sceneform.math.Vector3
import com.google.ar.sceneform.rendering.ModelRenderable
import com.google.ar.sceneform.ux.ArFragment
import com.google.ar.sceneform.ux.TransformableNode
import kotlinx.android.synthetic.main.activity_ux.*
import java.util.*
/**
* This is an example activity that uses the Sceneform UX package to make common AR tasks easier.
*/
class HelloSceneformActivity : AppCompatActivity() {
private lateinit var sbScale: SeekBar
private var arFragment: ArFragment? = null
private var thinkerRenderable: ModelRenderable? = null
private val nodeList = ArrayList<TransformableNode>()
// CompletableFuture requires api level 24, FutureReturnValueIgnored is not valid
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!checkIsSupportedDeviceOrFinish(this)) {
return
}
setContentView(R.layout.activity_ux)
arFragment = supportFragmentManager.findFragmentById(R.id.ux_fragment) as ArFragment
sbScale = findViewById(R.id.sb_scale)
sbScale.progress = 50
sbScale.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
tv_scale_data.text = "${i + 10} mm"
for (node in nodeList) {
val box = node.renderable.collisionShape as Box
val renderableSize = box.size
val renderableHeightInMeters = renderableSize.z
val desiredHeightInMeters = (i.toFloat() + 10.0f) / 1000.0f
val scaleZ = desiredHeightInMeters / renderableHeightInMeters
node.parent.worldScale = Vector3(scaleZ, scaleZ, scaleZ)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// do nothing
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// do nothing
}
})
tv_scale_data.text = "${sbScale.progress + 10} mm"
// When you build a Renderable, Sceneform loads its resources in the background while returning
// a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
ModelRenderable.builder()
.setSource(this, R.raw.thinker)
.build()
.thenAccept { renderable -> thinkerRenderable = renderable }
.exceptionally {
val toast = Toast.makeText(this, "Unable to load thinker renderable", Toast.LENGTH_LONG)
toast.setGravity(Gravity.CENTER, 0, 0)
toast.show()
null
}
arFragment!!.setOnTapArPlaneListener { hitResult: HitResult, _: Plane, _: MotionEvent ->
if (thinkerRenderable == null) {
return@setOnTapArPlaneListener
}
// Create the Anchor.
val anchor = hitResult.createAnchor()
val anchorNode = AnchorNode(anchor)
anchorNode.setParent(arFragment!!.arSceneView.scene)
// Create the transformable thinker and add it to the anchor.
val thinker = TransformableNode(arFragment!!.transformationSystem)
thinker.setParent(anchorNode)
thinker.renderable = thinkerRenderable
thinker.select()
val box = thinker.renderable.collisionShape as Box
val renderableSize = box.size
val renderableHeightInMeters = renderableSize.z
val desiredHeightInMeters = (sbScale.progress.toFloat() + 10.0f) / 1000.0f
val scaleZ = desiredHeightInMeters / renderableHeightInMeters
anchorNode.worldScale = Vector3(scaleZ, scaleZ, scaleZ)
nodeList.add(thinker)
}
}
companion object {
private val TAG = HelloSceneformActivity::class.java.simpleName
private const val MIN_OPENGL_VERSION = 3.0
/**
* Returns false and displays an error message if Sceneform can not run, true if Sceneform can run
* on this device.
*
*
* Sceneform requires Android N on the device as well as OpenGL 3.0 capabilities.
*
*
* Finishes the activity if Sceneform can not run
*/
fun checkIsSupportedDeviceOrFinish(activity: Activity): Boolean {
val openGlVersionString = (activity.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
.deviceConfigurationInfo
.glEsVersion
if (java.lang.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
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment