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
6
Question by guavaman · Feb 14, 2013 at 08:51 PM · collisionphysicsnormalcontact

Getting surface normal from collision

When a collision event is triggered, you are returned a list of contact points, from which you can get normals. Unity's manual describes this as the "Normal of the contact point." Not very descriptive. I have always assumed this was the surface normal of the opposite collider at the point of collision, however this does not seem to be the case.

ContactPoint.normal doesn't seem to give the actual surface normal, but rather some kind of impact normal. In other words, depending on the angles of impact, the normal returned can change.

I did a test with a sphere collider and a ramp (rotated flattened box collider). The ramp was rotated to have a slope of 45 degrees. I made the sphere collider "walk up" the ramp and output the slope of the surface derrived from the contact normal as it pushed its way up the ramp. At first the results were as expected -- returned angle was 45 degrees. Then I disabled and re-enabled the sphere collider game object and the results changed. The impact returned different values now. The angle compared to Vector3.up would jitter +- 10 degrees as the sphere pushed up against the ramp. Visualizing this with a short ray at the point of contact showed a line that danced slighly on the vertical axis.

The only reason I noticed this was because I tried my collision with another test sphere I was using for doing some character movement tests. This sphere was never able to get the stable, smooth 45 degree result returned like my simpler sphere above. When pushing against the ramp, I'd get about a 50+ degree angle returned, but when I stopped pushing against the ramp, it would drop back to the correct 45 degrees. Every time I pushed up against the ramp, I'd see the incorrect slope angle returned.

The only way I've found to reliably get the surface normal is with a raycast. Am I missing something here? It sure would be a lot simpler if ContactPoint.normal just returned the surface normal of the polygon it collided with. I guess you could also get the surface normal from a mesh collider by getting the triangle list and normal list, but this seems overly complicated.

Comment
Add comment · Show 7
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 GerryM · Feb 15, 2013 at 11:44 PM 0
Share

What do you mean by "disabled and re-enabled the sphere collider game object"? $$anonymous$$anually in the inspector? Or via script?

It doesn't seem to change anything for me. Was trying to reproduce your jitter without success. The normals are fine, even when I apply any force to the objects.

avatar image guavaman · Feb 16, 2013 at 12:12 AM 1
Share

Re: disabling/enabling. $$anonymous$$anually in the inspector. If you do the test below and everything comes out fine, try disabling and renabling the sphere object in the inspector while it's playing and try again.

Here's a little test script that should show what I mean. To set up the object, create a game object with a sphere collider and a rigidbody (disable useGravity, enable freeze rotation XYZ), add the script. Create several ramps and different slope angles, and even rotate a couple on the Y so they're not all facing XY perfectly. $$anonymous$$ove the game object with the WASD keys, RF for up/down movement. Enable gizmo display. Play and push the sphere against the ramp at various angles. Try stopping on the ramp. It will show a debug readout showing the current slope angle of the surface as well as draw a red line representing the surface normal of the contact.

 using UnityEngine;
 using System.Collections;
 
 public class CollisionTest : $$anonymous$$onoBehaviour {
 
     public float speed = 5.0f;
     private Vector3 moveDirection = Vector3.zero;
 
     private Rigidbody rb;
 
     void Awake() {
         rb = rigidbody;
     }
 
     void OnCollisionStay(Collision c) {
         // Display slope of all collision contacts
         ContactPoint[] ps = c.contacts;
         for(int i = 0; i < ps.Length; i++) {
             Vector3 normal = ps[i].normal;
             Debug.DrawRay(ps[i].point, normal, Color.red);
             float slopeAngle = Vector3.Angle(normal, Vector3.up);
             Debug.Log("contact.normal slope = " + slopeAngle + " degrees @ " + Time.time); // show the surface normal
             //Debug.Break();
         }
     }
 
     void FixedUpdate() {
         // zero moveDirection
         moveDirection.x = 0.0f;
         moveDirection.y = 0.0f;
         moveDirection.z = 0.0f;
 
         // zero velocity - critical to eli$$anonymous$$ate physics imparted forces (trying to mimic CharacterController's behavior)
         rb.velocity = new Vector3(0.0f, 0.0f, 0.0f);
 
         // add unit movement
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.W))
             Add$$anonymous$$ove(Vector3.left);
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.A))
             Add$$anonymous$$ove(Vector3.back);
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.D))
             Add$$anonymous$$ove(Vector3.forward);
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.S))
             Add$$anonymous$$ove(Vector3.right);
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.R))
             Add$$anonymous$$ove(Vector3.up);
         if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.F))
             Add$$anonymous$$ove(Vector3.down);
 
         // move the unit
         rb.AddForce(moveDirection, Force$$anonymous$$ode.VelocityChange);
     }
 
     void Add$$anonymous$$ove(Vector3 dir) {
         Vector3 move = dir * speed;
         moveDirection.x += move.x;
         moveDirection.y += move.y;
         moveDirection.z += move.z;
     }
 }
 
avatar image GerryM · Feb 16, 2013 at 09:05 PM 1
Share

Very interesting, now I can reproduce your error - but only when I briefly disable the object. Disabling and enabling seems to somehow break the rigidbody. When you play long enough with the rigidbody settings it does recover again. Really strange. It's definitely not expected behavior. I would file a bug report.

In the meantime your raycast solution seems the best way to go.

avatar image MountDoomTeam · Feb 16, 2013 at 10:18 PM 0
Share

sounds mysterious-good to file a bug report! Just take the scene in question and send it to unity as a package if you want or use the in-program bug report option.

you could disable the mesh renderer, the Collider component, and other components individually to achieve the same thing? you could also change the ball position and place it in outer space when you don't need it?

avatar image guavaman · Feb 17, 2013 at 09:11 AM 0
Share

Glad to see it does the same thing for you and I'm not crazy. ;) Actually, in my case, I don't even have to disable/enable the object for the problem to show up. So while there may be some kind of bug with enable/disable, it's possible to get this issue without doing that.

I ran into another situation where the normal returned is incorrect. I placed a flat rectangular step (about 0.15 high) sticking out of the flat plane floor to test walking up a step simply using the default behavior of physics forces. I ran the sphere collider towards the step and placed a Debug.Break and a Debug.DrawLine showing the normal on impact of the most forward collision point. One would expect the normal to return a 90 degree slope if it hit the side plane, or a 0 degree slope if it hit the top plane. However, it returned slopes between 13 and 40 something degrees randomly. The best I could tell is that it may have been returning an average normal since it was essentially hitting the corner of the step, though I don't recall ever seeing exactly 45 degrees. Still, it reenforces my concern that CollisionPoint.normal does not return surface normals but rather some other normal based on impact angles, or the shapes of the colliders, or something I haven't identified.

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by GerryM · Feb 17, 2013 at 01:30 PM

Anyhow, apart from what CollisionPoint.normal should return, it doesn't return anything consistently. Therefore it seems to be buggy.

Please, file a bug report with an easy example and keep us posted on any news. Thank you!

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

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

12 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

Related Questions

Collision.contacts? 1 Answer

Obtaining contact point and normal of first object in collision 0 Answers

contact.normal not updating in OnCollisionStay2D 0 Answers

Collision normals changing based on player position 0 Answers

How do I get a collision's contact normal without using any non-kinematic rigidbodies? 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