• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
8
Question by SirGive · Sep 19, 2011 at 03:11 AM · rotationnormalalignment

Orient vehicle to ground normal (terrain hugging)

So the problem I'm having is trying to orient a vehicle to the ground based on a raycast. The raycast works, the movement works, and aligning the normal of the ground to the transform.up works. However, together these don't work. It won't rotate.

alt text

I think the problem is that aligning the transform.up = hit.normal overrides any rotation. My question would be, how exactly do I form an algorithm that will translate rotation into the normal. I figure if I can rotate the normal before I set it to the up vector that rotation should be possible. And I don't want it to rotate and snap back, which I found out how to do.

Here is my code (C#):

 if (Physics.Raycast(transform.position, -transform.up, out hit))
     {
         Quaternion grndTilt = Quaternion.FromToRotation(transform.up, hit.normal);
         transform.rotation = Quaternion.Euler(0, Input.GetAxis("Horizontal") * turnSpeed * 100 * Time.deltaTime, 0) * grndTilt;
         //transform.up = hit.normal;    
     }
     Vector3 movDir;
     //transform.Rotate(0, Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime,0);
     movDir = transform.forward*Input.GetAxis("Vertical")*speed;
     // moves the character in horizontal direction
     controller.Move(movDir*Time.deltaTime-Vector3.up*0.1f);

I've been all over the internet, and nothing seems to be working!

EDIT:

Removed the code because it was incorrect. The solution:

Two parts - a composite vector from each of the corners to give you the direction to orient (my original issue) - and separating the mesh to a sub gameobject. Keep your controller as the root (or even another sub object). Very clean movement. Forgive me for no code example. :)

instruction-1.png (11.9 kB)
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image picobots · Apr 05, 2012 at 07:17 PM 0
Share

What is "back" in the code you ended up using?

avatar image SirGive · Apr 06, 2012 at 02:47 PM 0
Share

the back and front are offset variables to move the raycasts towards the front of the tank and the back. These are float data types.

An easy solution is in two parts: - a composite vector from each of the corners to give you the direction to orient (my original issue) - and separating the mesh to a sub gameobject. $$anonymous$$eep your controller as the root (or even another sub object)

Was a very clean movement

7 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by Thoras_Bublyk · Feb 14, 2015 at 06:15 PM

Hey folks!!! After many hours of research i got it. In your Update function manually increment Y angle of your object and manually set rotation after align. Excellent!!!


     float objYangle;
         
         void Start(){
         objYangle=transform.eulerAngles.y;
         }
         
         void Update() {
         objYangle +=  Input.GetAxis("Horizontal") * turnSpeed;
         
         SirGiveMagicAlignFunction(); //first answer by mr SirGive
         
         transform.Rotate(0, objYangle, 0); //and finally set current angle
         
         }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by FlightOfOne · Jul 12, 2017 at 09:16 PM

This thread really helped me out with this problem. I have combined what @SirGive and @EasyKill showed and created this method. This is the most smoothest and predictable way that worked for me. I am using this in vehicle (using with Navmesh Agent). Hope this helps someone.

