Last active
August 19, 2022 17:15
-
-
Save ThomasGorisse/7436e553dbe3daef302798f9c5cb0406 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package io.github.sceneview.components | |
| import android.animation.ObjectAnimator | |
| import com.google.android.filament.* | |
| import com.google.ar.sceneform.rendering.* | |
| import dev.romainguy.kotlin.math.* | |
| import io.github.sceneview.* | |
| import io.github.sceneview.animation.TransformAnimator | |
| import io.github.sceneview.gesture.* | |
| import io.github.sceneview.math.* | |
| const val defaultSmoothSpeed = 1.0f | |
| interface TransformComponent : Component { | |
| val transformManager get() = engine.transformManager | |
| val transformInstance: Int @EntityInstance get() = transformManager.getInstance(entity) | |
| /** | |
| * ### The node position to locate it within the coordinate system of its parent | |
| * | |
| * Default is `Position(x = 0.0f, y = 0.0f, z = 0.0f)`, indicating that the node is placed at | |
| * the origin of the parent node's coordinate system. | |
| * | |
| * **Horizontal (X):** | |
| * - left: x < 0.0f | |
| * - center horizontal: x = 0.0f | |
| * - right: x > 0.0f | |
| * | |
| * **Vertical (Y):** | |
| * - top: y > 0.0f | |
| * - center vertical : y = 0.0f | |
| * - bottom: y < 0.0f | |
| * | |
| * **Depth (Z):** | |
| * - forward: z < 0.0f | |
| * - origin/camera position: z = 0.0f | |
| * - backward: z > 0.0f | |
| * | |
| * ------- +y ----- -z | |
| * | |
| * ---------|----/---- | |
| * | |
| * ---------|--/------ | |
| * | |
| * -x - - - 0 - - - +x | |
| * | |
| * ------/--|--------- | |
| * | |
| * ----/----|--------- | |
| * | |
| * +z ---- -y -------- | |
| */ | |
| var position: Position | |
| get() = transform.position | |
| set(value) { | |
| transform = Transform(value, quaternion, scale) | |
| } | |
| /** | |
| * ### The node world-space position | |
| * | |
| * The world position of this node (i.e. relative to the [SceneView]). | |
| * This is the composition of this component's local position with its parent's world | |
| * position. | |
| * | |
| * @see worldTransform | |
| */ | |
| var worldPosition: Position | |
| get() = worldTransform.position | |
| set(value) { | |
| position = (worldToParent * Float4(value, 1f)).xyz | |
| } | |
| /** | |
| * TODO: Doc | |
| */ | |
| var quaternion: Quaternion | |
| get() = transform.quaternion | |
| set(value) { | |
| transform = Transform(position, value, scale) | |
| } | |
| /** | |
| * ### The node world-space quaternion | |
| * | |
| * The world quaternion of this node (i.e. relative to the [SceneView]). | |
| * This is the composition of this component's local quaternion with its parent's world | |
| * quaternion. | |
| * | |
| * @see worldTransform | |
| */ | |
| var worldQuaternion: Quaternion | |
| get() = worldTransform.toQuaternion() | |
| set(value) { | |
| quaternion = worldToParent.toQuaternion() * value | |
| } | |
| /** | |
| * ### The node orientation in Euler Angles Degrees per axis from `0.0f` to `360.0f` | |
| * | |
| * The three-component rotation vector specifies the direction of the rotation axis in degrees. | |
| * Rotation is applied relative to the node's origin property. | |
| * | |
| * Default is `Rotation(x = 0.0f, y = 0.0f, z = 0.0f)`, specifying no rotation. | |
| * | |
| * Note that modifying the individual components of the returned rotation doesn't have any effect. | |
| * | |
| * ------- +y ----- -z | |
| * | |
| * ---------|----/---- | |
| * | |
| * ---------|--/------ | |
| * | |
| * -x - - - 0 - - - +x | |
| * | |
| * ------/--|--------- | |
| * | |
| * ----/----|--------- | |
| * | |
| * +z ---- -y -------- | |
| */ | |
| var rotation: Rotation | |
| get() = quaternion.toEulerAngles() | |
| set(value) { | |
| quaternion = Quaternion.fromEuler(value) | |
| } | |
| /** | |
| * ### The node world-space rotation | |
| * | |
| * The world rotation of this node (i.e. relative to the [SceneView]). | |
| * This is the composition of this component's local rotation with its parent's world | |
| * rotation. | |
| * | |
| * @see worldTransform | |
| */ | |
| var worldRotation: Rotation | |
| get() = worldTransform.rotation | |
| set(value) { | |
| quaternion = worldToParent.toQuaternion() * Quaternion.fromEuler(value) | |
| } | |
| /** | |
| * ### The node scale on each axis. | |
| * | |
| * Reduce (`scale < 1.0f`) / Increase (`scale > 1.0f`) | |
| */ | |
| var scale: Scale | |
| get() = transform.scale | |
| set(value) { | |
| transform = Transform(position, quaternion, value) | |
| } | |
| /** | |
| * ### The node world-space scale | |
| * | |
| * The world scale of this node (i.e. relative to the [SceneView]). | |
| * This is the composition of this component's local scale with its parent's world | |
| * scale. | |
| * | |
| * @see worldTransform | |
| */ | |
| var worldScale: Scale | |
| get() = worldTransform.scale | |
| set(value) { | |
| scale = (worldToParent * scale(value)).scale | |
| } | |
| /** | |
| * @see TransformManager.getTransform | |
| * @see TransformManager.setTransform | |
| */ | |
| var transform: Transform | |
| get() = transformManager.getTransform(transformInstance) | |
| set(value) { | |
| transformManager.setTransform(transformInstance, value) | |
| } | |
| /** | |
| * @see TransformManager.getWorldTransform | |
| */ | |
| val worldTransform: Transform | |
| get() = transformManager.getWorldTransform(transformInstance) | |
| /** | |
| * ### The transform from the world coordinate system to the coordinate system of the parent node | |
| */ | |
| val worldToParent: Transform | |
| get() = parentTransformable?.let { inverse(it.worldTransform) } ?: Transform() | |
| /** | |
| * @see TransformManager.getParent | |
| * @see TransformManager.setTransform | |
| */ | |
| var parentTransformable: TransformComponent? | |
| get() = transformManager.getParent(transformInstance).takeIf { it != 0 }?.let { | |
| object : TransformComponent { | |
| override val engine = this@TransformComponent.engine | |
| override val entity = it | |
| } | |
| } | |
| set(value) { | |
| transformManager.setParent(transformInstance, value?.transformInstance ?: 0) | |
| } | |
| /** | |
| * ### The node scale | |
| * | |
| * - reduce size: scale < 1.0f | |
| * - same size: scale = 1.0f | |
| * - increase size: scale > 1.0f | |
| */ | |
| fun setScale(scale: Float) { | |
| this.scale.xyz = Scale(scale) | |
| } | |
| /** | |
| * ## Change the node transform | |
| * | |
| * @see position | |
| * @see quaternion | |
| * @see scale | |
| */ | |
| fun transform( | |
| position: Position = this.position, | |
| quaternion: Quaternion = this.quaternion, | |
| scale: Scale = this.scale, | |
| smooth: Boolean = false, | |
| smoothSpeed: Float = defaultSmoothSpeed | |
| ) { | |
| if (smooth) { | |
| smooth(position, quaternion, scale, smoothSpeed) | |
| } else { | |
| this.position = position | |
| this.quaternion = quaternion | |
| this.scale = scale | |
| } | |
| } | |
| /** | |
| * ## Change the node transform | |
| * | |
| * @see position | |
| * @see rotation | |
| * @see scale | |
| */ | |
| fun transform( | |
| position: Position = this.position, | |
| rotation: Rotation = this.rotation, | |
| scale: Scale = this.scale, | |
| smooth: Boolean = false, | |
| smoothSpeed: Float = defaultSmoothSpeed | |
| ) = transform(position, rotation.toQuaternion(), scale, smooth, smoothSpeed) | |
| /** | |
| * ## Smooth move, rotate and scale at a specified speed | |
| * | |
| * @see position | |
| * @see quaternion | |
| * @see scale | |
| * @see speed | |
| */ | |
| fun smooth( | |
| position: Position = this.position, | |
| quaternion: Quaternion = this.quaternion, | |
| scale: Scale = this.scale, | |
| speed: Float = defaultSmoothSpeed | |
| ) = smooth(Transform(position, quaternion, scale), speed) | |
| /** | |
| * ## Smooth move, rotate and scale at a specified speed | |
| * | |
| * @see position | |
| * @see quaternion | |
| * @see scale | |
| * @see speed | |
| */ | |
| fun smooth( | |
| position: Position = this.position, | |
| rotation: Rotation = this.rotation, | |
| scale: Scale = this.scale, | |
| speed: Float = defaultSmoothSpeed | |
| ) = smooth(Transform(position, rotation, scale), speed) | |
| /** | |
| * ## Smooth move, rotate and scale at a specified speed | |
| * | |
| * @see transform | |
| */ | |
| fun smooth(transform: Transform, speed: Float = defaultSmoothSpeed) { | |
| val maxLength = floatArrayOf( | |
| distance(this.position, transform.position), | |
| length(this.quaternion - transform.quaternion), | |
| distance(this.scale, transform.scale) | |
| ).maxOrNull()!! | |
| TransformAnimator.ofTransform(this, transform).apply { | |
| setAutoCancel(true) | |
| duration = (maxLength * speed).toLong() | |
| }.start() | |
| } | |
| fun animatePositions(vararg positions: Position): ObjectAnimator = | |
| TransformAnimator.ofPosition(this, *positions) | |
| fun animateQuaternions(vararg quaternions: Quaternion): ObjectAnimator = | |
| TransformAnimator.ofQuaternion(this, *quaternions) | |
| fun animateRotations(vararg rotations: Rotation): ObjectAnimator = | |
| TransformAnimator.ofRotation(this, *rotations) | |
| fun animateScales(vararg scales: Scale): ObjectAnimator = | |
| TransformAnimator.ofScale(this, *scales) | |
| fun animateTransforms(vararg transforms: Transform): ObjectAnimator = | |
| TransformAnimator.ofTransform(this, *transforms) | |
| /** | |
| * ### Rotates the node to face a point in world-space | |
| * | |
| * @param targetPosition The target position to look at in world space | |
| * @param upDirection The up direction will determine the orientation of the node around the direction | |
| * @param smooth Whether the rotation should happen smoothly | |
| */ | |
| fun lookAt( | |
| targetPosition: Position, | |
| upDirection: Direction = Direction(y = 1.0f), | |
| smooth: Boolean = false | |
| ) { | |
| val newQuaternion = lookAt( | |
| targetPosition, | |
| worldPosition, | |
| upDirection | |
| ).toQuaternion() | |
| if (smooth) { | |
| smooth(quaternion = newQuaternion) | |
| } else { | |
| transform(quaternion = newQuaternion) | |
| } | |
| } | |
| /** | |
| * ### Rotates the node to face another node | |
| * | |
| * @param targetNode The target node to look at | |
| * @param upDirection The up direction will determine the orientation of the node around the direction | |
| * @param smooth Whether the rotation should happen smoothly | |
| */ | |
| fun lookAt( | |
| targetTransformable: TransformComponent, | |
| upDirection: Direction = Direction(y = 1.0f), | |
| smooth: Boolean = false | |
| ) = lookAt(targetTransformable.worldPosition, upDirection, smooth) | |
| /** | |
| * ### Rotates the node to face a direction in world-space | |
| * | |
| * The look direction and up direction cannot be coincident (parallel) or the orientation will | |
| * be invalid. | |
| * | |
| * @param lookDirection The desired look direction in world-space | |
| * @param upDirection The up direction will determine the orientation of the node around the look direction | |
| * @param smooth Whether the rotation should happen smoothly | |
| */ | |
| fun lookTowards( | |
| lookDirection: Direction, | |
| upDirection: Direction = Direction(y = 1.0f), | |
| smooth: Boolean = false | |
| ) { | |
| val newQuaternion = lookTowards(worldPosition, -lookDirection, upDirection).toQuaternion() | |
| if (smooth) { | |
| smooth(quaternion = newQuaternion) | |
| } else { | |
| transform(quaternion = newQuaternion) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment