- Home /
Draw an arc around a sphere
I found a similar question to this one, but I wanted to make sure am I going in the right direction. The other similar quiestion mentiones drawing parabola around a sphere. Not sure if this would be the same.
So yes I have two ships and a planet in between, I need to establish an energy link between the ships. The solution must work in all 3 dimensions.
The first idea I got was to use LineRenderer and draw middle point where the beam should twist after the ray casted passes trough the planet. Then I wanted to apply Bezier curve to make it curved instead of zig-zag straight line.
However I am not mathematician though I understand well trygonometry and algebraic calculations. I managed to find some distances with the data I already have, but still I cannot calculate the right point (x, y, z) where should that arc middle point be standing.
Here is what I came up with:
This is only in 2D but in 3D would more complicated. Known parameters: spaceship 1 postion, spaceship 2 position, planet center, raycast hit point, raycast mid point. Doing some maths with Pytagorean theroem and such I found the distance, c1, c2, a1, a2 and b. If I were to get the point where the normal hits the ray casted I could possibly get some point away from the planet and draw mid point in my Line Renderer to connect the spaceships.
I could try some equations but it is overwhelming at the moment. Am I going in the right direction or is there a better way to achieve the same thing?
I know this is more maths than programming but anyway someboy might find this useful.
Answer by spinnerbox · Sep 28, 2015 at 03:39 PM
I found a simple solution by using vectors and the cross product of vectors. This solution works with more than one planet and also with planets away from the origin point. Here it is:
Vector3 hitPoint = rayHit.point;
Vector3 planetCenter = rayHit.transform.position;
Vector3 side1 = spaceShip1Pos - planetCenter;
Vector3 side2 = spaceShip2Pos - planetCenter;
Vector3 normal = Vector3.Cross(side1, side2);
if (normal == Vector3.zero)
{
normal = new Vector3(0, 2, 0);
}
Vector3 newBeamPoint = Vector3.Cross(normal.normalized, side1.normalized).normalized * surfaceDistance + planetCenter;
So you take two vectors (side1 and side2) from the planet center to the ships and generate a cross vector product which is normal to the plane made by those two vectors. If you do again cross product of one of the calculated normal and one of the two sides, specifically side1 you will get a vector which is always normal to the ray casted from the ships and the planet center. If you were to change side2 instead of side1 you will need a minus in front of Vector3.Cross at newBeamPoint line.
The if statement checks if the normal is equal to (0, 0, 0) and this happens when the ray casted travels trough the plane center and the scene origin. In that case I chose custom vector of (0, 2, 0).
Answer by Bunny83 · Sep 27, 2015 at 04:44 PM
Well, one way is to don't use trigonometry at all but simply use a repulsion rule and simply use a direct line of several connected points (50 for example) and use something like this(requires webplayer and browser with NPAPI support). This however has problems when the ships are at the exact opposite side. Well, most approaches have certain problems since it's impossible to derive a direction around the sphere but this one will completely break in that case.
The other, probably more clean way, is to use your approach. To determine the middle point you just need to do:
Vector3 s1;
Vector3 s2;
Vector3 pCenter;
float pRadius;
float dist; // additional distance from the planet's surface
Vector3 sCenter = (s1 + s2)*0.5f;
Vector3 dir = (sCenter - pCenter).normalized;
dir *= pRadius + dist;
Vector3 arcMidpoint = pCenter + dir;
You might want to calculate 2 additional mid points between ship1 and the arc midpoint and ship2 and the arc midpoint. This can be done the same way. Just replace either s2 or s1 with arcMidpoint and repeat those steps.
To calculate meaningful bezier tangents you want to use vectors that are actual tangents of the sphere. The whole problem can be reduced to a 2d problem once you have the arc midpoint. You just need to calculate the normal of the plane where your arc lies in. This can be done by:
Vector3 planeNormal = Vector3.Cross(s1-s2, dir).normalized;
This vector will point towards you in your drawing. With this normal you can easily calculate the tangent in each midpoint.
Vector3 tangent = Vector3.Cross(planeNormal, dir).normalized;
This tangent will be perpendicular to the sphere and points towards ship2
-tangent
will be the other direction towards ship1.
To get a smooth curve you'll need to find proper tangent points. Usually you calculate the point based on the distance between the endpoints.
If you don't know how to calculate the points on a cubic bezier curve, see this answer.
But this seems same as my previous solution with drawing a line from the planet center to the middle point between the ships and when I get too close to the planet with one of the ships the arc goes trough the planet :)
This works well only when the ships are on the same distance away from the planet. Will try to find more general solution
Your answer
Follow this Question
Related Questions
Bezier curve confusion on 2 points 1 Answer
Bezier curver using LineRenderer 0 Answers
Raycasting along line renderer width 1 Answer
Raycast2D ignores gameobject 0 Answers