See final outcome here

  void AlignWithSurface(Transform _parent, Transform _hull, LayerMask _checkLayer, float _maxCheckDist =30, float _rate=0.1f)
     {
 
         RaycastHit frHit,flHit,rrHit,rlHit;
 
         Physics.Raycast(fr.position + Vector3.up, -Vector3.up, out frHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(fl.position + Vector3.up, -Vector3.up, out flHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(rr.position + Vector3.up, -Vector3.up, out rrHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(rl.position + Vector3.up, -Vector3.up, out rlHit, _maxCheckDist, _checkLayer);
 
         Vector3 a = rrHit.point - rlHit.point;
         Vector3 b = frHit.point - rrHit.point;
         Vector3 c = flHit.point - frHit.point;
         Vector3 d = rrHit.point - flHit.point;
 
         // Get the normal at each corner
 
         Vector3 crossBA = Vector3.Cross(b, a);
         Vector3 crossCB = Vector3.Cross(c, b);
         Vector3 crossDC = Vector3.Cross(d, c);
         Vector3 crossAD = Vector3.Cross(a, d);
 
         Vector3 _upNew = (crossBA + crossCB + crossDC + crossAD).normalized;
 
         Quaternion _newRot= Quaternion.LookRotation(Vector3.Cross(_parent.right, _upNew).normalized, _upNew); //If parented
         //Quaternion _newRot = Quaternion.LookRotation(_hull.forward, _upNew); //If NOT parented
 
         _hull.rotation = Quaternion.Lerp(_hull.rotation, _newRot, _rate);
 
     }


Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image jobo22 · Oct 05, 2018 at 11:53 PM 0
Share

Hi @FlightCrazed I see your video and it is exactly what I'm trying to accomplish. I also have a tank that I want to align to the terrain. I copied your script and made public transforms for the corners of my tank and of my main tank that I assigned in the inspector. I call the AlignWithSurface() function in Update(), but it's not working. Sometimes my tank will rock a little bit side to side, but it won't go up and down when it goes up or down a hill. I use the line for not parented. Any help would be appreciated. Thanks! :)

avatar image FlightOfOne jobo22 · Oct 06, 2018 at 03:34 PM 1
Share

Hi There, this is the whole file. I do have something called move to ground in there. Also be sure that the max distance (length of the rays) can actually reach the ground.

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 /// <summary>
 /// Orientates the objects to align with the surface
 /// </summary>
 public class VehicleSurfaceOrientator : $$anonymous$$onoBehaviour {
     public Transform fl, fr, rl, rr;
     public Layer$$anonymous$$ask ground$$anonymous$$ask;
     private RaycastHit _groundHit;
     private void Update()
     {
        
         AlignWithSurface(transform, transform, ground$$anonymous$$ask);
         $$anonymous$$oveToGround();
     }
 
     void $$anonymous$$oveToGround()
     {
         if(Physics.SphereCast(transform.position+Vector3.up,1,Vector3.down,out _groundHit,100,ground$$anonymous$$ask))
         {
             transform.position = _groundHit.point;
         }
     }
 
     /// <summary>
     /// </summary>
     /// <param name="_parent"></param>
     /// <param name="_hull"></param>
     /// <param name="_checkLayer"></param>
     /// <param name="_maxCheckDist"></param>
     /// <param name="_rate"></param>
     void AlignWithSurface(Transform _parent, Transform _hull, Layer$$anonymous$$ask _checkLayer, float _maxCheckDist = 30, float _rate = 0.1f)
     {
 
         RaycastHit frHit, flHit, rrHit, rlHit;
 
         Physics.Raycast(fr.position + Vector3.up, -Vector3.up, out frHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(fl.position + Vector3.up, -Vector3.up, out flHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(rr.position + Vector3.up, -Vector3.up, out rrHit, _maxCheckDist, _checkLayer);
         Physics.Raycast(rl.position + Vector3.up, -Vector3.up, out rlHit, _maxCheckDist, _checkLayer);
 
         Vector3 a = rrHit.point - rlHit.point;
         Vector3 b = frHit.point - rrHit.point;
         Vector3 c = flHit.point - frHit.point;
         Vector3 d = rrHit.point - flHit.point;
 
         // Get the normal at each corner
 
         Vector3 crossBA = Vector3.Cross(b, a);
         Vector3 crossCB = Vector3.Cross(c, b);
         Vector3 crossDC = Vector3.Cross(d, c);
         Vector3 crossAD = Vector3.Cross(a, d);
 
         Vector3 _upNew = (crossBA + crossCB + crossDC + crossAD).normalized;
 
         Quaternion _newRot = Quaternion.LookRotation(Vector3.Cross(_parent.right, _upNew).normalized, _upNew); //If parented
         //Quaternion _newRot = Quaternion.LookRotation(_hull.forward, _upNew); //If NOT parented
 
         _hull.rotation = Quaternion.Lerp(_hull.rotation, _newRot, _rate);
 
     }
 }
 
avatar image jobo22 FlightOfOne · Oct 08, 2018 at 06:12 PM 0
Share

Thank you so much! I got it all working, you saved me hours of frustration and I got exactly what I was wanting! :)

  • ‹
  • 1
  • 2

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

18 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Aligning Y-Axis rotation of stretched gameobject to specific angles while retaining initial position 0 Answers

Make cube look at player relative to a defined rotation. 0 Answers

Cant understand why object rotates when setting transform.up to normal 2 Answers

How can I obtain the overall rotation of multiple selected gameobjects in the unity editor? 2 Answers

How to handler rotation of a Gameobject while aligning it with normals 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges