Unity3D: Bouncing/Reflecting Raycast
Asked Answered
C

2

6

Hey everyone thanks for the help,

What I am trying to do is fairly straight forward, I am trying to display a Line Renderer that follows my bouncing/reflecting Raycast.

Here is what I have so far.

 private LineRenderer lr;

public int maxReflectionCount = 3;
public float maxStepDistance = 200f;


void Start()
{
    lr = GetComponent<LineRenderer>();
}


void Update()
{
    RaycastHit hit;

    if (Physics.Raycast(transform.position, transform.forward, out hit))
    {
        if (hit.collider)
        {
            lr.SetPosition(1, new Vector3(0, 0, hit.distance));

            Reflect(this.transform.position + this.transform.forward * 0.75f, this.transform.forward, maxReflectionCount);


        }
    }
    else
    {
        lr.SetPosition(1, new Vector3(0, 0, 2000));

    }

}


private void Reflect(Vector3 position, Vector3 direction, int reflectionsRemaining)
{

    if (reflectionsRemaining == 0)
    {
        return;
    }


    Vector3 startingPosition = position;


    Ray ray = new Ray(position, direction);
    RaycastHit hit2;
    if (Physics.Raycast(ray, out hit2, maxStepDistance))
    {
        direction = Vector3.Reflect(direction, hit2.normal);
        position = hit2.point;
    }
    else
    {
        position += direction * maxStepDistance;
    }



    Debug.DrawRay(startingPosition, position, Color.green);


    Reflect(position, direction, reflectionsRemaining - 1);


}

It seems like Vector3.Reflect is the key but I can't quite figure out how to use it properly.

I have gotten it to sort of work with Gizmos

Line Bounce w Gizmos

but I cant use Gizmos in the real thing and I am having trouble getting it to work with the LineRenderer. I have even tried to use the Debug.DrawRay but to no avail.

I really just want to use it to show what angles things will bounce around at. Any ideas on how I might get this working?

I appreciate any help!

EDIT 1: So I have removed all the Line Renderer stuff because I can worry about that later and I been working on what Hacky suggested. I still cant get it working properly, but here is what it currently looks like.

//private LineRenderer lr;

public int maxReflectionCount = 3;
public float maxStepDistance = 200f;

Vector3 reflDirection;
Vector3 hitPosition;


void Start()
{
    //lr = GetComponent<LineRenderer>();
}


void Update()
{
    RaycastHit hit;

    if (Physics.Raycast(transform.position, transform.forward, out hit))
    {
        if (hit.collider)
        {
            //lr.SetPosition(1, new Vector3(0, 0, hit.distance));

            Reflect(this.transform.position + this.transform.forward * 0.75f, this.transform.forward, maxReflectionCount);
        }
    }
    else
    {
        //lr.SetPosition(1, new Vector3(0, 0, 2000));
    }

}


private void Reflect(Vector3 position, Vector3 direction, int reflectionsRemaining)
{

    if (reflectionsRemaining == 0)
    {
        return;
    }


    Vector3 startingPosition = position;


    Ray ray = new Ray(position, direction);
    RaycastHit hit2;
    if (Physics.Raycast(ray, out hit2, maxStepDistance))
    {
        reflDirection = Vector3.Reflect(direction, hit2.normal);
        hitPosition = hit2.point;
    }
    else
    {
        position += reflDirection * maxStepDistance;
    }

    Debug.DrawRay(startingPosition, reflDirection, Color.green, 1);

    //Debug.DrawLine(startingPosition, position, Color.blue);


    Reflect(position, direction, reflectionsRemaining - 1);

}

EDIT 2 (Big Progress!): Ok so I got the Raycasting Reflection working....and its glorious.

Here is what it looks like:

 public int maxReflectionCount = 5;
public float maxStepDistance = 200f;



void Start()
{


}


void Update()
{

    Laser();
}


void Laser()
{
    DrawReflectionPattern(this.transform.position + this.transform.forward * 0.75f, this.transform.forward, maxReflectionCount);
}

