How to create an arcing effect using rays? (repost)

Do you want some math for making the “random lighting lines”?

Or do you alreay have the lightning path shape, and just want a way to render the lines?
Was gonna say there is the Beam object you can use to render some basic lines.

But if you want some math for producing the shape like you are showing in your image, I can lead you in the right direction.
You would just have your single Ray cast that you are doing, but then produce a bunch of Vectors that run along the line of the ray. And then take each point and give it a random offset. In this way, the lines will still follow your ray, because their positions were generated “relative” to the ray itself.

If you wanted to get fancy, you could also offset the points by finding the “perpendicular direction” to the ray, and offset the points based on that direction.

I want it to shoot in random directions and random shapes.

Right. So by random shapes you mean like, the lightning could move in a circle maybe? Or just whatever path you define. It sounds like.

But many times when people make a lightning effect of any shape, it always starts with a single line.
Kinda like in your image. You have a basic single line (ray). And you basically define a bunch of points (vectors) that run along that line, and then you can apply random offsets to each vector.

But let’s say you want your lightning to have some “shape” to it. Like a wide curve. That curve (or whatever shape) would be like the black line in your image. Except that you would need multiple smaller lines to make up the larger curve.
But you would still only ever have 1 “ray”.
The ray is just to tell where the lightning starts, and where it ends.

I could elaborate on some code, but I want to make sure of what kind of code would be most helpful to you. This subject of procedural lightning effects has been somthing that I’ve had interest in understanding better in the past as well.

But the core idea is that you have a “backbone line” at which the rest of the lightning is developed from. That could be a straight line, or a curve, or a triangle. Because any path can be represented with a bunch of straight lines.

Also, you may have seen these already, but I’ll share them anyway.

I am trying to make a custom one actually. Is that possible?

Well yea it’s possible, you just need the core math that makes it all work :stuck_out_tongue:

I can offer some “bare bones” code that I think is the basis. I did have to think through this for a bit and test to make sure it does what I think it does. Because it does rely on CFrames, because you can use CFrames to offset things relative to a specific orientation.

But again, there are different ways to do a lightning effect, and some don’t require CFrames.

Going back to your image, you have 2 different “lines”. You have a black line which you could call your “reference line” (you call it the raycast, because that’s what it is). But you would call it the reference line because your lightning will be “based off” that black line; It’s all relative to the black line. The red line is your actual lightning, but the way you get it is by taking your “reference line” and applying offsets to specific points on the reference line. It could be a wide arc, it could be random numbers to give it more noise. But they are all offsets at the end of the day. You are just adding an “offset” to your “reference”.
But also, most crucially, your “reference line” could be at any angle, so you can’t always just offset things the normal way. You have to make your offsets in a “transformed space”. That is where CFrames come in. They allow you to move things in a specific reference frame.

So you need to first make a CFrame which is at “point A” and it’s LookVector is pointing towards “point B”
local aimCFrame = CFrame.lookAt(startPos,endPos)
This code produces a CFrame that is pointing towards B, from A.

With this CFrame, you can then apply offsets based on the CFrame’s “RightVector” and “UpVector” which will allow you to create whatever shape you want that follows the “reference line”.

This is some sample code which demonstrates the math:

local startPos = workspace.p1.Position
local endPos = workspace.p2.Position

local distance = (endPos-startPos).Magnitude

function CreatePart(pos)
	local p = Instance.new("Part")
	p.Parent = workspace
	p.Anchored = true
	p.Size = Vector3.one
	p.Position = pos
end

local aimCFrame = CFrame.lookAt(startPos,endPos)

local sampleReduction = 3

distance = math.floor(distance)/sampleReduction

for i=1, distance do
	local t = i/distance
	
	local xOffset = math.sin(t*math.pi)*8 + math.random() * 5
	local yOffset = math.random() * 5
	
	local forward = aimCFrame.Position + aimCFrame.LookVector * i * sampleReduction -- determines position of each point along the reference line
	local rightShift = aimCFrame.RightVector * xOffset -- horizontal offset
	local upShift = aimCFrame.UpVector * yOffset -- vertical offset
	
	CreatePart(forward + rightShift + upShift)
end

You can test it by creating two parts and having this script refer to them as the start position and end position for the lightning. And it will creates new parts that would represent the “vertices” for your lightning. So this could be applied to a series of Beam objects, or you could use parts as the lines that make up the lightning. But tbh, I think it would be easier to use Beam objects.

The last thing that needs to be said about this code is that, if you want to customize the shape of the lightning as it moves from point A to B. You would change the variables “xOffset” and “yOffset” to be set to whatever values you want.
You can see in my case, I used math.sin to produce a “wide arc”, but you could use other math functions to achieve the same thing. And you can also see that I use math.random() to add some noise to the shape as well. But you could use perlin noise if you wanted.
Whatever equation you can think up to get whatever shape you want can be replaced for xOffset and yOffset.

The code below that is necesary for making sure your lightning shapes are offset in the right direction, depending on where A and B are.
And yea, there are other ways this code could be improved as well. As the distance between A and B get’s bigger, it will use more parts. But that might be bad for performance. You you’d want to make it so the points that are used is fixed.

