Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasGorisse committed May 29, 2024
2 parents 1fb782e + e5bdb39 commit 22c421b
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sceneview.sample.armodelviewer

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
Expand All @@ -18,9 +19,12 @@ import io.github.sceneview.ar.getDescription
import io.github.sceneview.ar.node.AnchorNode
import io.github.sceneview.math.Position
import io.github.sceneview.node.ModelNode
import io.github.sceneview.node.ViewNode
import io.github.sceneview.sample.doOnApplyWindowInsets
import io.github.sceneview.sample.setFullScreen
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MainActivity : AppCompatActivity(R.layout.activity_main) {

Expand All @@ -42,6 +46,8 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
}
}

var anchorNodeView: View? = null

var trackingFailureReason: TrackingFailureReason? = null
set(value) {
if (field != value) {
Expand Down Expand Up @@ -102,6 +108,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
this@MainActivity.trackingFailureReason = reason
}
}
sceneView.viewNodeWindowManager = ViewNode.WindowManager(this)
}

fun addAnchorNode(anchor: Anchor) {
Expand All @@ -111,25 +118,44 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
isEditable = true
lifecycleScope.launch {
isLoading = true
sceneView.modelLoader.loadModelInstance(
"https://sceneview.github.io/assets/models/DamagedHelmet.glb"
)?.let { modelInstance ->
addChildNode(
ModelNode(
modelInstance = modelInstance,
// Scale to fit in a 0.5 meters cube
scaleToUnits = 0.5f,
// Bottom origin instead of center so the model base is on floor
centerOrigin = Position(y = -0.5f)
).apply {
isEditable = true
}
)
}
buildModelNode()?.let { addChildNode(it) }
buildViewNode()?.let { addChildNode(it) }
isLoading = false
}
anchorNode = this
}
)
}

suspend fun buildModelNode(): ModelNode? {
sceneView.modelLoader.loadModelInstance(
"https://sceneview.github.io/assets/models/DamagedHelmet.glb"
)?.let {
modelInstance ->
return ModelNode(
modelInstance = modelInstance,
// Scale to fit in a 0.5 meters cube
scaleToUnits = 0.5f,
// Bottom origin instead of center so the model base is on floor
centerOrigin = Position(y = -0.5f)
).apply {
isEditable = true
}
}
return null
}

suspend fun buildViewNode(): ViewNode? {
return withContext(Dispatchers.Main) {
val engine = sceneView.engine
val materialLoader = sceneView.materialLoader
val windowManager = sceneView.viewNodeWindowManager ?: return@withContext null
val view = LayoutInflater.from(materialLoader.context).inflate(R.layout.view_node_label, null, false)
val viewNode = ViewNode(engine, windowManager, materialLoader, view, true, true)
viewNode.position = Position(0f, -0.2f, 0f)
anchorNodeView = view
viewNode
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp" android:color="#EDEDED" />
<solid android:color="#99000000" />
<corners android:radius="7dp" />
</shape>
34 changes: 34 additions & 0 deletions samples/ar-model-viewer/src/main/res/layout/view_node_label.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="@drawable/bg_black_transparent_rounded"
android:gravity="center_horizontal">


<TextView
android:id="@+id/node_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="View Node Test"
android:textStyle="bold"
android:textSize="24sp"
android:textColor="@android:color/white"
/>

<TextView
android:id="@+id/node_dist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="100m"
android:textSize="20sp"
android:textColor="@android:color/white"
/>

</LinearLayout>
59 changes: 51 additions & 8 deletions sceneview/src/main/java/io/github/sceneview/node/ModelNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import io.github.sceneview.model.lightEntities
import io.github.sceneview.model.model
import io.github.sceneview.model.renderableEntities
import io.github.sceneview.utils.intervalSeconds
import kotlin.math.abs

/**
* Create the ModelNode from a loaded model instance.
Expand Down Expand Up @@ -110,7 +111,11 @@ open class ModelNode(
override var name = super<ChildNode>.name
}

data class PlayingAnimation(val startTime: Long = System.nanoTime(), val loop: Boolean = true)
data class PlayingAnimation(
val startTime: Long = System.nanoTime(),
var speed: Float = 1f,
val loop: Boolean = true
)

val renderableNodes = modelInstance.renderableEntities.map {
RenderableNode(modelInstance, it)
Expand Down Expand Up @@ -233,21 +238,46 @@ open class ModelNode(
* animation definition. Uses `TransformManager`.
*
* @param animationIndex Zero-based index for the `animation` of interest.
* @param speed The rate at which the `animation` plays. Reverses the `animation` if negative.
* Pauses the `animation` if zero.
* @param loop Specifies if the `animation` should repeat forever.
*
* @see Animator.getAnimationCount
*/
fun playAnimation(animationIndex: Int, loop: Boolean = true) {
fun playAnimation(animationIndex: Int, speed: Float = 1f, loop: Boolean = true) {
if (animationIndex < animationCount) {
playingAnimations[animationIndex] = PlayingAnimation(loop = loop)
playingAnimations[animationIndex] = PlayingAnimation(speed = speed, loop = loop)
}
}

/**
* @see playAnimation
* @see Animator.getAnimationName
*/
fun playAnimation(animationName: String, loop: Boolean = true) {
animator.getAnimationIndex(animationName)?.let { playAnimation(it, loop) }
fun playAnimation(animationName: String, speed: Float = 1f, loop: Boolean = true) {
animator.getAnimationIndex(animationName)?.let { playAnimation(it, speed, loop) }
}

/**
* Sets the rate at which the `animation` is played.
*
* @param animationIndex Zero-based index for the `animation` of interest.
* @param speed The rate at which the `animation` plays. Reverses the `animation` if negative.
* Pauses the `animation` if zero.
* @see playAnimation
*/
fun setAnimationSpeed(animationIndex: Int, speed: Float) {
if (animationIndex < animationCount) {
playingAnimations[animationIndex]?.speed = speed
}
}

/**
* @see setAnimationSpeed
* @see Animator.getAnimationName
*/
fun setAnimationSpeed(animationName: String, speed: Float) {
animator.getAnimationIndex(animationName)?.let { setAnimationSpeed(it, speed) }
}

fun stopAnimation(animationIndex: Int) {
Expand Down Expand Up @@ -383,18 +413,31 @@ open class ModelNode(
super.onFrame(frameTimeNanos)

model.popRenderable()
applyAnimations(frameTimeNanos)
animator.updateBoneMatrices()
}

private fun applyAnimations(frameTimeNanos: Long) {
playingAnimations.forEach { (index, animation) ->
if (animation.speed == 0f) return@forEach

animator.let { animator ->
val elapsedTimeSeconds = frameTimeNanos.intervalSeconds(animation.startTime)
animator.applyAnimation(index, elapsedTimeSeconds.toFloat())
val adjustedTimeSeconds = elapsedTimeSeconds.toFloat() * abs(animation.speed)
val animationDuration = animator.getAnimationDuration(index)
val animationTime: Float = if (animation.speed > 0) {
adjustedTimeSeconds
} else {
animationDuration - adjustedTimeSeconds
}

if (!animation.loop && elapsedTimeSeconds >= animator.getAnimationDuration(index)) {
animator.applyAnimation(index, animationTime)

if (!animation.loop && adjustedTimeSeconds >= animationDuration) {
playingAnimations.remove(index)
}
}
}
animator.updateBoneMatrices()
}
}

Expand Down

0 comments on commit 22c421b

Please sign in to comment.