Character align to surface normal ???

Hi i am at a Student Project, which could not be solved with standart unity gravity

Character are suposed to move around a small planet.
The Planet is not absolutely regular so it’s not possible to solve this just by radius

The only solution i could think about is to keep the characters aligned to the surface normal. Does anyone have an Idea how to do so?

I do, actually. Let me grab it.

transform.rotation = Quaternion.FromToRotation (Vector3.up, hit.normal);

Pretty sure that does it. Let me know if it works.

2 Likes

it say’s:

Unknown identifier: ‘hit’

:roll:

D’oh. I forgot the raycasting part. Here, try this instead:

var hit : RaycastHit;
var castPos = Vector3(transform.position.x,transform.position.y-.25,transform.position.z);
if (Physics.Raycast (castPos, -transform.up, hit)) {
	transform.rotation = Quaternion.FromToRotation (Vector3.up, hit.normal);
}
2 Likes

I have tried that way, transform.up = hit.normal, and

var surfaceRot : Quaternion = Quaternion.FromToRotation (Vector3.up, hit.normal);    
		var newRot : Quaternion = surfaceRot * Quaternion.AngleAxis(transform.rotation.eulerAngles.y, Vector3.up); 
		transform.rotation = Quaternion.Slerp(transform.rotation, newRot, 0.5);

however none of them work as desired.

Thanks a lot :slight_smile:

The cube are aligning semselves to the surface, one gets a jiggling. I gues it rotates and then the raycast gets a new position and it rotates again. I’m more into 3d- modeling, and now starting with javascript. My next step will be to figure out how to send the cube to the position of the raycast hit plus half the height of the Object.

aha I did put the script in a function update > jiggling. In a fuction start the align and then stay calm. I gues it’s more complicated with a character controler.

With a Character Controller, you’ld probably want to make use of the OnControllerColliderHit() event rather than using raytracing, I imagine.

Ok here is my problem http://www.youtube.com/watch?v=HF71eido9ow (You might want to watch in HD so you can see scripts).

Any ideas?

to Lab013: I could not figure out your problem watching the video. Maybe you could post the spript and tell me your goal.

I’ve been trying to work out a similar problem recently where I wanted to have an object orbit a planet like Mario Galaxy.

After getting through quaternion hell (flipping at south pole) I eventually ended up with this:

using UnityEngine;
using System.Collections;

public class OrbitPlanet : MonoBehaviour {
	public float rotationSpeed = 120.0f;
	public float translationSpeed = 10.0f;  
	public float height = 2.0f; 			//height from ground level 
	private Transform centre;				//transform for planet
	private float radius;					//calculated radius from collider
	public SphereCollider planet;			//collider for planet

	void Start () {
		//consider scale applied to planet transform (assuming uniform, just pick one)
		radius = planet.radius * planet.transform.localScale.y;
		centre = planet.transform;
		//starting position at north pole
		transform.position = centre.position + new Vector3(0,radius+height,0);
	}
	
	void Update () {
		//translate based on input		
		float inputMag  = Input.GetAxis("Vertical")*translationSpeed*Time.deltaTime;
		transform.position += transform.forward * inputMag;
        //snap position to radius + height (could also use raycasts)
		Vector3 targetPosition = transform.position - centre.position;
		float ratio = (radius + height) / targetPosition.magnitude;
		targetPosition.Scale( new Vector3(ratio, ratio, ratio) );
		transform.position = targetPosition + centre.position;
		//calculate planet surface normal                		
		Vector3 surfaceNormal = transform.position - centre.position;
		surfaceNormal.Normalize();
		//GameObject's heading
		float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed;
		Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
		//align with surface normal
		transform.rotation = Quaternion.FromToRotation( transform.up, surfaceNormal) * transform.rotation;
		//apply heading rotation
		transform.rotation = headingDelta * transform.rotation;
	}
}

All you have to do to try it out is:

Create a sphere object and scale every axis up a bit (say by 10-15m)
Create a cube and attach this script to it
Script requires a sphere collider as an argument so select the sphere game object.
Use arrow keys to fly around!

Hope it helps
Nick