2 Likes

Final remark to clarify what is possible with this code.

This could even be used to create 3D Spirals.

Ok, thanks. Sorry for not responding. Didn’t check my site in a while!

Ok, so I managed to make it adjust the size automatically, but I am unsure how to work with the rotation.

Rotating the arc?

I believe it involves a usage of both Cosine and Sine functions for the X and Y positions.

Because, Sine and Cosine are essentially used to convert an angular rotation into a “Cartesian Position”. In other words, you could draw a circle using sine and cosine.
Or, you could make somthing move in a circle using sine and cosine; Their inputs are angles.

If you get creative with sine and cosine (which you absolutely should) (don’t be afraid of them) then you could even make some lightning have a spiral shape to it.

But I will spare you some hints as to how you need to use sine and cosine to make it rotate. Because in my example, you would be using sine/cosine in 2 different ways. So I will also adjust those 2 lines to be clear about what can be done.

Also, I reccomend Desmos

for visualizing a lot of the math behind this. Which might help to explain what each piece of code does.

In the following code, I hade “removed” the lines that have not changed since my last post with the same code. I am only showing things that are new.
I also added some variables to make it clear what certain values were meant for. But you can move these variables to wherever you want.

“arcAngle” is the actual angle the arc would be in. But when you want to make it so this value could change over time, this variable would obviously be in a different place, or it would just change over time.

“t” is a variable from [0,1] What people will call a “normalized value”.

local arcSize = 8

local arcAngle = math.rad(0)

function ArcShape(x)
	return -4*x*(x-1) -- produces an arc from [0,1]
end

-- loop
	--
	
				-- Arc Shape  -- Arc Scale -- Rotation Of Arc  -- Random Noise To Make It Look Natural
	local xOffset = ArcShape(t) * arcSize * math.cos(arcAngle) + math.random() * 5
	local yOffset = ArcShape(t) * arcSize * math.sin(arcAngle) + math.random() * 5

	--
	--
	--

	--
--

You could also get a spiral by doing this instead

local xOffset = ArcShape(t) * arcSize * math.cos(8*t) + math.random() * 5
local yOffset = ArcShape(t) * arcSize * math.sin(8*t) + math.random() * 5

The major difference is that we are using “t” in the sine/cosine to have the angle be different for each “segment” in the lightning bolt.

And that is pretty much it.

Lastly!

I do want to say this again that this code is meant for straight lines, of course. BUT, Any other shape you might want to make, can be made out of a series of straight lines.
So this code could then be used in a series of line segment to make lightning effects of any shape.

2 Likes

Ok but it applies only to the position, not to the rotation. How do achieve so it applies to position and rotation both? Also thank you for explaining this in detail!

Or actually, I was thinking that maybe it could be made like the arcing effect you sent me. It could create parts coming out of it and then somehow connect the arc segments to those parts. I hope you understood what I just said here.

That code you are looking at is probably not what you want. I was just showing that to show you other things that are possible.

It was the code before it that applies a rotation.

And I am assuming when you say “rotation” you are talking about rotation along the lightning bolt.

I would encourage you to experiment and play around with the “base code” I sent originally. From this exact message:

Like I said, you would change “xOffset” and “yOffset” to whatever you want. Those are the things that change the shape of the lightning. But you would also use them to change the rotation as well.
To “rotate” it, you would use math.cos() and math.sin(). Because those functions convert a rotation into a position. Which is how rotations work in mathematics.

A rotation is actually just a specific type of change in position. And that is what sine and cosine are for. Sine and Cosine take in an angle for rotation. And they output a x position and y position that represents that rotation.

But most importantly, the value you put into “sin” and “cos” would be the same “for all of the parts”. Like if you see where it says math.cos(arcAngle) in the for loop.

Yes, I would get creative if we learned about sines and cosines. We learn that stuff later on in school… The whole point of this post was to actually work with the math, not the scripts.

So was there any other questions I haven’t answered yet?

No. I just want you to put it in a script, because I am very confused if that’s ok…

I don’t understand the question, are you trying to raycast in an arch but have the cast be straight?

Yes. That is exactly what I am trying to achieve.

I’m not sure what you mean by that.
I did show a lot of code that would be the backbone for what I thought you were asking for.
The code I showed was the hard part of this entire thing.

I also don’t understand your usage of “raycast”. Raycast refers to a very specific thing. It refers to when you are performing a geometry query; looking to see if any parts intersect with a straight line. And it is always a straight line. If you want a “curved raycast”, you would need to do multiple raycasts that form the curve you want. And that can be achived using the code I’ve showed before.

The code I showed is basically generating an array of points. So you could use those to create a series of raycasts.

Otherwise, if you use the code for somthing that is purely an effect, then that is not a raycast.

Just to be clear, the code I’ve shown already is like 95% of your question. You are free to alter certain things in that code to fit what you are trying to do.
The things that matter the most to you are:
“startPos”, “endPos”, “xOffset”, “yOffset”.
Also, “forward + rightShift + upShift” is the position of each “point” on the lightning bolt.

Whether you are trying to make somthing functional or visual with a lightning shape, this code is the backbone. It’s just a matter of adjusting things to fit your code.

1 Like