localRotation is not rotating around the cube center - android

Sceneform 1.15 on Android
I want to make that the cube renderable is rotating around the own centar.
val anchorNode = AnchorNode().apply {
setParent(scene)
worldPosition = Vector3(2f, 3f, 0f)
}
scene.addChild(anchorNode)
dieNode = Node().apply {
setParent(anchorNode)
localRotation = Quaternion.eulerAngles(Vector3(10f,20f,60f))
name = "die"
renderable = it
}
I made an animator that is supposed to only rotate the cube around its own center.
private fun roll() {
val anim = createAnimator()
val node = scene.findByName("die")!!
anim.target = node
anim.setDuration(9000)
anim.start()
}
private fun createAnimator() : ObjectAnimator {
val o1 = Quaternion.eulerAngles(Vector3(-90f,180f,90f))
val animator = ObjectAnimator()
animator.setObjectValues(o1)
animator.setPropertyName("localRotation")
animator.setEvaluator(QuaternionEvaluator())
animator.setInterpolator(LinearInterpolator())
animator.setAutoCancel(true)
return animator
}
But, it happens that while cube is rotating, it is also moved which is not desired behavior.
Screenshots where one of the symetrically placed die in world should be only rotated:

The position is not centred for the Cube object. If it is off the centre with respect to the parent object, it will rotate around (0,0,0), if it lies off this axis - the object will move in a circle, not rotate.

Related

How to rotate ImageVector’ pathData in Compose

I am trying to implement similar animation like this, with Jetpack Compose
figure: https://dribbble.com/shots/4762799-Microinteraction-Exploration-002
For the play icon’s transformation (from a triangle to a rectangle) , it not difficult to get it done by using path morphing animation.After reading some gist, I found that I can build an ImageVector by supplying the pathData , that's new to me~
While for ****the part on the right, the rotation of the cube object. Well, maybe I should call that a rolling-over or whatever, because the cube changed its pivot after -90 degrees.
I'm wondering that wether I can create a VectorGroup for the cube’s pathData and animate it by updating its group parameters.
re: androidx.compose.ui.graphics.vector.ImageVector.Builder#addGroup
ImageVector.Builder(defaultWidth = 100.dp, defaultHeight = 100.dp, viewportWidth = 100, viewportHeight = 100)
.addGroup(name = "CubeRotation", rotate = params.rotate, pivotX = params.pivotX, pivotY = params.pivotY,)
.addPath(pathData = pathData, fill = SolidColor(Color.LightGray))
.clearGroup()
.build()
Here I trying to update the pivotX halfway through the animation, so I divide it into two section:
// rotate -90 degrees twice with different pivot
val rotate = if (fraction <= 0.5f) {
lerp(0f, -180f, fraction)
} else {
lerp(0f, -180f, fraction - 0.5f)
}
// change the pivotX
val pivotX = if (fraction <= 0.5f) 52f else 30f
GroupParams(
pivotX = pivotX,
pivotY = 100f,
rotate = rotate,
)
Frustratedly, after rotating by the first -90 degrees, the transformation that this rotation performed will NOT persist, -or- its transformation NOT being applied after the half time of the transition.
fraction: 0~0.5
fraction: 0.5~1
The code sample I've uploaded: IndicatorDrawable.kt
Can I implement the rotate transformation by just updating the pathData ?
For me, the VectorGroup in ImageVector looks like creating AnimatedVectorDrawable in xml, or maybe I should try some traditional way like ObjectAnimationSet in View system ?

How to reset a transformable node added to sceneview?

I like to know how can we reset the scaling of a node on button click,
I have added a TransformableNode with functionality to rotate and scale on users gesture
what I need is after all the transactions if the user clicks a button I need to reset the model to its initial size and rotation,
The rotation is working fine but the scaling doesn't have any effect, how can we do that?
Following is the method I Used to reset the node
private fun resetModel(){
modelDragTransformableNode.localRotation = Quaternion.axisAngle(Vector3(0f, 0f, 0f), 00f)
modelDragTransformableNode.localScale = Vector3(1f, 1f, 1f)
}
The method used to add the node to sceneview
private fun addNodeToScene(model: ModelRenderable) {
if (sceneView != null) {
val transformationSystem = makeTransformationSystem()
modelDragTransformableNode = NewDragTransformableNode(transformationSystem)
modelDragTransformableNode.localPosition = Vector3(0f, -0.3f, -2.0f)
modelDragTransformableNode?.renderable = model
val collisionShape: Box = modelDragTransformableNode.collisionShape as Box
sceneView.getScene().addChild(modelDragTransformableNode)
val collisionShape2: Box = modelDragTransformableNode.collisionShape as Box
modelDragTransformableNode.select()
sceneView.getScene()
.addOnPeekTouchListener { hitTestResult: HitTestResult?, motionEvent: MotionEvent? ->
transformationSystem.onTouch(
hitTestResult,
motionEvent
)
}
}
}
The scale is not updating because it's controlled by the ScaleController's onUpdated method. Try disabling the scale controller before setting the scale and then enable it again:
modelDragTransformableNode.getScaleController().setEnabled(false)
If it doesn't work you can always use a custom scale controller with exposed setScale method (see example).

