3
\$\begingroup\$

enter image description here

Sorry for my english. I added a picture to explain what i want. I want rotate Big Sphere to make the black point locate in front of camera. (to the white point's position) not black point moving, whole sphere moving.

or is it better to move camera to black point?

which API should i use?

\$\endgroup\$
9
  • \$\begingroup\$ How is that "black point" represented technically? Is it a child object of the sphere? Do you have its position as a Vector3 in world space / local space? Is it a direction in euler angles? Is it a point on the texture you still need to detect through image recognition? The easiest case to program would be if the black point would be exactly on transform.position.forward. \$\endgroup\$ Commented Nov 16, 2019 at 16:12
  • \$\begingroup\$ the black point is Vector3 in world space. and the black point is just image to explain this question. it is just a vector. \$\endgroup\$ Commented Nov 16, 2019 at 16:15
  • \$\begingroup\$ Something along the lines of sphere.transform.position + (blackSpot - sphere.transform.position).normalized * distance; camera.transform.LookAt(sphere.transform); \$\endgroup\$ Commented Nov 16, 2019 at 17:07
  • \$\begingroup\$ @Draco18s that looks like an answer to me! :) \$\endgroup\$ Commented Nov 16, 2019 at 17:20
  • 1
    \$\begingroup\$ Rotating the sphere would involve doing the reverse math that LookAt does, which is annoying and complicated and I'm not being paid enough to figure it out. You might be able to get LookAt to make the sphere look away from the negative of the dot's position, but I am not sure on the exact differential there. \$\endgroup\$ Commented Nov 17, 2019 at 8:10

3 Answers 3

1
\$\begingroup\$

You have the vector that goes from the center of the sphere to the camera, let us call it a. That should be a = camera.transform.position - sphere.transform.position;.

Similarly you have the vector that goes from the center of the sphere to black spot, let us call it b. I have no clue how you defined this one, I'll trust you have the vector.

You need to rotate the sphere in such way that b lines up with a. That is, you need to rotate in the plane defined by the center of the sphere and the vectors a and b. And the angle you need to rotate is the angle between a and b.

It seems natural to use an axis-angle representation. We need the angle between a and b, and a vector perpendicular to both to act as rotation axis.

Getting the angle between two vectors is easy, you call Vector3.Angle. And for the axis, we can use cross product, you call Vector3.Cross.

Now you can create a quaternion from angle-axis by calling Quaternion.AngleAxis and that would be a rotation that lines up your vectors.

It looks like this:

var angle = Vector3.Angle(a, b); var axis = Vector3.Cross(a, b); var rotation = Quaternion.AngleAxis(angle, axis); 

And you need to compose that rotation with the current transform rotation (that is quaternion multiplication).

Alternatively, you can use Transform.RotateAround:

sphere.transform.RotateAround(sphere.transform.position, axis, angle); 

A little caveat: I don't know if it will line them up such that the black point goes to the camera or away from it. I believe it depends on whatever or not the black point is roughly in the direction of the camera to begin with or not.

You can use the sign dot product to check if the vectors are looking roughly in the same direction (call Vector3.Dot). A positive dot product means the vectors are roughly in the same direction (the way I have described it, you want a and b going the same direction).

You can invert the rotation if needed (based on the check of the sing of the dot product). There are many ways to create the inverted rotation, including using the negative of the angle or the axis in AngleAxis, or Quaternion.Inverse.

\$\endgroup\$
1
  • \$\begingroup\$ Quaternion.FromToRotation is a convenience method that rotates from vector a to vector b, so you don't have to do the angle/axis math step by step. \$\endgroup\$ Commented Nov 3, 2020 at 13:09
0
\$\begingroup\$

you can use Quaternion.FromToRotation it is someting like this

transform.rotation = Quaternion.FromToRotation(startRotation, desiredRotation);

Have a nice day

\$\endgroup\$
1
  • \$\begingroup\$ Can you include some tips on how to compute desiredRotation? \$\endgroup\$ Commented Oct 3, 2020 at 22:40
0
\$\begingroup\$

If you're trying to animate the sphere in the way you described, you need to interpolate between the two rotations. I haven't tried this, so you'll have to experiment on your own, but, you should be able to use Quaternion.Lerp or Quaternion.Slerp to achieve this.

Slerp (sphericall interpolation), for example, takes in two quaternions - one representing the initial rotation, and another one representing the target rotation:

Quaternion Slerp(Quaternion initial, Quaternion final, float t); 

The t parameter ranges from 0 - initial rotation, to 1 - final rotation.

Assuming the sphere is untransformed (not rotated) to begin with, you can use Quaternion.identity as the initial rotation, otherwise, use transform.localRotation, where transform is the sphere's transform.

Since your point on the sphere is represented by a vector, you can use Quaternion.FromToRotation to get the quaternion representing the final rotation.

Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection); 

This will produce a rotation that, when applied to the sphere, reorients your point so that it's "looking" in the toDirection.

the black point is Vector3 in world space

The fromDirection and toDirection vectors need to be expressed in (sphere's) local space (unless your sphere happens to sit at [0, 0, 0]). To get a vector in local space, just subtract (vector in world space) - (sphere's location).

The toDirection is just (camera location) - (sphere's location). I'm not sure if you need to normalize these vectors (probably not).

Finally, you'd apply the interpolation over time; you'll have to calculate t so that it reaches 1 after your desired animation time has elapsed:

elapsedAnimTime += deltaTime; float t = elapsedAnimTime / desiredTotalAnimTime; transform.localRotation = Quaternion.Slerp(initial, final, t); 

Note that you'll (probably) have to put in some conditions to stop animating after t reaches 1.

Because it's a quaternion, it should reorient your sphere using the "shortest path" (it won't go through some weird angle).

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.