Reflecting a Ray Randomly

Hi! I’m currently looking in to ways to reflect a “bullet” or lazer in my case in a random way that actually makes sense.

So what does this mean? Lets say a user shoots there gun at a block of wood, I want the bullet to reflect but not in a logical way, I just want it to reflect randomly. However! It shouldn’t reflect in a way that wouldn’t make sense whatsoever. Here are some examples I drew up.

How I want it

The blue lines showed in this example are just a FEW ways that the bullet could go, which would make sense and be proper. None of the bullets are going through the brick.

What I don’t want

Notice how the bullets are moving away from the camera and would go through the block.

What I’ve tried
I’ve tried numerous things, including methods that are posted here on the devforums… However none of them are exactly what I’m looking for.

3 Likes

So, is this mimicking how a bullet bounces off a wall at certain angles, but you want it to be more random?

Could you simply not get the real reflection angle (what logically it would be, like a laser off a mirror) and add a random offset to it point away from the wall?

If this is going to be a game mechanic, it is better have at least some predictability for such a thing, which could give players more flexibility to whatever they’re doing - rather than being random.

I think a little more information on what you’re trying to achieve would be useful.

That would always be going in the same direction, just with a different offset. Not exactly what I’m looking for… And it’s also a very hacky method.

Get the normal reflection vector, and then offset it slightly in all axes randomly, then use .unit on the new vector and use it as the direction vector for the ray? This wouldn’t change the origin of the ray?

n.b. You’d have to multiply the unit vector by the length you want.

local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
    return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end

If I get what you’re saying, you’re trying to reflect the ray in a direction which is within a certain angle away from the same ray but in the opposite direction.

Using the above function, this is easily achieved and gives an evenly spread distribution of rays. (Adding random increments to the direction vector can give unevenly spread results.)

local ray, newRayLength --your initial ray & the new ray length
local partHit, hitPosn = game.Workspace:FindPartOnRay(ray)
local reflectedDirection, newRay
if partHit then
 reflectedDirection = RandomVectorOffset(-ray.Direction, math.rad(30)) 
 newRay = Ray.new(hitPosn, reflectedDirection*newRayLength)
end

This will generate a new ray no more than 30 degrees off of a ray going in the opposite direction of your initial ray.

Alternatively, if you want it within 30 degrees off of the “true-reflected” ray:

  1. Acquire the surface normal from the method FindPartOnRay.

  2. reflectedDirection = RandomVectorOffset(ray.Direction - 2*ray.Direction:Dot(surfaceNormal)*surfaceNormal, math.rad(30))

2 extra sources for the mathematically curious:
https://math.stackexchange.com/questions/56784/generate-a-random-direction-within-a-cone
https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector

5 Likes

I have a reflection module from years (many years) ago that kind of gave you the ability to define how accurate the reflection was, and acted more like a grid-snapping system.

It uses a really weird way to calculate the direction of a ray reflecting of a (frontal) surface, mostly since I am absolutely terrible at Maths and to this day don’t understand how to calculate reflection. lol.

Check it out if seems like something that’d be useful. But be warned, its old and badly made. x_x

-ps- don’t ask me how it works, its that old I can’t remember. xD

I also noticed that my method may sometimes produce new rays which go through the block.

There are several ways to combat this, such as:

  1. You can set the maxAngle lower to reduce the likelihood of this.
  2. Check if new ray intersects with the original object that was hit (immediately after it’s creation). If it does, remove that ray and continue to generate randomly offset rays until one is found that doesn’t intersect the original object.
  3. Acquire a reflected direction within 90 (or less) degrees away from the surface normal.
    reflectedDirection = RandomVectorOffset(surfaceNormal, math.rad(90))