Keeping raycast on the same level

I want my raycast to end at certain height(red line). But as the game is 3D and the camera rotates I can't use a fixed magnitude. What I thought was a stroke of genius, I figured I'd project the height vector(a) to the ray direction to get vector(b). The result is in the right direction, but the magnitude of b is not big enough.

The wanted result is to get the vector b always reach the red line(Magnitude changes depending on the camera). My previous knowledge of vector projection says it should work, but obviously it doesn't. Where am I going wrong here?

---- EDIT: Question clarification ----

Step one: The ray is cast depending on used input. And it fails to hit any of the gameobjects.

Step two: Check the area around the midlevel(redline) to see if any gameobjects are close enough(green circle). For this to work, I need the magnitude of b-vector to use the Ray.GetPoint().

• could you tell us, exactly why?what are you trying to achieve? – Heisenbug Apr 24 '13 at 10:43
• @Heisenbug I have gameobjects that are interacted with. The ray chooses which one is chosen, should the ray miss its target. I.e Ray misses a gameobject, decide which is the closest and pick that up instead. But the objects are on two levels, so I need the "missed ray" to check the mid ground(so it does not favor either one) – Esa Apr 24 '13 at 11:28
• in both the images you posted, the ray always seems to intersect a GameObject, so I don't understand exactly what's the problem. – Heisenbug Apr 24 '13 at 12:59

You know the length going from the red line to the top of the blue line, right? Then you can apply some basic trigonometry.

The blue line and the red line are the legs of a right triangle. Your desired line from the camera to the red line in the direction of the raycast is the triangle's hypotenuse (origin at the camera):

Given an angle, theta between the hypotenuse and some leg of a right triangle:

cos(theta) = adjacent_leg_length / hypotenuse_length


But you don't have the hypotenuse_length, so you'll rearrange it like so:

hypotenuse_length = adjacent_leg_length / cos(theta)


Assuming you have your raycastDirection, cameraPosition, and redLineHeight as demonstrated in your screenshots, here's how to get a relative vector representing this hypotenuse:

Vector3 cameraPosition = GetCameraPosition();
float redLineHeight = GetRedLineHeight();
float cameraHeightFromRedLine = cameraPosition.y - redLineHeight;
float angle = Vector3.Angle(Vector3.down, raycastDirection);
float magnitude = cameraHeightFromRedLine / Mathf.Cos(angle);
Vector3 yourNewVector = raycastDirection.normalized * magnitude;


Now that you have this new vector, you can do a check at the end of it with Physics.OverlapSphere:

float checkRadius = GetCheckRadius();
Collider[] hits = Physics.OverlapSphere(cameraPosition + yourNewVector, checkRadius);
foreach (Collider hit in hits) ProcessHit(hit);


Alternatively, if you have a list of hittable GameObjects and there aren't that many in that list, you can bypass the Physic.OverlapSphere call and do a squared distance comparison on each. The advantage of using Physics.OverlapSphere is that PhysX does smart things to prune colliders it would otherwise have to check against. But if you already have that list filtered down enough, you can save on not having to call out to the native physics code. It all depends on the cost of iterating through your hittable set vs the cost of calling out to Physics.OverlapSphere. Start with OverlapSphere for simplicity, and then if you find yourself needing to cut down on physics calls, then this is one place to possibly look at after you profile.

If you need to bone up on trig, Khan Academy has some videos.

You can use Physics.SphereCast instead of RayCast. This allow you to perform queries of the intersection of a sphere sweeped along a given direction instead of single ray, allowing a more tolerant collision detection.

Assign at least two different layers to the plane and the GameObjects under it, in order to exclude the plane from the query.

Instead of using Linecast, which, if I understand correctly, you use now, I'd suggest Raycast function, where the length of the direction vector doesn't matter. (By the mathematical definition, ray doesn't have an end.) If you want to be able to select a specific type of objects, it usually makes sense to assign these objects to a specific layer in unity and use layerMask. I think that this approach is better for your task, because this way the filtering of selected objects isn't tied to some specific knowledge about the position of camera or the objects; it is tied to the layer the objects are in, and it makes much more sense.

• I'm using raycasts. The reason why I need the certain distance is because I need the magnitude of the b-vector for Ray.GetPoint. To which I give the magnitude and I get a point on the redline. I'll update the question for clarity. – Esa Apr 24 '13 at 11:57
• Can you tell more about what are you trying to achieve? If undersand correctly, you want to get position of the mouse cursor (or tap point) against a special plane — for example, to create an object on the ground when the player taps there, am I right? – Max Yankov Apr 24 '13 at 12:00
• I updated the question. Is it more understandable now? – Esa Apr 24 '13 at 12:14