Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 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
1
Question by PeterB · Mar 06, 2011 at 03:30 PM · raycastnormalsnormalsurface

How do I obtain the surface normal for a point on a collider (can't use RaycastHit.normal)?

Is there an alternate way of obtaining the true surface normal given a point on a collider surface other than RaycastHit.normal?

It seems as if RaycastHit.normal is bugged and doesn't always return a surface normal, but something else.

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

3 Replies

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

Answer by Statement · Mar 06, 2011 at 03:55 PM

I don't think the fault is in the RaycastHit.normal but rather the call that populates it (SphereCast). However, if you get the triangle you hit, you can use the hit.barycentricCoordinate to calculate the surface normal. This will only work on mesh colliders as only mesh colliders can provide mesh data.

private Vector3 GetMeshColliderNormal(RaycastHit hit) { MeshCollider collider = (MeshCollider)hit.collider; Mesh mesh = collider.sharedMesh; Vector3[] normals = mesh.normals; int[] triangles = mesh.triangles;

 Vector3 n0 = normals[triangles[hit.triangleIndex * 3 + 0]];
 Vector3 n1 = normals[triangles[hit.triangleIndex * 3 + 1]];
 Vector3 n2 = normals[triangles[hit.triangleIndex * 3 + 2]];

 Vector3 baryCenter = hit.barycentricCoordinate; 
 Vector3 interpolatedNormal = n0 * baryCenter.x + n1 * baryCenter.y + n2 * baryCenter.z;
 interpolatedNormal.Normalize();
 interpolatedNormal = hit.transform.TransformDirection(interpolatedNormal);
 return interpolatedNormal;

}

I tested this code right after your previous question with the sphere cast. It seems to work well with the plane but the position of the sphere cast hit is still arbitrary with regard to large radii.

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
1

Answer by poncho · Mar 08, 2011 at 05:21 PM

i use the

void OnCollisionEnter(Collision collisionInfo)
{
}

the normal vector3 can be obtained really easy just need this

collisionInfo.contacts[0].normal;

i used this code on a bouncing ball on irregular planes, really useful this simplify the need of the GetMeshColliderNormal, it have all that code inside

hope this helps as it helped me =)

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 DanJC · Apr 07, 2013 at 02:29 AM 4
Share

Just going to point out for anyone reading that the normal given by

ContactPoint.normal;

(which is the result of collisionInfo.contacts[0].normal;) is not the same as the normal given by

RaycastHit.normal;

The former is the normal of the collision itself - ie, the direction the that two objects want to push away from each other. The latter is the normal of the surface being collided with.

For a bouncing ball, ContactPoint.normal makes sense. But for finding the surface normal, it doesn't.

avatar image
1

Answer by FeastSC2 · Mar 14 at 01:42 PM

It's an old thread, but I stumbled upon it and it did not provide the answer I was looking for.

Raycasting will get you the expected normals, but if you're using SphereCast or CapsuleCast, the normals that are given by these functions are not the normals you expect to receive. The solution to this is simply to then do a Raycast to this collider to acquire the surface normal (as opposed to the collision normal). This works for EVERY type of collider except the Non-convex mesh collider. In that scenario, you could use the solution provided by user @Statement, however I do not recommend it. Your game needs and should only have convex mesh colliders, that's just the unfortunate reality. There are some assets in the store that making non-convex mesh colliders into multiple convex mesh colliders.

     public static RaycastHit CreateRaycastHitFromCollider(Vector3 _rayOrigin, Collider _collider)
     {
         var colliderTr = _collider.transform;
 
 
         // Returns a point on the given collider that is closest to the specified location.
         // Note that in case the specified location is inside the collider, or exactly on the boundary of it, the input location is returned instead.
         // The collider can only be BoxCollider, SphereCollider, CapsuleCollider or a convex MeshCollider.
         var closestPoint = Physics.ClosestPoint(_rayOrigin, _collider, colliderTr.position, colliderTr.rotation);
   
         if (_collider is MeshCollider {convex: false} meshCollider)
         {
             Debug.LogWarning($"do not use convex mesh-colliders as it does not deal well with physics at all. " +
                              $"There are solutions provided in the asset store to automatically transform non-convex meshes to convex meshes. The problematic mesh: {_collider.transform.GetFullPathName()} meshName:{meshCollider.sharedMesh.name}");
             // This is not great. If we have complex meshColliders we will encounter issues.
             closestPoint = _collider.ClosestPointOnBounds(_rayOrigin);
         }
         
         var dir = (closestPoint - _rayOrigin).normalized;
         var ray = new Ray(_rayOrigin, dir);
         var hasHit = _collider.Raycast(ray, out var hitInfo, float.MaxValue);
         
         if (hasHit == false)
         {
             Debug.LogError($"This case will never happen!");
         }
 
         return hitInfo;
     }


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 IntergalacticSloth · Mar 24 at 03:46 PM 0
Share

Thanks for this!

We can also add this at the beginning of your function to avoid errors if we try to test from INSIDE the collider for even a moment. For now we just return a useless rayHit...

 RaycastHit hitInfo = new RaycastHit();
 bool inside;
 inside = _collider.bounds.Contains(_rayOrigin);
     
 if (inside)
 {
 Debug.LogWarning("Getting raycast to nearest point failed - we are inside provided collider");
 return hitInfo;
  }





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

Assigning vertex normal in Surface program to o.Normal brakes lighting? 0 Answers

How do i find the normal of a line between two points? 1 Answer

Pointcast? - Raycast Point X from same Point X 0 Answers

Allow y rotation 1 Answer

RaycastHit.normal problem 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