private void DrawReflectionPattern(Vector3 position, Vector3 direction, int reflectionsRemaining)
{
    if (reflectionsRemaining == 0)
    {
        return;
    }

    Vector3 startingPosition = position;

    Ray ray = new Ray(position, direction);
    RaycastHit hit;
    if (Physics.Raycast(ray, out hit, maxStepDistance))
    {
        direction = Vector3.Reflect(direction, hit.normal);
        position = hit.point;
    }
    else
    {
        position += direction * maxStepDistance;
    }

    //Gizmos.color = Color.yellow;
    //Gizmos.DrawLine(startingPosition, position);

    Debug.DrawLine(startingPosition, position, Color.blue);

    DrawReflectionPattern(position, direction, reflectionsRemaining - 1);


}

Now I just have to figure out how to connect the Line Renderer to it and we are in business!

Connote answered 20/8, 2018 at 13:7 Comment(0)
A
0

I read 2 questions:

  1. I don't know how to use vector3.reflect ("It seems like Vector3.Reflect is the key but I can't quite figure out how to use it properly.")
  2. I don't know how to use the linerenderer ("I am having trouble getting it to work with the LineRenderer")

I'll try answering these questions here: The way you use Vector3.Reflect is correct. See the sample in the unity docs: https://docs.unity3d.com/ScriptReference/RaycastHit-normal.html

First visualize the outcome of the equation with Debug.DrawRay(start,dir,color, duration) or Debug.drawline. Use a duration of 1 so that it stays visible in the scene for a second and doesn't disappear immediately. In your Debug.DrawRay is an error: The second parameter of Debug.DrawRay is the direction where you have the position. You also don't save the start position of the ray so it should be:

Ray ray = new Ray(position, direction);
RaycastHit hit2;
if (Physics.Raycast(ray, out hit2, maxStepDistance))
{
    reflDirection = Vector3.Reflect(direction, hit2.normal);
    hitPosition = hit2.point;
}
else
{
    position += reflDirection * maxStepDistance;
}

Debug.DrawRay(hitPosition, reflDirection, Color.green);

When that works, use the linerenderer to show it in the game view. It expects only positions, so no directions. Be careful to not mix directions with positions. (add a direction to a position to get the destination)

Agitator answered 20/8, 2018 at 15:11 Comment(3)
Thanks for the help! So was I needing two other Vector3's? Is that why you added reflDirection and hitPosition instead of using position and direction? Sorry I am pretty basic with my programming knowledge, just trying to learn.Connote
Man I cant even get what you posted working lol... Ok so I have removed all the Line Renderer code, you are right that I can worry about that later. I have entered your code and added the new Vector3's but I still cant getting it working properly. Ill edit my post to show you what I am working with.Connote
You have a nice recursive function. The source is pretty good. You only need to save the value of the ray position and direction in the beginning of that function so that in the end you can use it. Glad you made it. As for the linerenderer: it contains a list of positions. For that to work you clear the linerenderer's positions on laser() and add a position to it in every DrawReflectionPattern(). That's all. Make sure that the transform of the linerenderer's object is completely reset too.Agitator
O
0

I would like to add a bit to it to help others who happen across it. Additionally, I would like to just provide a friendly reminder to OP to accepts Hacky's response as the answer, it did after all answer the question.

For my input, I would just like to point out that recursive functions should be avoided where possible as each call to a function copies all value types being passed into it as parameters and it may keep all the previous calls variables still allocated until the very last call when every function can finally terminate. Don't quote me on that last part. I would recommend a loop for this and it can easily do what you ended up doing while saving you from any overhead of calling functions and from the values needing to be copied every time. Heres my take on your "DrawReflectionPattern" function:

private void TraceReflection(Vector3 startPosition, Vector3 direction, int reflectionsRemaining) {
    for (Vector3 endPosition; (reflectionsRemaining>0); reflectionsRemaining--, startPosition = endPosition) {  
        if (Physics.Raycast(startPosition, direction, out RaycastHit hit, maxStepDistance)) {
            direction = Vector3.Reflect(direction, hit.normal);
            endPosition = hit.point;
        } else {
            endPosition = startPosition + (direction * maxStepDistance);
        }
        Debug.DrawLine(startPosition, endPosition, Color.blue);
    }
}

You can also do a number of things to make it even better like defining the hit variable before the for loop, but I think this still demonstates how to use a loop instead of a recursive function.

Orthodontia answered 18/6, 2022 at 22:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.