I did this so long ago… even posted in here in the forums.
There are a few methods you can use. The LookAt with the up vector is decent, it almost gets you what you want.
Your poblem is actually 2 fold. 1, how to get the person “on” the planet then 2, how to get them to go and move in the right direction.
- you can use 1 of 3 methods here.
You can either use a raycast from the where the person is or outside the planet to teh center of the planet to get the current position of where your feet should be. (this can be done using layers, layering the planet and all the objects on it. This is ideal for games like Mario World where you can have peaks and valleys. Using the person’s locations towards teh center will get you bridges and tunnels as well.
You can use a static distance. (Player.position - World.position).normalized * radius. This gets you the exact point on the sphere where things are supposed to be. No valleys, no hills.
Physics. Lock the rotation and handle that mathematically and let the physics engine handle gravity. Every FixedUpdate you should add force in the direction of the core. (World.position - Player.position).normalized * gravityAmount
- Headings are fairly simple to control. Everything is “local” Press A or D and rotate locally on Y axis. No muss. To set your “vertical” you will need to still use LookAt as suggested, but once you have the current position and heading, this is incredibly easy.
You need to be aware of how you are using collision control though. Physics do really good here. Mathematical positioning such as the first option above will require you to use CapsuleCast or something similar to figure collosion.
UpVector = (player.position - world.position); // this gives you a vector measuring where gravity should be coming from
PlayerRadius = UpVector.magnitude; // this gives you the current amount of distance from the center that the player is
LookAtPoint = (player.position + player.forward) - world.position; // very similar to UpVector, but measures 1 unit in front of the player
LookAtPoint = LookAtPoint.normalized * PlayerRadius; // this sets the look at point to the same distance from the center as the player
player.LookAt(LookAtPoint, UpVector); // this simply makes the player look at his forward and keeps that look point even with the world.
Now this code is not “exact” it simulates the look at point by using the world radius as a key. This is not normal. This would give very poor results on spheres less than like 20 units or so. It would give great results on large spheres as you can’t actually see the difference in the game.
To do the “correctly” I believe that you would need to use Vector3.Cross() to get the proper offset from the world center, then add the palyer’s radius to that in the player direction. Since I am not running Unity right now, I can’t test that. 
Edit:
Oh yeah, Cross works perfectly.
Vector3 up = transform.position - world.position;
Vector3 LookAt = Vector3.Cross(up, -transform.right) + up;
transform.LookAt(LookAt, up);