Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • 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
4
Question by ThumbStorm · Sep 14, 2010 at 03:10 PM · rotationraycastquaternionnormals

Rotating an object to equal normals of object below

Hello, I'm using a modified version of the car tutorial script to control a hovering vehicle along a pipe shaped track that goes up/down/left/right. I need the vehicle's x rotation to match the track below preferably a smooth rotation from it's current x to the x of the normal below it. I have a ray casting down to the track with the following:

function FixedUpdate() {

var hit : RaycastHit;

if (Physics.Raycast (transform.position, -Vector3.up, hit)) { //this part is to match the vehicles x to the tracks x// transform.rotation = Quaternion.FromToRotation (Vector3.right, hit.normal); distanceToGround = hit.distance;

 if (distanceToGround >.9) {
     rigidbody.AddForce (-Vector3.up * 350000);

 } 

}

}

This causes the vehicle to lay on it's side and jump around. I know i need to extract the x rotation of hit.normal and apply it to the x rotation of the vehicle but I'm missing something here. Any ideas would be greatly appreciated. Thanks

Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
21
Best Answer

Answer by skovacs1 · Sep 14, 2010 at 06:12 PM

There are lots of meanings to floating along a surface and many ways to implement them. Your code really only aligns an axis of rotation to the surface normal beneath it in world space rather than actually floating.

If you actually wanted to follow the contours of the surface, you could actually cast rays down the object's axis rather than the world axis and smooth between the rotations and positions to align properly. If using physics, you could apply appropriate forces/torque relative to the surface normal and the casting direction. You could setup a collider for the space beneath the object and let it slide along the surface using physics. To calculate it based on collisions, you could apply forces or changes along contact point normals with something like rigidBody.AddForceAtPosition(10 * contact.normal, contact.point). With a collider, you could scale the collider to indicate the amount of hover desired. There are numerous ways to go about this, including forcing an orbit above a surface by determining the position based on the orientation as the mouseOrbit camera script does (sticking the object to a rail essentially). If that's more of what you actually wanted, then please rephrase the question to reflect that.

What the posted code does:

function FixedUpdate() { var hit : RaycastHit;

 //cast a ray down in the world from our current position
 if(Physics.Raycast(transform.position, -Vector3.up, hit)) {
     //sets the rotation so the x-axis aligns to the normal of the surface beneath us
     //this aligns the x to the surface's outward direction not the surface's x-axis
     transform.rotation = Quaternion.FromToRotation(Vector3.right, hit.normal);

     //distance to the ground
     distanceToGround = hit.distance;
     //if too far away force it towards the down direction
     if(distanceToGround >.9) rigidbody.AddForce(-Vector3.up * 350000);
 }

}

Alignment

You are aligning the x axis (which indicates the right hand side of a properly aligned object) with the surface normal (meaning that the left side of the object will point towards the surface) and you complain that the vehicle is laying on its side. With this code, the side will align to the surface if the geometry is properly aligned or if differently aligned, the side may still align to the surface if you are aligning the wrong axis for your misaligned geometry.

To correct this, you must correct the axis you are aligning on from Vector3.right to some other axis.

Jumping Around

Because you are assigning the rotation directly, each time the calculated rotation is different from the current rotation, the assignment will make it jump to the orientation specified. If by jump around, you are referring to the actual position as well, please bear in mind that all rotations are relative to your pivot and if your geometry is offset from your pivot, it will appear to move as well. Also, if the transform pivot is offset from the geometry, you should also realize that the raycast is being cast from this pivot and you might not get the results desired in some cases.

To correct this, you could use Quaternion.Slerp or Quaternion.Lerp to smoothly interpolate between orientations or you could calculate the euler angles and do your own interpolation. Of course, with these approaches, there are some things to consider:

If you are interpolating from the current orientation to the target orientation with the same weight each FixedUpdate you will quickly begin the adjustment and smooth to the end (possibly never being 100% aligned, but always approaching it). It may sort of jump at the start if the change was large enough, but will logarithmically slow down.

var adjustRatio : float = 0.1; //amount of the difference to rotate by private var hit : RaycastHit;

function FixedUpdate() { if(Physics.Raycast(transform.position, -Vector3.up, hit)) { if(hit.distance >.9) rigidbody.AddForce(-Vector3.up * 350000); if(hit.normal == transform.up) return; //May never happen... tranform.rotation = Quaternion.Slerp(transform.up, hit.normal, adjustRatio); } }

If you are controlling the angles, you could interpolate by a fixed amount of your discretion. This way, while the change will still be done through assignment, it will never exceed a certain amount and the speed of the adjustment will be more or less constant.

var adjustSpeed : float = 10; //degrees private var hit : RaycastHit; private var newUp : Vector3;

function FixedUpdate() { if(Physics.Raycast(transform.position, -Vector3.up, hit)) { if(hit.distance >.9) rigidbody.AddForce(-Vector3.up 350000); if(hit.normal == transform.up) return; newUp = Vector3.RotateTowards(transform.up, hit.normal, adjustSpeed Mathf.Deg2Rad, 0); transform.rotation = Vector3.LookRotation(transform.forward, newUp); } }

If you store the start orientation and previous normal, you could start your interpolations whenever the normal changes and continue/end it whenever it doesn't. This will linearly interpolate the rotation about a sphere. Using SmoothStep will force all changes to smooth in and out, but can change from quick adjustments to a sudden smoothing in another direction if the surface normal changed suddenly during the interpolation - this could be corrected by adding some inertial correction based on the current weight.

var adjustSpeed : float = 1; private var fromRotation : Quaternion; private var toRotation : Quaternion; private var targetNormal : Vector3; private var hit : raycastHit; private var weight : float = 1;

function Start() { targetNormal = transform.up; }

function FixedUpdate() { if(Physics.Raycast(transform.position, -Vector3.up, hit)) { if(hit.distance >.9) rigidbody.AddForce(-Vector3.up 350000); if(hit.normal == transform.up) return; if(hit.normal != targetNormal) { targetNormal = hit.normal; fromRotation = transform.rotation; torotation = Quaternion.FromToRotation(Vector3.up, hit.normal); weight = 0; } if(weight <= 1) { weight += Time.deltaTime adjustSpeed; tranform.rotation = Quaternion.Slerp(fromRotation, toRotation, weight); //Or to smooth the weight //tranform.rotation = Quaternion.Slerp(fromRotation, toRotation, // Mathf.SmoothStep(weight)); } } }

Comment
Add comment · Show 1 · 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 ThumbStorm · Sep 14, 2010 at 07:32 PM 0
Share

I couldn't have asked for a better response! I've just learned a ton of stuff and you've cleared up some things I've been trying and failing at. $$anonymous$$uch appreciated, thanks.

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.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Rotating with a preferred driection. 0 Answers

Unity Rotate Raycast on Quaternion 1 Answer

Rotate an object from inside (With Flipped Normals) 3 Answers

How can I smooth the rotation using quaternion and raycast? 1 Answer

Align navmeshagent to ramp and rotate normally,Script is aligning to slopes but no longer rotating on other axis 0 Answers


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