0
\$\begingroup\$

Am trying to learn about Raycasting, and I thought I would start with something simple, and that was a laser that would come out of an object (think laser pointer in your hand) and always go to the crosshair.

Using ViewportToWorldPoint I found it easy to cast a ray from the center of the camera, but this had an issue as you can see in this GIF below.

enter image description here

The line would clip through because the ray was coming from the center, not off to the side where the laser pointer would be.

Am not sure how to solve this.

void Update(){
    Vector3 ray = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0f));

    line.SetPosition(0, transform.position);

    RaycastHit hit;

    if(Physics.Raycast(ray, Camera.main.transform.forward, out hit, raylength)){
        if(hit.collider != null){
            line.SetPosition(1, hit.point);
        }
    } else {
        Vector3 pos = line.GetPosition(0);
        line.SetPosition(1, ray + (Camera.main.transform.forward * raylength));
    }
}

The closest thing I could find that I am trying to replicate for this exercise is the No Man's Sky mining tool

enter image description here

\$\endgroup\$
2
\$\begingroup\$

You need to fire two rays:

  1. The first ray is fired from the player's-eye view, to find out what's under the crosshair, so you know what worldspace point to aim at. The closer that point is, the more you need to angle your shot inward to hit it.

  2. The second ray is fired from the tool/weapon muzzle, toward the hit from the first ray. This will tell you what a shot or beam fired from the device will hit first on its way toward the target.

You might also want to use spherecasts for one or both of these checks, if your beam has much thickness or you have a lot of tight corners and gaps to shoot around. This ensures the 0-width ray doesn't miss something that it looks like we should have hit.

Vector3 GetHitPoint(Vector3 muzzlePosition) {
    // Unless you've mucked with the projection matrix, firing through
    // the center of the screen is the same as firing from the camera itself.
    Ray crosshair = new Ray(camera.position, camera.forward);

    // Cast a ray forward from the camera to see what's 
    // under the crosshair from the player's point of view.
    Vector3 aimPoint;
    RaycastHit hit;
    if(Physics.Raycast(crosshair, out hit, rayLength)) {
        aimPoint = hit.point;        
    } else {
        aimPoint = crosshair.origin + crosshair.direction * rayLength;
    }

    // Now we know what to aim at, form a second ray from the tool.
    Ray beam = new Ray(muzzlePosition, aimPoint - muzzlePosition);

    // If we don't hit anything, just go straight to the aim point.
    if(!Physics.Raycast(beam, out hit, rayLength))
        return aimPoint;

    // Otherwise, stop at whatever we hit on the way.
    return hit.point;
}
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ I didn't think about using another ray. I assume ray.position is meant to be ray.origin? I tweaked your code and it worked absolutely fine for my exercise. Cheers. \$\endgroup\$ – JacketPotatoeFan Apr 12 '19 at 14:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.