Placing objects on a sphere.

So anyways something I’m working on contains a planet ( sphere ) and the game involves placing objects on here. the object would always face in the same direction kinda, not sure how to explain it.

like that. everything’s bottom would be facing towards the center of the planet. How would I implement this? I’m pretty sure its not that hard but i’m stupid at times…

You just need to calculate the normal to the sphere’s surface at the particular location you want the object placed and then rotate the object so that the object’s up vector is equal to the normal.

Sorry, i’m pretty bad at math but I can learn new things. Do you have an example on how I would calculate the normal and what the normal is exactly?

Thanks.

The normal would just be

Vector3 centerOfSphere = sphere.transform.position;

Vector3 placementPosition = placePosition;

Vector3 normal = ( placementPosition - centerOfSphere ).normalized;

Thanks, I will probably figure it out from here.

Yea, and you can basically thik of the normal as the up direction. the point on the sphere would be (normal * radius) + centerOfSphere

You could even take the point on the sphere, subtract the center position, and normalize the resulting vector and that would give you an appropriate up vector.

Sorry I don’t think I quite understand.

If I calculate the normal, and got my mouse position, how would I place the object with the correct rotation?

Instantiate(building, mousePos, normal);

So if you’ve got a mouse position in screen coords you use camera.ScreenPointToRay to get a ray which is a position and direction.

once you’ve got that ray, you can see if it collides with the sphere.

bool CheckRaySphere( Ray ray, Vector3 sphereOrigin, float sphereRadius, out float distance ) { 
    Vector3 localPoint = ray.origin - sphereOrigin;
    float temp = -Vector3.Dot( localPoint, ray.direction );
    float det = temp * temp - Vector3.Dot( localPoint, localPoint ) + sphereRadius * sphereRadius;
    if( det < 0 ) { distance = Mathf.Infinity;  return false; }
    det = Mathf.Sqrt(det);
    float intersection0 = temp - det;
    float intersection1 = temp + det;
    if( intersection0 >= 0 )
    {
        if(intersection1 >= 0 ){
            distance = Mathf.Min(intersection0, intersection1); return true;
        }else{
            distance = intersection0; return true;
        }
    }
    else if( intersection1 >= 0 ){
        distance = intersection1; return true;
    }else{
        distance = Mathf.Infinity; return false;
    }
}

source: Simple Ray/Sphere Collision - Math and Physics - GameDev.net

You would use above function then with that ray like so:

float distance;
if(CheckRaySphere( ray, sphereCenter, sphereRadius, out distance) ){
    // did hit sphere.
    Vector3 position = ray.GetPoint(distance);
    Vector3 normal = ( position - sphereCenter ).normal;
    Quaternion rotation = Quaternion.LookRotation(normal);
    Instantiate(prefab, position, rotation);
}

the look rotation call uses the up direction as forward, which is not ideal. you’ll ahve to figure out what you want forward to be for its angle the object faces. but you should see this working somewhat anyways as is now.

Also i didnt test the code and just ported from that forum site. I’ve used derivatives of that code before and it works.