1 Like

Thanks for the script NKoufou , thought i wont be able to learn much from it cause i’m just a little into javascript, but thanks. I tried it the way you described an it works pretty smoth. Does it work on iregular surfaces too ?

My projekt at the moment looks like this:

You are looking at the planet from the top down.
You turn the planet and the cube slide acros to stay in the top middle, there’s a point actracting them.

I used the script from Podperson he posted in his topic: Faux Gravity making my brain spin
And there’s the problem: The Planet moves and the cubes (riggid bodies) slide. I did not figure out how riggid bodies could be transported on a moving Platform. They remain at their position and then fell down. They should stick to moving surface but move on their own when needed to.

The section that updates the position can be changed to use a Collider.Raycast instead for irregular surfaces, this would return a contact point and a normal.

I am not quite sure I understand what you are trying to do (you want the rigid body objects to stick to the surface when you rotate the planet?) but you might want to turn off gravity in the rigid body components to prevent them from sliding off.

Nick

Imagine a Platform which is sliding from one side of the room to another. ( like we knew from 1000 games )
You walkaround and when you jump on the moving Platform you can walk on it AND get transported by it’s movement.

In Unity’s Rigid bodies You jump on the platform and it slides away under your feet. Same with the moving Planet.

1 Like

I converted NKoufou’s script to javascript for JS users.

Im curious though, it was mentioned that this could be used for irregular survaces using raycast. how would that work?

var rotationSpeed = 120.0;
var translationSpeed = 10.0; 
var height = 2.0;          //height from ground level
private var centre : Transform;            //transform for planet
private var radius : float;               //calculated radius from collider
var planet : SphereCollider ;         //collider for planet


function Start () 

{
      //consider scale applied to planet transform (assuming uniform, just pick one)
      radius = planet.radius * planet.transform.localScale.y;
      centre = planet.transform;
      //starting position at north pole
      transform.position = centre.position + Vector3(0,radius+height,0);
}

function Update () 

{
      //translate based on input      
      var inputMag  = Input.GetAxis("Vertical")*translationSpeed*Time.deltaTime;
      transform.position += transform.forward * inputMag;
        //snap position to radius + height (could also use raycasts)
      targetPosition = transform.position - centre.position;
      var ratio = (radius + height) / targetPosition.magnitude;
      targetPosition.Scale(Vector3(ratio, ratio, ratio) );
      transform.position = targetPosition + centre.position;
      //calculate planet surface normal                      
      surfaceNormal = transform.position - centre.position;
      surfaceNormal.Normalize();
      //GameObject's heading
      var headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed;
      headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
      //align with surface normal
      transform.rotation = Quaternion.FromToRotation( transform.up, surfaceNormal) * transform.rotation;
      //apply heading rotation
      transform.rotation = headingDelta * transform.rotation;
   }

When you use a raycast, the RaycastHit object it returns contains a field for the normal of the surface at the point where the ray hit. You can use this to align the character (basically, just cast a ray downward to get the normal of the floor).

I used NKoufou’s code to create a simple box cruising around on a sphere but when I place objects on the sphere for it to run into I have some issues. I am using the JS code. When I apply rigid bodies to my obstacles they fly off into space, but if I apply it to the cube the collision works fine. However when the collision occurs my box bounces back and is stuck in this crazy spin. If I leave out the rigid bodies all together then my box just passes through the other meshes. Does anyone know how to stop the rotation or create collisions without the rigid bodies?

Thanks for your help

You shouldn’t add rigidbodies to objects that are not supposed to move in the scene (like the obstacles). When you say the box goes into a crazy spin, how exactly is it spinning? It is possible to limit the rotation of a rigidbody object to one or two axes using a configurable joint component if that seems like it would fix the problem.

Thanks for the reply Andeeee but I figured it out. It has something to do with the geometry of the cube. When the two flat faces collide it caused an odd rotation on the y axis. I decided instead to also apply a sphere collider to my cube on the “planet”. Now the rotation is gone. I’m not really sure how this changed, but my only educated conclusion is the geometry of the colliders. Hmm… Guess I’ll never know but it works!