# How to detect which side of a part is most "up"

I want to know which vector (upvector, lookvector, rightvector, -upvector, -lookvector, or -rightvector) is the side of the part that faces most up. I need this for my code of adding snow on top of all parts. Some are rotated a little, so i used upvectors. But some are rotated more than 90 degrees and I can’t use upvector anymore because then it would be upside down (upside down snow doesn’t seem that realistic) please help me here is the code

``````for i,v in pairs(game.Workspace:GetChildren()) do
if v:IsA("Part") and v.Name ~= "Baseplate" then
local snow = v:Clone()
snow.Parent = v
snow.Size = snow.Size-Vector3.new(0,snow.Size.Y-0.1,0)
snow.Anchored = true
snow.BrickColor = BrickColor.new("White")
snow.Material = "Sand"
local num = (v.Size.Y/2)+0.05
snow.CFrame = snow.CFrame + snow.CFrame.UpVector * num
end
end

``````

1 Like

Couldn’t you just use the Orientation of the part to determine this?

1 Like

Sorry i kinda suck at math. I see the connection between orientation and vectors. But idk how to translate it. Can you help please?

1 Like

Why not just fire raycasts down from the sky and when that ray comes in contact with a part, you can use the NormalId to find out where to position the snow? (Haven’t used Raycasts in awhile so I’m not gonna pseudo-code it rn and look silly :P).

1 Like

I wrote an article on this a long time ago!

4 Likes

wow nice! i will try it out

wow i think it is right. Is it this function?

``````
local function getHighestFace(part)
local highestFace
local height = -math.huge

for k, normalId in pairs(Enum.NormalId:GetEnumItems()) do
local y = part.CFrame:pointToWorldSpace(Vector3.FromNormalId(normalId)).y
if y > height then
highestFace = normalId
height = y
end
end

return highestFace
end
``````

That’s just one function I wrote to make the dice work - it’s not the whole thing. You could use that function in your own code; however the article has download a download link to the completed dice model at the bottom.

oh ok. But what does the function return?

It returns a NormalId. Notice how it iterates over `Enum.NormalId:GetEnumItems()`

ok. Is there a way I can implement that into my script here? I need to replace “upVector” with something else (the top side of the part)

``````for i,v in pairs(game.Workspace:GetChildren()) do
if v:IsA("Part") and v.Name ~= "Baseplate" then
local snow = v:Clone()
snow.Parent = v
snow.Size = snow.Size-Vector3.new(0,snow.Size.Y-0.1,0)
snow.Anchored = true
snow.BrickColor = BrickColor.new("White")
snow.Material = "Sand"
local num = (v.Size.Y/2)+0.05
snow.CFrame = snow.CFrame + snow.CFrame.UpVector * num -- what do i replace this line with?
end
end
``````

Here’s my attempt, using Ozzypig’s getHighestFace method. It works, but I feel slightly uncomfortable with the math that I did to achieve it (namely, the “positive” normal variable thing that I do in order to figure out the size feels icky). I’m pretty awful with math so I’m sure there’s a far better way to do this portion.

``````local function getHighestFace(part)
local highestFace
local height = -math.huge

for k, normalId in pairs(Enum.NormalId:GetEnumItems()) do
local y = part.CFrame:pointToWorldSpace(Vector3.FromNormalId(normalId)).y
if y > height then
highestFace = normalId
height = y
end
end

return highestFace
end

local normal = Vector3.FromNormalId(getHighestFace(part))
local offset = normal * part.Size * 0.5

local positive = if normal.X<0 or normal.Y<0 or normal.Z<0 then normal*-1 else normal

local existing = part:FindFirstChild("SnowPart")
local snow = existing or Instance.new("Part")

if not existing then
snow.Name = "SnowPart"
snow.Anchored = true
snow.BrickColor = BrickColor.new("White")
snow.Material = Enum.Material.Sand
end

snow.Size = (positive*thickness)+(part.Size*-positive+part.Size)
snow.CFrame = part.CFrame:ToWorldSpace(CFrame.new(offset))+(normal*thickness/2)

snow.Parent = part
return snow
end

for _,v in ipairs(workspace:GetChildren()) do
if v:IsA("Part") and v.Name~="Baseplate" then
end
end
``````
4 Likes

There’s an error

line: snow.Size = (positivethickness)+(part.Size-positive+part.Size)

error: 14:17:16.818 ServerScriptService.Script:49: invalid argument #3 (NumberSequence expected, got Vector3) - Server - Script:49

Seems like you modified the code a bit, and I’m not sure what you changed. The code that I sent is only 43 lines long, while your error shows that you’re running some code that’s 49 lines long. I need to see the changes in order to figure out what’s wrong, because the script that I sent you works just fine.

1 Like

oh no it’s some comments above the code. I found out why. It’s because I have a part, and in that part there is a particle emitter called “Snow”. It broke your code. Can you make it so the name won’t be affected? Change this line of code:

``````	local existing = part:FindFirstChild("Snow");

``````

then i will set as solution thanks!

Just change “Snow” in these two spots to something else, like “SnowPart” or something.

Edit: Went back up and changed the code in my reply here to do just this.

Ok, since I can just put any random, I’ve decided it’s the correct one thanks!