Android matrix postscale with aniamtion

A think a do not understand enough matrices theory to build animation for matrix inside image view.
For example i have some value that i want to set in postScale method to my matrix.
I use this code
fun animateScale(scale_factor:Float,matrix: Matrix)
{
matrix.postScale(scale_factor,scale_factor)
image_view.imageMatrix = matrix
}
This code makes scale to image view as it is expected. But i cant calculate postScale with animation. I tried different approaches using ValueAnimator.ofFloat(0f, 1f) or ValueAnimator.ifInt(1, 100) but result is weird.
Updated
I added my tries of animating as it asked in comments.
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.addUpdateListener(
{ animation ->
val current_anim_value = animation.animatedValue as Float
val factor_to_anim = scale_factor - ( scale_factor * current_anim_value)
matrix.postScale(factor_to_anim, factor_to_anim)
image_view.imageMatrix = matrix
})
animator.duration = 3000
animator.start()

Added object on vertical plane always rotated in ARCore

I am adding an image on vertical plane in Sceneform ARFragment. But it always get rotated. The code is working fine on horizontal plane. My code for placing images on vertical Plane is as follow:
arFragment.setOnTapArPlaneListener { hitResult: HitResult,
plane: Plane,
motionEvent: MotionEvent ->
if(!isOnceTapedOnSurface) {
val anchor = hitResult.createAnchor()
val anchorNode = AnchorNode(anchor)
anchorNode.setParent(arFragment.arSceneView.scene)
andy = TransformableNode(arFragment.transformationSystem)
if(plane.type == Plane.Type.VERTICAL) {
val anchorUp = anchorNode.up
andy.setLookDirection(Vector3.up(), anchorUp)
}
andy.setParent(anchorNode)
andy.renderable = andyRenderable
andy.select()
// arFragment.arSceneView.planeRenderer.isVisible = false
isOnceTapedOnSurface = true
}
}
To fix this issue you can use the above solution. But you should rotate an object using world rotation. Don't use local rotation. We need to zero the rotation value. If you are using local rotation, the object will behave anchor(parent) rotation. So by using world rotation we can control the object.
String planeType = "";
//When tapping on the surface you can get the anchor orientation
if (plane.getType() == Plane.Type.VERTICAL){
planeType = "Vertical";
}else if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING){
planeType = "Horizontal_Upward";
}else if (plane.getType() == Plane.Type.HORIZONTAL_DOWNWARD_FACING){
planeType = "Horizontal_Downward";
}else {
planeType = "Horizontal";
}```
// First set object world rotation zero
transformableNode.setWorldRotation(Quaternion.axisAngle(new Vector3(0, 0f, 0), 0));
// check plane type is vertical or horizontal if it is vertical below logic will work.
if (planeType.equals("Vertical")) {
Vector3 anchorUp = anchorNode.getUp();
transformableNode.setLookDirection(Vector3.up(), anchorUp);
}
To fix this issue you need to set public Pose getCenterPose(). It returns the pose of the center of the detected plane, defined to have the origin. The pose's transformed +Y axis will be point normal out of the plane, with the +X and +Z axes orienting the extents of the bounding rectangle.
anchor = mySession.createAnchor(plane.getCenterPose())
When the its trackable state is TRACKING, this pose is synced with the latest frame. When its trackable state is PAUSED, an identity pose will be returned.
Your code could be the following:
Anchor newAnchor;
for (Plane plane : mSession.getAllTrackables(Plane.class)) {
if(plane.getType() == Plane.Type.VERTICAL &&
plane.getTrackingState() == TrackingState.TRACKING) {
newAnchor = plane.createAnchor(plane.getCenterPose());
break;
}
}
One more thing from Google ARCore software engineers:
Keep objects close to anchors.
When anchoring objects, make sure that they are close to the anchor you are using. Avoid placing objects farther than a few meters from the anchor to prevent unexpected rotational movement due to ARCore's updates to world space coordinates.
If you need to place an object more than a few meters away from an existing anchor, create a new anchor closer to this position and attach the object to the new anchor.

adding localRotation moves ArCore Node?

This has me totally puzzled. I put this node in the scene, but as soon as I add "localRotation", the node moves. It looks fine if I don't move it (positioned centered where I expect). Do I have to initialize the Quaternion so that it's perpendicular to the floor plane/pose?
scene?.apply {
boundingBoxNode?.let { scene.removeChild(it) }
boundingBoxNode = null
viewModel.boundingBox?.let { box ->
MaterialFactory.makeTransparentWithColor(this#MyActivity, boundingBoxColor)
.thenAccept { material ->
boundingBoxNode = Node().apply {
renderable = ShapeFactory.makeCube(box.size, box.center, material).apply {
collisionShape = null
isShadowCaster = false
}
localRotation = box.rotation
scene.addChild(this)
}
}
}
FYI, don't set the center on ShapeFactory.makeCube(box.size, box.center). Do this instead (ShapeFactory.makeCube(box.size, Vector3.zero()) so that it's centered on the origin.
You can then do:
worldPosition = box.center to move it.
I was rotating a box that wasn't centered :facepalm:

Categories

Resources