- Home /
Moving and scaling an object according to hand position.
Hi,
I need some help with my college project. I have a cylinder and need it to act as a coil. For example, if I touched the cylinder's surface it's height will decrease (scaled in the y direction) as if pressing on a coil then when I remove my hand it returns back to its original size.
This is what I reached till now but I still have some problems that I can't solve.
public class Deformation : MonoBehaviour {
Vector3 tempPos;
private void InteractionManager_SourceUpdated(InteractionSourceUpdatedEventArgs hand)
{
if (hand.state.source.kind == InteractionSourceKind.Hand)
{
Vector3 handPosition;
hand.state.sourcePose.TryGetPosition(out handPosition);
float negXRange = transform.position.x - transform.localScale.x;
float posXRange = transform.position.x + transform.localScale.x;
float negYRange = transform.position.y - (transform.localScale.y / 2);
float posYRange = transform.position.y + (transform.localScale.y / 2);
float negZRange = transform.position.z - transform.localScale.z;
float posZRange = transform.position.z + transform.localScale.z;
float handX = handPosition.x;
float handY = handPosition.y;
float handZ = handPosition.z;
if ((negXRange <= handX) && (handX <= posXRange) && (negYRange <= handY) && (handY <= posYRange) && (negZRange <= handZ) && (handZ <= posZRange))
{
tempPos.y = handPosition.y;
transform.localScale = tempPos;
}
else
{
tempPos.y = 0.3f;
transform.localScale = tempPos;
}
}
}
// Use this for initialization
void Start()
{
tempPos = transform.localScale;
InteractionManager.InteractionSourceUpdated += InteractionManager_SourceUpdated;
}
I attached two scripts to my object (cylinder) the TapToPlace script from the HoloToolKit and the deformation script stated above. The problem is when I deploy to my HoloLens to test, when I place the cylinder first to the needed place then try to deform it after that, it is placed but not deformed. If I tried it the other way around both work. Any ideas why does the deformation script does not work after the TapToPlace one?
The cylinder when viewed by my HoloLens is somehow transparent. I mean that I can see my hand through it. I need it to be more solid.
I wonder if there is something like a delay that I can use because when I use the deformation script stated above the cylinder is scaled to my hand position then scaled back to its default size very fast and appears as if blinking.
At first I place the cylinder on a setup (something as a table for example) then I begin to deform it. When I commented the else part in the deformation script stated above, it was scaled and left stable without returning to the original size. It is scaled symmetrically so its height is decreased from up and down resulting in the base of the cylinder becomes away from the table. I need the base of the cylinder to be always stable and touching the table under it.
Note: I am using Unity 2017.3.1f1 (64-bit) - HoloToolkit-Unity-2017.2.1.3
Thank you in advance.
Firstly, I'm kind of just trying to hit at things here as generally college projects will check for plagiarism / getting help so you might want to be careful!
I'm assu$$anonymous$$g you haven't shared your TapToPlace script or I'm being very imperceptive! That will make it hard to debug why the order matters, I can't see anything in the script you have shared that would cause it though using scale alone to check "collisions" is dubious and I would suggest using a bounding box multiplied by scale ins$$anonymous$$d.
You might need to explain this more, I haven't used anything HoloLens-esque before so again might be misunderstanding on my part, but if your shader is opaque then basically you can't do anything more (brightness settings come to $$anonymous$$d), this seems likely to not be something unity can solve and more a HoloLens issue.
Look at Coroutines for delayed operations / animation-esque behaviour. I'd also have a think about the actual physics of a spring, i.e how it works off of forces rather than directly moving to new positions. You could store a force value based on how much you have compressed the spring, and apply some mathematics based on that to provide a more believable motion.
This issue could be fixed in two ways really, the easiest way would be to centre you model so that the origin (where the arrows show up in unity) is at the bottom edge, that was scaling will go 'towards' this origin position and so will only effect one side of the spring. Two you can do some maths to work out the size difference of the new scale vs the original scale and then add HALF of that value to the position to realign the bottom edge with it's starting position.
Again this is a somewhat brief overview, if you need and are allowed more help with particular areas then let me know!
The TapToPlace script is the one in HoloTool$$anonymous$$it 2017.2.1.3. This where you can find it: https://github.com/$$anonymous$$icrosoft/$$anonymous$$ixedRealityToolkit-Unity/blob/master/Assets/HoloToolkit/Spatial$$anonymous$$apping/Scripts/TapToPlace.cs
Can you please help me with the bounding box? How to use it or things like that. Please excuse my questions as i am new to mixed reality development. I searched for a documentation or something like that but couldn't find any helpful link.$$anonymous$$y object is green with components --> R: 0, G: 255, B: 0, A: 255. I checked the brightness and it is turned up to full. I am using the standard shader. Do you mean that I need to use the opaque shader ins$$anonymous$$d of the standard one?
I searched about the Coroutines for delayed operations and going to try it. Can you please clarify what do you mean by "I'd also have a think about the actual physics of a spring, i.e how it works off of forces rather than directly moving to new positions. You could store a force value based on how much you have compressed the spring, and apply some mathematics based on that to provide a more believable motion.". I don't understand how can I do that.
I would prefer to do it the first way as you said. I only have a problem how to make my centre at the bottom edge.
Thank you very much for your concern @Scribe .
Answer by Scribe · Apr 21, 2018 at 08:38 PM
1
So this one looks like it may be fixed by converting the hand position to local space. Currently I assume if the object is at (0,0,0) then it works because the hand position is between (-1, -1, -1) and (1, 1, 1). But when you move the object to , let's say (20, 20, 20) having a hand on it will mean the hand position is (20, 20, 20) and therefore not between the (-1, -1, -1) and (1, 1, 1) constraints that you calculate from your scale. You can make the hand position into local space using the InverseTransformPoint function.
2
I'm not sure I can help on this one much, the standard shader should be fine. might be worth adding some screenshots and let us know if this is happening in the editor; just in the build; or just on the HoloLens.
3
Here's a little physics about elastic potential: http://hyperphysics.phy-astr.gsu.edu/hbase/pespr.html
The important bit is Hooke's Law F = -kx
. In this scenario you can calculate x
as the difference between your current scale and your 'resting' scale, k is an arbitrary constant that you'll want to adjust based on the scale of your setup, for a 1x2x1 sized spring you probably want it around the 50 mark, unless you are going for a slinky effect!
F is a force, but you can equate this directly to an acceleration using F=ma
where m is mass, if you aren't simulating exact scientific outcomes or collisions between more than one object, you can normally just say mass is 1 and therefore F=a
and adjust the other numbers to get the desired effect.
Applying that acceleration value is pretty easy, the important bit is that you need to accumulate it in a speed variable over time, here some code:
[SerializeField]
private float springConstant = 50f;
[SerializeField]
private float dampingFactor = 2f;
[SerializeField]
private float minimumScale = 0.5f;
[SerializeField]
private float maximumScale = Mathf.Infinity;
private Transform t;
private Vector3 initialScale;
void Start()
{
t = transform;
initialScale = t.localScale;
StartCoroutine(SpringMotion());
}
private IEnumerator SpringMotion()
{
float speed = 0;
while (true)
{
float scale = t.localScale.y;
float max = Mathf.Max(minimumScale, maximumScale);
float min = minimumScale;
float displacement = scale - initialScale.y;
// The first bit of this is Hooke's law, followed by some damping due to friction
// you can go pretty complex here if you wanted, but visually no-one will probably notice!
float acceleration = (-displacement * springConstant) - (speed * dampingFactor);
speed += acceleration * Time.deltaTime;
float intendedScale = scale + (speed * Time.deltaTime);
if (intendedScale > max)
{
intendedScale = max;
acceleration = 0;
speed = 0;
}
else if (intendedScale < min)
{
intendedScale = min;
acceleration = 0;
speed = 0;
}
t.localScale = new Vector3(t.localScale.x, intendedScale, t.localScale.z);
yield return null;
}
}
Give this a play, specifically by changing the maximumScale
value as this can be used to mimick what you want from a hand effect, infact if you set the maximumScale
value based on your hand it should look pretty good, you will need to work out what 'scale' a particular hand position means however.
4
This will depend on what you use to model your spring, in Blender for example (from memory so may have missed a step) you would select your spring model, then press tab (or use the drop down menu) to enter edit mode I think. The ctrl+A to select all of your vertices, and then move them all up. When you exit 'edit' mode with the drop down or tab? maybe again!? Then hopefully you will see that you objects origin has stayed the same, but the vertices have moved up. You can use this technique to position your origin to the bottom of your spring.
Your answer
Follow this Question
Related Questions
How do I attach a Created Material A Texture, NormalMap and OcclussionMap? 0 Answers
Multiple Cars not working 1 Answer
Spinning platform C# script correction & wrong texture 1 Answer
Distribute terrain in zones 3 Answers
UV mapping icosphere 1 Answer