I need some help figuring out how to deal with rotations

I’m a beginner to scripting in unity, and i have some trouble wrapping my mind around dealing with rotations in C#.
All i’m trying to do is to create a child object of my player controller that will always face the ground below it, so i use a raycast facing down to check the surface normal, but out of everything i tried the only code that actually makes the object face the ground is when i simply do “transform.up=MyHit.normal”, but the problem with that is that it overrides the Y rotation of the parent for some reason, here are examples of what it looks like:

what can i do to make this work?

i tried to use Quaternion.Euler like this:

transform.rotation = Quaternion.Euler(Myhit.normal[0], player.rotation.eulerAngles[1], Myhit.normal[2]);

Which does fix the rotation issue, rather surprisingly because it hardly rotates the object in the X and Z axes, it rotates it so slightly that you can hardly see it, like shown here:

when i move it over the terrain the rotation does change, just very slightly, and it doesn’t follow the ground at all like in the first videos…
What did i do wrong here? how can i simply make it move along with the ground like in the first videos but rotate with its parent object like in the last video?
plz help i am really confused…

Anyone?

@tomer20072

Hi there, not exactly sure what you are doing… but you should maybe just create a new rotation;

Quaternion.LookRotation might be all you need, else you could construct a new rotation from vectors forward, surface normal and a perpendicular vector of these two previous.

Ok that sounds good, how can i do that? i mean how would the code go? i couldn’t think of a way to do it with Quaternion.LookRotation, but i actually tried a bunch of different ways with a separate quatrenion for the rotation and then i tried a separate vector 3 for the the ray hit, but no matter how i phrase it with quatrenion.euler, it all just works the same…
it does rotate in the X and Z axes, because i can see the values changing, but it’s rotating so slightly that you can’t even see it, and the rotation value of these axes doesn’t seem go past 0.6-0.7… so clearly something is wrong with the code , so, what is it?

All i need to happen is for the object to have the same Y rotation as the player like in the last video, but also face the ground like in the first two videos.

bump

OK, let’s see if we can make out what you’re trying to do.

You want the child object to align itself with the ground. So its Y rotation is going to stay the same as the parent (more or less), but it’s going to tilt so that it stays parallel with the surface of the ground.

That’s… tricky. So first, you need to stop using phrases like “all I need to happen” regarding this problem. Those phrases imply that it’s simple, and it’s not. :slight_smile:

I happen to have some really cool code (if I do say so myself) that can do this. It casts four rays down (where the “wheels” are in my case, because it’s for a vehicle simulator), and adjusts the rotation of the object to conform to the terrain or other objects it’s driving over as well as possible.

Here’s that code, though it’s not going to work as-is for you unless your situation is very similar to mine (i.e. you have four cylinders that serve as wheels).

/*
This script "grounds" a truck by adjusting its vertical position
and angle so that all four wheels are on the ground, or as close
to it as possible.
*/

using UnityEngine;
using UnityEngine.Events;
using System.Collections.Generic;

public class Grounder : MonoBehaviour {
   
    [Tooltip("Cylinders representing the wheels")]
    public Transform[] wheels;
  
    void Update() {
        // We'll find where the center of each wheel "should" be in order for
        // the bottom of the wheel to rest on the ground.  Collect these up,
        // and then find the proper position & orientation of the truck.
        Vector3[] pts = new Vector3[4];
        int qtyPts = 0;
       
        foreach (Transform w in wheels) {
            float wheelR = (w.localScale.x + w.localScale.z) * 0.25f;
           
            // For direction, we'll go straight down for now, which really
            // models the wheels as spheres... but that's a decent approximation
            // for such wide truck tires.
            Vector3 down = -Vector3.up;
            //Debug.DrawLine(w.position, w.position + down * wheelR, Color.green, 0);
            RaycastHit hit;
            if (Physics.Raycast(w.position, down, out hit)) {
                Vector3 p = hit.point - down * wheelR;
                pts[qtyPts++] = p;
                //Debug.DrawLine(p + Vector3.right, p - Vector3.right, Color.green, 0);
                //Debug.DrawLine(p + Vector3.forward, p - Vector3.forward, Color.green, 0);
            }
        }
       
        if (qtyPts >= 3) {
            // Find the average normal of planes among all sets of 3 points.
            Vector3 normal = NormalFromPoints(pts[0], pts[1], pts[2]);
            if (qtyPts > 3) {
                normal += NormalFromPoints(pts[1], pts[2], pts[3]);
                normal += NormalFromPoints(pts[2], pts[3], pts[0]);
                normal += NormalFromPoints(pts[3], pts[0], pts[1]);
                normal *= 0.25f;
            }
                       
            // Correct our "up" rotation.
            Quaternion q = Quaternion.FromToRotation(transform.up, normal);
            transform.rotation = q * transform.rotation;
           
            // Also, correct our position by averaging errors from all points.
            Vector3 dpos = Vector3.zero;
            for (int i=0; i<qtyPts; i++) dpos += pts[i] - wheels[i].position;
            dpos /= (float)qtyPts;
            dpos.x = dpos.z = 0;        // (only correct in Y)
            transform.position += dpos;
           
            //Debug.DrawLine(transform.position, transform.position + normal*5, Color.magenta, 0);
            //Debug.DrawLine(transform.position, transform.position + transform.up*4, Color.gray, 0);
        }
    }

    Vector3 NormalFromPoints(Vector3 ptA, Vector3 ptB, Vector3 ptC) {
        // The normal of the plane is the cross-product of two vectors in it.
        Vector3 result =  Vector3.Cross(ptB - ptA, ptC - ptA);
        result.Normalize();
        return result;
    }
}

…However, that script is designed to allow the vehicle to roll correctly over small obstacles, etc. It may be overkill for your needs.

Your idea of going using the surface normal is an interesting one. You can’t just take a normal and use it as a rotation, though… these are completely different things.

But you might be able to take the normal and use it as the axis of rotation, with Quaternion.AngleAxis. And the angle you specify would be the Y rotation of the parent. (Or maybe it would be zero, if you’re assigning to localRotation, since that would be just a local rotation — you’d get the Y rotation of the parent anyway.)