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).
Related
I have a background images and an image. I am changing the pivot values of RotationAnimation according to the drag event. But as soon as I stop dragging, the background starts to circle on the page instead of spinning around.
val listener = View.OnTouchListener(function = { view, motionEvent ->
if(motionEvent.action == MotionEvent.ACTION_MOVE) {
view.y = motionEvent.rawY -view.height/2
view.x = motionEvent.rawX -view.width/2
rotateAnimation(view.pivotX,view.pivotY)
binding.bgDragable.y = view.y
binding.bgDragable.x = view.x
}
if(motionEvent.action == MotionEvent.ACTION_UP){
rotateAnimation(view.x, view.y)
}
true
})
this is the function where i created the rotation animation.
private fun rotateAnimation(pivotX: Float, pivotY: Float){
val rotateAnim = RotateAnimation(0F, 360.0F,Animation.ABSOLUTE, pivotX,
Animation.ABSOLUTE, pivotY)
rotateAnim.duration = 2000
rotateAnim.repeatCount = Animation.INFINITE
binding.bgDragable.animation = rotateAnim
}
How should I get the pivot values so that at the end of the drag event, the background rotates around itself.
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.
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()
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:
I'm attempting to anchor a ViewRenderable to a ModelRenderable so that it appears on the top right corner of the Renderable & I use the following snippet to place it.
//Sets the button north east of the node that it is attached to
viewRenderable.localPosition = Vector3(
parent.right.x,
parent.up.y,
parent.right.z
)
However, the viewRenderable doesn't really show up as intended. It rather shows up a few floats away from the top right corner of the ModelRenderable. Is there a way I can get the actual bounds of the ModelRenderable so that I can place it better? I want the end result something similar to the below picture.
What I have right now is this image:
My code:
//Creation of ViewRenderable
val shareButton = ViewRenderable.builder()
.setVerticalAlignment(ViewRenderable.VerticalAlignment.TOP)
.setHorizontalAlignment(ViewRenderable.HorizontalAlignment.RIGHT)
.setView(view.getARFragment().context, R.layout.share)
.build()
//Creation of ModelRenderable
val video = ModelRenderable.builder()
.setSource(view.getARFragment().context,
Uri.parse("chroma_key_video.sfb")).build()
//Adding Model to the scene | Extension method called on ParentNode
private fun Node.attachVideoNode(videoRenderable: ModelRenderable?) {
//Show another anchor object
val videoNode = Node()
//Attach the new node with the node that this method was called on
videoNode.setParent(this#attachVideoNode)
//Set local position
videoNode.localPosition = this.right //This works fine. The video is rendered next to another ModelRenderable.
// Set the scale of the node so that the aspect ratio of the video is correct.
val videoWidth = mediaPlayer?.videoWidth?.toFloat()
val videoHeight = mediaPlayer?.videoHeight?.toFloat()
videoHeight?.let {
videoWidth?.apply {
videoNode.localScale = Vector3(
(this#apply / it), 1.0f, 1.0f)
}
}
// Start playing the video when the first node is placed.
mediaPlayer?.apply {
if (!isPlaying) {
start()
// Wait to set the renderable until the first frame of the video becomes available.
// This prevents the renderable from briefly appearing as a black quad before the video
// plays.
texture?.surfaceTexture
?.setOnFrameAvailableListener { surfaceTexture ->
videoNode.renderable = videoRenderable
surfaceTexture.setOnFrameAvailableListener(null)
//Attach a share button
videoNode.attachShareButton()
ARApplication.log("The local rotation of this videoRenderable is ${videoNode.localRotation}")
}
} else
videoNode.renderable = videoRenderable
}
}
//Attaches a share button to any node that it is called on. | Extension method called on VideoNode
private fun Node.attachShareButton() {
//Create a new node to display the close button
var closeButton = Node()
closeButton.setParent(this)
ARApplication.log("The close button has been added to the scene at world coordinates: ${closeButton.worldPosition}")
//Set the close button as a renderable
closeButton.renderable = view.getViewRenderable()
}
I don't know exactly what you already got, but this is a solution for put a text on the ViewRenderable on the top and on the right
x x V
x O x
x x x
V - ViewRenderable
O - ModelRenderable
ViewRenderable.builder()
.setView(context, R.layout.VIEW_LAYOUT_XXXXX)
.setHorizontalAlignment(ViewRenderable.HorizontalAlignment.RIGHT) //Here is where the magic happens
.build()
.thenAccept(
(renderable) -> {
YOUR_NODE_XXXXX.setRenderable(renderable);
TextView textView = (TextView) renderable.getView();
textView.setText(YOUR_TEXT_XXXXX);
})
.exceptionally(
(throwable) -> {
throw new AssertionError(R.string.ERROR_MSG_XXXXX, throwable);
});
I let a _XXXXXin everything that you should change with your code.
Result should be like this
EDIT. Ok looking your code now this is what you should do:
Firs you need to inicialize your view (I think your "close button" should be your share button)
private fun Node.attachShareButton() {
if(shareButton == null){ //Create a new node to display the share button
var shareButton = Node()
shareButton.setParent(this)
shareButton.renderable = view.getViewRenderable()
shareButton.setLocalPosition(new Vector3(SIZE_OF_BUTTON, SIZE_OF_BUTTON, SIZE_OF_BUTTON));
}
if (infoCard == null) {
infoCard = new Node();
infoCard.setParent(this);
infoCard.setEnabled(false);
infoCard.setLocalPosition(new Vector3(0.0f, SIZE_OF_BUTTON*0.55f, 0.0f));
ViewRenderable.builder()
.setView(context, R.layout.share)
.setHorizontalAlignment(ViewRenderable.HorizontalAlignment.RIGHT)
.build()
.thenAccept(
(renderable) -> {
infoCard.setRenderable(renderable);
})
.exceptionally(
(throwable) -> {
throw new AssertionError(R.string.ERROR_MSG_XXXXX, throwable);
});
}
shareButton.onTap(HitTestResult hitTestResult, MotionEvent motionEvent){
if (infoCard == null) {
return;
}
infoCard.setEnabled(!infoCard.isEnabled()); //This show your card when the button is click/tap
}
}