So what I want to do is to put a attachment at all 8 corners, but I’m having trouble finding the positions of the farther corners. I already know the range of the light and the positions of the corners on the part.
Thanks in advance!
So what I want to do is to put a attachment at all 8 corners, but I’m having trouble finding the positions of the farther corners. I already know the range of the light and the positions of the corners on the part.
Thanks in advance!
The corners can be derived from Range and Angle.
sin(α) = x/r; x = sin(α) * r
cos(α) = d/r; d = cos(α) * r
As you can discern from the image, horizontal orange line doesn’t lie in the same plane as the four corners, hence why we calculate d
.
The offsets are applied differently depending on the surface face. I’ll take front face as an example.
1. CFrame.new(x, x, -d)
2. CFrame.new(x, -x, -d)
3. CFrame.new(-x, x, -d)
4. CFrame.new(-x, -x, -d)
In some cases this may be enough, but the attachments are not uperfectly aligned until we additionally offset them by half of the part’s size.
local part = workspace.Part
local light = part.SurfaceLight
local function PlaceAttachment(cf: CFrame): ()
local attachment = Instance.new("Attachment")
attachment.Visible = true
attachment.CFrame = cf
attachment.Parent = part
end
local x = math.sin(math.rad(light.Angle/2)) * light.Range
local d = math.cos(math.rad(light.Angle/2)) * light.Range
local halfSize = part.Size/2
PlaceAttachment(CFrame.new(x + halfSize.X, x + halfSize.Y, -d - halfSize.Z))
PlaceAttachment(CFrame.new(x + halfSize.X, -x - halfSize.Y, -d - halfSize.Z))
PlaceAttachment(CFrame.new(-x - halfSize.X, x + halfSize.Y, -d - halfSize.Z))
PlaceAttachment(CFrame.new(-x - halfSize.X, -x - halfSize.Y, -d - halfSize.Z))
Sorry for replying late, but I tried the code and it would only work for one of the faces. Is there anyway to make it so it work for all faces? Like front, back, right, left, top, and bottom.
I mean I could change the order of the negatives on the Cframe, but is that the only way? Is there a way to make the Cframe local instead of world?
Yes. I typed out the example for front face manually to show procedure without knowing anything about your use case. When you only need one face, it is usually best to keep it simple, readable, with selected few equasions.
I saw your other topic regarding finding face corners from three days ago and allowed myself to extend the function. (@RoBoPoJu thank you, with your permission, your function now already has a place among utilities in my projects.)
local lightPart = workspace.LightPart
local light = lightPart.SurfaceLight
local function getAxisFromValue(value: number): Enum.Axis
for _, axis: Enum.Axis in Enum.Axis:GetEnumItems() do
if axis.Value == value then
return axis
end
end
error("No axis EnumItem with this value exists.")
end
local function findFaceAndLightCorners(part: BasePart, light: SurfaceLight): {Vector3}
local corners: {Vector3} = {}
local normalAxisValue = light.Face.Value % 3
local normalAxis = getAxisFromValue(normalAxisValue)
local otherAxis1 = getAxisFromValue((normalAxisValue + 1) % 3)
local otherAxis2 = getAxisFromValue((normalAxisValue + 2) % 3)
local x = math.sin(math.rad(light.Angle/2)) * light.Range
local d = math.cos(math.rad(light.Angle/2)) * light.Range
for dir1Sign = -1, 1, 2 do
for dir2Sign = -1, 1, 2 do
-- face corners
local localSpaceCorner = .5 * (
part.Size[normalAxis.Name] * Vector3.FromNormalId(light.Face)
+ dir1Sign * part.Size[otherAxis1.Name] * Vector3.FromAxis(otherAxis1)
+ dir2Sign * part.Size[otherAxis2.Name] * Vector3.FromAxis(otherAxis2)
)
table.insert(corners, localSpaceCorner)
-- projected corners
local localSpaceCorner = .5 * (
part.Size[normalAxis.Name] * Vector3.FromNormalId(light.Face)
+ Vector3.FromNormalId(light.Face) * d * 2
+ dir1Sign * (part.Size[otherAxis1.Name] + x * 2) * Vector3.FromAxis(otherAxis1)
+ dir2Sign * (part.Size[otherAxis2.Name] + x * 2) * Vector3.FromAxis(otherAxis2)
)
table.insert(corners, localSpaceCorner)
end
end
return corners
end
for _,corner in findFaceAndLightCorners(lightPart, light) do
local attachment = Instance.new("Attachment")
attachment.Visible = true
attachment.Position = corner
attachment.Parent = lightPart
end
Dude this worked like a charm, thanks a lot! I also have a question where did you learn all this math? Cause I want to know how to do this too.
It’s basic trigonometry which you can find loads of resources for. If you take geometry or algebra 2 you should be able to understand it
Hmm I’m in algerbra 2 trig rn. Do you learn it like near the end of the school year?
For honors classes it should be around the start of second semester, and around the end for regular ed at least in the US
Well, I guess I’ll just learn it online. Thanks!
Happy to help!
As Vectue said, trigonometry and algebra are (sooner or later) taught in high schools (though there are excellent courses online too). You’ll see how math that you learn during the course of standard education, even if you find it boring, can really help with understanding lots of concepts in 3D game development. Hopefully high school math is enough to build our intuition to be able to grasp more complicated topics on our own.
Granted, in theory, this problem is not hard to solve. It usually takes me more work to find the most convenient application.
Best of luck!
Image 1 below visualises what findFaceAndLightCorners()
does with the farther corners. All of them are exposed to the same translations but with different signs. The two nested for-loops are a fancy way to find pairs of (1,1), (-1,1), (1,-1), and (-1,-1).
Vector3.FromNormalId()
finds the direction based on surface. Once the function determines direction and the other two axis, we know which axis to extend by d
. The other two axis are extended by half the part’s size depending on the axis. We can chip in and add x
to them, given the sign pair used.
I was a bit unfocused yesterday and, to not overcomplicate, I multiplied both d
and x
by two, equivalent to:
local localSpaceCorner = (
part.Size[normalAxis.Name]/2 * Vector3.FromNormalId(light.Face)
+ Vector3.FromNormalId(light.Face) * d
+ dir1Sign * (part.Size[otherAxis1.Name]/2 + x) * Vector3.FromAxis(otherAxis1)
+ dir2Sign * (part.Size[otherAxis2.Name]/2 + x) * Vector3.FromAxis(otherAxis2)
)
Alternatively, assuming all four face corners are known, we could find the vectors connecting each of them with the centre on the surface, mirror them, and extend by x. See image 2: red vector helps determine the direction purple vector is facing. This is very convenient if we can easily determine the centre point, but since we don’t know which face corners are opposites, finding it leads close to what we have right now.
Another potential solution is using CFrame.lookAt(), facing in the direction of Vector3.FromNormalId(), and applying d and x. Finding the sign, in my findings, still takes too many steps.
All in all, given how the first four corners are queried, I believe it’s a win if we simply take the same path for their extended coordinates.
(part.Size[otherAxis1.Name]/2 + x)
I’m a little confused on this part. Isn’t x the distance to the edge of the light already? Why add half the part size.
Never mind sorry, I figured it out
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.