Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. We are looking for feedback on the experimental Unity Safe Mode which is aiming to help you resolve compilation errors faster during project startup.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Align Object to Terrain in Only One Axis

Discussion in 'Scripting' started by Ronald_McScotland, Mar 13, 2017.

  1. Ronald_McScotland

    Ronald_McScotland

    Joined:
    Jul 30, 2014
    Posts:
    173
    Hello, I've been experimenting with a wall system that automatically places wall modules along a line. Each module when placed Raycasts down to the terrain, and aligns itself with the terrain using the following code:

    Code (CSharp):
    1. if (Physics.Raycast (transform.position + (Vector3.up * 100f), Vector3.down, out hit, 200f, 1 << LayerMask.NameToLayer ("Ground"))){
    2.             transform.position = hit.point;
    3.             transform.rotation = Quaternion.LookRotation (hit.normal, transform.parent.forward);
    4. }
    The result is somewhat correct, in that it follows the terrain like so:


    However, the wall also leans out from hillsides:


    I've been unable to come up with a way to keep the wall following the angle of the terrain from laterally, without leaning out on its forward/backward axis. Any ideas?
     
  2. Ronald_McScotland

    Ronald_McScotland

    Joined:
    Jul 30, 2014
    Posts:
    173
    I managed to figure it out. In case anyone else has this problem, here's my solution:

    Code (CSharp):
    1.  
    2. (Physics.Raycast (transform.position + (Vector3.up * 100f), Vector3.down, out hit, 200f, 1 << LayerMask.NameToLayer ("Ground"))){
    3.             transform.position = hit.point;
    4.             Vector3 normal = hit.normal;
    5.             normal = transform.parent.InverseTransformDirection (normal);
    6.             normal.z = 0f;
    7.             normal = transform.parent.TransformDirection (normal);
    8.             transform.rotation = Quaternion.LookRotation (normal, transform.parent.forward);
    9. }
    10.  
    I use inverse transform direction to get the hit normal relative to the wall parent object. Then I eliminate the z component of that vector (since that's the axis I don't want any rotation on). Then convert the normal back to world space with transform direction, and align the wall segment to it using Quaternion.LookRotation.

    In my case I'm aligning with the parent transform's forward rather than up axis, because the wall segments were exported from blender and so have the z-axis representing up and down rather than forward and back, so in others cases it might be necessary to fiddle with which axes to align to.
     
    ScoutingNinja3D likes this.
unityunity