Feed
Recently a series of physics related, first of all to summarize some of the things written last year, and then see if you can masturbate a physics engine out.
Ray detection in the previous write Ray tracking when there are some written, but at that time is relatively simple to write, just recently work on the use of these, so good to write.
Write Ray Sphere's collision detection today.
Environment:
Unity5.2.3 Windows10 64bit
Start
Define a class to record the intersecting information
public class Raycasthitinfo {public Vector3 point; public Vector3 normal; public float distance; }
The first is the intersection, and the normal of the intersection, and finally the distance from the beam.
Define the underlying shape
Public enum Geometrytype { Sphere, Box, Capsule, Plane, Cylinder, Cone, } public class Ngeometry { [hideininspector] public geometrytype type; Public Ngeometry (Geometrytype _type) { type = _type; } } public class Sphere:ngeometry {public Vector3 Center; public float radius; Public Sphere (): Base (geometrytype.sphere) {} public Sphere (Vector3 _center, float _radius) : Base ( Geometrytype.sphere) { Center = _center; radius = _radius; } public bool Contains (Vector3 p) { return (p-center). Magnitude <= radius * radius; } }
The quickest way to understand the three-dimensional collision algorithm is to first understand the two-dimensional algorithm.
First look at the position of the ray and the circle in the two-dimensional space.
There are three species, intersecting, tangent, and absent.
Here the ray and the sphere intersect, the basic and the two-dimensional situation is no different, can be seen as a ray and the sphere of a plane intersection.
Core code
public static bool Raycast (Ray Ray, float distance, Sphere Sphere, out Raycasthitinfo hitinfo) {if (! Intersectrayspherebasic (ray, distance, sphere, out Hitinfo)) {return false; } hitinfo.normal = Hitinfo.point-sphere.center; HitInfo.normal.Normalize (); return true;} public static bool Intersectrayspherebasic (Ray Ray, float distance, Sphere Sphere, out Raycasthitinfo hitinfo) {Hitinfo = new Raycasthitinfo (); Vector3 offset = sphere.center-ray.origin; float raydist = Vector3.dot (ray.direction, offset); float off2 = Vector3.dot (offset, offset); float rad2 = Sphere.radius * Sphere.radius; We ' re in the sphere if (off2 <= rad2) {hitinfo.point = Ray.origin; Hitinfo.normal = Vector3.zero; Hitinfo.distance = 0.0f; return true; }//moving away from object or too far away if (raydist <= 0 | | (raydist-distance) > Sphere.radius) {return false; }//Find hit distance squaredRay passes by Sphere without hitting float d = rad2-(off2-raydist * raydist); if (d < 0.0f) {return false; }//Get the distance along the ray hitinfo.distance = Raydist-mathf.sqrt (d); if (Hitinfo.distance > Distance) {//Hit point beyond length return false; } hitinfo.point = Ray.origin + ray.direction * hitinfo.distance; return true;}
Reminder point 1
float raydist = Vector3.dot (ray.direction, offset);
The dot multiplication, also called the inner product and quantity product of a vector, is the product of the length of a vector and its projection on another vector;
Since ray.direction is a unit vector, the projection length of offset in the ray direction is calculated here.
Reminder Point 2
Float d = rad2-(off2-raydist * raydist);
The d here calculates the position identified in the figure, and the Blue Line is the raydist of the above calculation.
Test code
Using unityengine;using system.collections;using Nphysx;public class Rayspheretester:monobehaviour {public GameObjec T Sphere; Sphere _sphere; Use the this for initialization void Start () {_sphere = new sphere (Vector3.zero, 1f); }//update is called once per framevoid update () {//ray sphere test. Ray Ray = new Ray (Vector3.zero, New Vector3 (1,1,1)); _sphere.center = sphere.transform.position; _sphere.radius = 0.5f * sphere.transform.localscale.x; Raycasthitinfo Hitinfo; float castdistance = 10f; if (Nraycasttests.raycast (Ray, Castdistance, _sphere, out Hitinfo)) {Debug.drawline (Ray.origin, Ray.direction * hitinfo.distance, color.red, 0, false); Debug.drawline (_sphere.center, _sphere.center + hitinfo.normal, Color.green, 0, false); } else {debug.drawline (ray.origin, Ray.direction * castdistance, Color. Blue, 0, false); } }}
Run results
Off Topic
A small problem is mentioned here, which is that due to the computational accuracy of floating-point counting units in the CPU,
The code solving the quadratic equation suffers from limited FPU accuracy and returns ' no intersection ' while there defini Tely is one. The "best" fix for Move the Ray origin closer to the target sphere.
Ray Sphere intersection results may be inaccurate, and some small optimizations have been made
public static bool Intersectraysphere (Ray Ray, float distance, Sphere Sphere, out Raycasthitinfo hitinfo) {Vector3 x = ray. Origin-sphere.center;float L = Vector3.dot (x, x)-sphere.radius-10.0f;l = Mathf.max (l, 0.0f); Ray Tmpray = new Ray (Ray.origin + L * ray.direction, ray.direction); bool status = Intersectrayspherebasic (Tmpray, distance -L, Sphere, out Hitinfo);D Ebug. Log ("L:" + L);//bool status = Intersectrayspherebasic (ray, distance, sphere, out hitinfo); if (status) {hitinfo.distance + = l;} return status;}
But for the time being I have not found this problem.
Reference
PhysX3.3 Source Code
Real Time Renderring 3rd
Ray-sphere Detection of collision detection