Can you read this book?

First you have to pick it up.

And you can with my character… in most situations. There’s a bug. Take a look at the picture below.

I have it scripted so when you click on a book nearby, the character moves into position and picks up the book at it’s exact location. The character lifts or lowers his arm at the shoulder, and either bends or extends his elbow, depending on the location of the book. If the book is low he will also lean forward.

The problem is with the shoulder angle controls. Here is the code:

		var bookDir = book.position - shoulder.position;
		var handDir = handDummy.position - shoulder.position;
		var up = shoulder.up;
		var targetBookAngle = Vector3.Angle(bookDir, up);
		var handAngle = Vector3.Angle(handDir, up);
		var shoulderAngle = handAngle - targetBookAngle;

		if(shoulderAngle < -1.0) {						// Lower Arm
			if (armLift / animSpeed < 2) {
			armLift += 1;
			atHeight = false;
			}
			} else 
			if(shoulderAngle > 1.0) {					// Lift Arm
			if (armLift / animSpeed > 0.00) {
			armLift -= 1 * Time.deltaTime * 60;
			atHeight = false;	
			}
			}else atHeight = true;						// On Target
}

The idea works: I find the angle from the shoulder to the book (Angle A, “targetBookAngle”), then from the shooulder to the hand (Angle B, “handAngle”), to figure out their difference (Angle C, “shoulderAngle”). If the result (shoulderAngle) is positive, he lowers his arm; if the result is negative, he lifts it.

Usually this works, but the angle isn’t being read right somehow. If books are too high, he lowers his arm and never gets there. Reading Angle A, “targetBookAngle”, books that are low have a low angle, medium height gives a medium angle, but high books give a low angle also.

Moving from degrees to eulers to quaternarions is very slippery and I’m going wrong somewhere.

Any help is greatly appreciated!

259286--9322--$reachingquestion_155.jpg

That’s why I like to avoid angles and rotations whenever possible :).

If I understand your problem correctly, you wish basically to know if the book is above or below the hand, yes?

If that is the case, you could test it with the following:

var handPlane = new Plane(handDummy.up, handDummy.position);
var dist = handPlane.GetDistanceToPoint(book.position);
if (dist < 0)
  // book below
else if (dist > 0)
  // book above
else
  // book on the plane

Obviously, this trick only works if you setup the correct plane. The plane I suggested in the code is basically parallel to the lower arm. If you want the plane going through the yellow line in your picture you should replace the plane normal (handDummy.up) by something like Vector3.Cross(handDummy.position - shoulder.position, handDummy.right).

Anyway, this kind of approach is only easier if you are more comfortable with vector calculus than with angles ;).

Thanks, Tom, I think you put me on the right track.

Is there any way I can render the Plane so I can see it to help debug?

You could create standard unity plane object (Game Object → Create Other → Plane), link to its transform in your script and whenever you create or change the plane you wish to visualize set the transform as follows:

Plane myPlane = new Plane(normal, point);
planeTransform.position = point;
planeTransform.up = normal;

Obviously the visual aid is not as large as the plane (which is infinite), but it will show how the plane runs within the area you need it.

Thanks.

Something is still off here. I’ve created the plane so I can see it, but it isn’t going through the hand. Now I’m trying to use LookAt and rotate the plane somehow. It’s very confusing.

myPlane.transform.position = shoulder.transform.position; 
myPlane.transform.LookAt(handDummy);

myPlaneBack.transform.position = myPlane.transform.position;
myPlaneBack.transform.rotation = myPlane.transform.rotation;
myPlaneBack.transform.Rotate(180, 0, 0);

When I try to put a rotation into the line, it’s throwing errors at me:

var tempVector = shoulder.transform.rotation.Euler;
var handPlane = new Plane( tempVector,	myPlane.position);

var shoulderAngle = handPlane.GetDistanceToPoint(book.position);

It looks as though tempVector is a position, not a rotation?

tempVector is a “Vector” as opposed to a “Point”.

There is a fundamental difference in vector math between vectors and points that is somewhat obscured in Unity as both are represented by the Vector3 class (and as you have discovered already, Vector3 can also be used to represent euler rotations, but that one I tend to avoid :P).

A point is a point in space, for example the position of your hand. A vector is a direction in space, like an arrow pointing to somewhere. You could think of a vector (or direction) as two points in space: the point where the arrow starts, and the point where the arrow ends. The point where the arrow starts is normally left out when describing a vector and is simply assumed to be (0,0,0). This is why vectors, like points are described with just one set of x,y,z data.

For example in unity, transform.position is the position of the object in world space, transform.forward is the direction the object is facing in world space (the blue arrow in your scene view when you select the object).

The plane in my example is built a vector (the direction the plane is facing (aka ‘normal vector’) and a point (a point somewhere on the plane).

At any rate, your original approach might be a better fit to how you think about geometry. For me, vector stuff is just easier to visualize than angles, but that is not true for every person. The problem can be solved with angles just as well as through vector math.

Thanks again for your explanation. You seem to differentiate between a ‘direction in space, like an arrow pointing to somewhere’ and a ‘rotation’ and I’m not sure there’s a difference there.

In any case, these lines create a plane that I can see and adjust:

myPlane.transform.position = shoulder.transform.position; 
myPlane.transform.LookAt(handDummy);

myPlaneBack.transform.position = myPlane.transform.position;
myPlaneBack.transform.rotation = myPlane.transform.rotation;
myPlaneBack.transform.Rotate(180, 0, 0);

If I can read the rotation of that plane, and use it to create the New Plane, that would work, but I can’t seem to get the vector information.

I’m looking for something like this:

var handPlane = new Plane( myPlane's direction,	shoulder.position);

See what I mean?

I’m pretty flexible with using planes vs. angles. :slight_smile: The gap here isn’t in my 3d visualization. I can visualize a problem using angles or planes as references. The problem is how to program the variables of those references.

I’m getting close, hang in there with me!

A direction and a rotation are fundamentally different. A direction is like me pointing to the north. If you rotate me 90 degrees, I would be pointing to the east after that.

If I would have been pointing to the south when you applied the same rotation, I would now be pointing to the west. The same rotation, but different directions.

In Unity, the direction North would be represented by a vector like (0,0,1), whereas the 90 degree rotation that rotates me east would look like (0,90,0). A direction vector is not expressed in angles, but in world units (meters, yards, feet, miles whatever unit you like for distances).

The thing that makes rotations and angles such a complex subject for me to visualize, is that (90,0,0), (0,90,0) (0,0,90), (-90,0,0), (0,-90,0) and (0,0,-90) are all rotations with a 90 degree angle, but they have completely different effects on where I’m pointing at after applying them to me (to illustrate: if I were facing north, these 6 rotations of 90 degrees would turn me up, east, north, down, west and north respectively).

So a direction is a property and a rotation is an action.

A direction is something, and a rotation does something.

Is that right?