Making Sharp Edges For Walls

I’ve been making a building system lately, and I don’t know how to tackle having sharp edges on the walls. I know a lot of games just use cylinders, but i’m looking to do sharp edges as it looks cleaner. If you are wondering, here is my server code:

--cframe is an array, with 1 and 2 being the end point of the walls 

local startPoint = cframe[1].p
local endPoint = cframe[2].p
local wall = Instance.new("Part")
wall.Size = Vector3.new(5, 0.1, (endPoint - startPoint).Magnitude)
wall.Anchored = true

wall.Material = Enum.Material.SmoothPlastic

wall.CFrame = CFrame.new(startPoint, endPoint) * CFrame.Angles(0,0,math.rad(90))

wall.CFrame = wall.CFrame + wall.CFrame.LookVector * ((endPoint - startPoint).Magnitude/2)

local model = Instance.new("Model")
model.Parent = workspace.Plane.ItemHolder
model.Name = "Wall"

wall.Parent = model
model.PrimaryPart = wall

As you can see it works fine, but when you place walls on an angle relative to each other, it’s not ideal. I know that @Coeptus and @NinjoOnline, and stravant did a gap fill plugin which is what i’m looking for, but in runtime. I did look into Ninjos post, but I tried my best and couldn’t fully extract a working answer, so I decided to scrap it. All help is appreciated

I would like to try and help but what is the wall object.

It is a part created in the script, which is then placed into a model created by the script. The model is in the item holder of the plane in workspace

Ok, so I made a simple setup and it seems to work for me.


Is this what you mean?

No, I already have the wall building working. Whenever I place to walls with touching edges, there’s a noticeable gap where it turns. Thats what im trying to fix

so if I walk the character round the wall I may see gaps at the ends?

Yes

Image of it happening

Capture

Ok thanks for that.
From my experimenting it looks like the value of the Y for the point parts need to be 1 or greater.
If I set it below 1 there appears to be some interference from the floor.
This resulted for me in the corner not being aligned.
I coloured my parts so I could see them before and during the building.
Here is my place file.
HelpWithWall.rbxl (15.9 KB)

not entirely sure if you understand my problem… im looking to reposition and resize my parts through a function(THAT WORKS FOR ANYTHING) so the edge isn’t there.

I am sorry but you are correct I have not understood your need.
I was concentrating on your script and thought I had found a solution to the corners created by that script.
I am not aware of a function that would place and resize the parts you have or a model made up of them however I have seen previous topics involving plugins that do resizing and placing models so perhaps a search in the forum would be useful to you.
Good luck.

Hmm, this is a neat problem…

So a few assumptions I’ll make

  1. The walls are always the same height and vertically aligned
  2. The walls have some degree of thickness
  3. The walls collide with each other
  4. The collision between two walls is always right surface intersecting with left surface

Okay, now with that in mind we’ll need two tools.

  1. An an ability to draw 3D triangles
  2. Raycasting

Our process will be as follows.

  1. Identify two walls that are intersecting right to left
  2. Find the two outermost points of each wall mid way up the total vertical height
  3. Raycast inward to find the intersection between the two walls
  4. Draw a triangle with those three points and set its thickness to the height of the wall.

The end result it the following:

2019-10-23_21-33-04

wall gap fill.rbxl (16.3 KB)

10 Likes

Okay thanks(like always Ego Moose to the rescue)
I will get to trying this asap and I will let you know!

1 Like

Upon further inspection, it appears as though it doesn’t work in my game. Sadly, 2 of the assumptions you made were incorrect - the walls are not always right surface collisions, and the walls are not upright. When they are created - (shown in the original script) its created rotated so that the X is the height and the Y is the width. Any thoughts on making it compatible for this?

Ok, so took a while and got a working script on some occasions.

Functions

(yes I just edited @stravant’s Resize Allign plugin)

function GetGeometry(part, hit)
	local cf = part.CFrame
	local pos = cf.p
	--
	local sx = part.Size.x/2
	local sy = part.Size.y/2
	local sz = part.Size.z/2
	--
	local xvec = rightVector(cf)
	local yvec = topVector(cf)
	local zvec = backVector(cf)
	--
	local verts, edges, faces;
	--
	local vertexMargin;
	--
	if part:IsA('Part') then
		if part.Shape == Enum.PartType.Block or part.Shape == Enum.PartType.Cylinder then
			--8 vertices
			verts = {
				pos +xvec*sx  +yvec*sy  +zvec*sz, --top 4
				pos +xvec*sx  +yvec*sy  -zvec*sz,
				pos -xvec*sx  +yvec*sy  +zvec*sz,
				pos -xvec*sx  +yvec*sy  -zvec*sz,
				--
				pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
				pos +xvec*sx  -yvec*sy  -zvec*sz,
				pos -xvec*sx  -yvec*sy  +zvec*sz,
				pos -xvec*sx  -yvec*sy  -zvec*sz,
			}
			--12 edges
			edges = {
				{verts[1], verts[2], math.min(2*sx, 2*sy)}, --top 4
				{verts[3], verts[4], math.min(2*sx, 2*sy)},
				{verts[1], verts[3], math.min(2*sy, 2*sz)},
				{verts[2], verts[4], math.min(2*sy, 2*sz)},
				--
				{verts[5], verts[6], math.min(2*sx, 2*sy)}, --bottom 4
				{verts[7], verts[8], math.min(2*sx, 2*sy)},
				{verts[5], verts[7], math.min(2*sy, 2*sz)},
				{verts[6], verts[8], math.min(2*sy, 2*sz)},
				--
				{verts[1], verts[5], math.min(2*sx, 2*sz)}, --verticals
				{verts[2], verts[6], math.min(2*sx, 2*sz)},
				{verts[3], verts[7], math.min(2*sx, 2*sz)},
				{verts[4], verts[8], math.min(2*sx, 2*sz)},
			}
			--6 faces
			faces = {
				{verts[1],  xvec, zvec, {verts[1], verts[2], verts[6], verts[5]}}, --right
				{verts[3], -xvec, zvec, {verts[3], verts[4], verts[8], verts[7]}}, --left
				{verts[1],  yvec, xvec, {verts[1], verts[2], verts[4], verts[3]}}, --top
				{verts[5], -yvec, xvec, {verts[5], verts[6], verts[8], verts[7]}}, --bottom
				{verts[1],  zvec, xvec, {verts[1], verts[3], verts[7], verts[5]}}, --back
				{verts[2], -zvec, xvec, {verts[2], verts[4], verts[8], verts[6]}}, --front
			}
		elseif part.Shape == Enum.PartType.Ball then
			-- just have one face and vertex, at the hit pos
			verts = { hit }
			edges = {} --edge can be selected as the normal of the face if the user needs it
			local norm = (hit-pos).unit
			local norm2 = norm:Cross(Vector3.new(0,1,0)).unit
			faces = {
				{hit, norm, norm2, {}}
			}
 
		else
			assert(false, "Bad Part Shape: `"..tostring(part.Shape).."`")
		end
	elseif part:IsA('CornerWedgePart') then
		local slantVec1 = ( zvec*sy + yvec*sz).unit
		local slantVec2 = (-xvec*sy + yvec*sx).unit
		-- 5 verts
		verts = {
			pos +xvec*sx  +yvec*sy  -zvec*sz, --top 1
			--
			pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
			pos +xvec*sx  -yvec*sy  -zvec*sz,
			pos -xvec*sx  -yvec*sy  +zvec*sz,
			pos -xvec*sx  -yvec*sy  -zvec*sz,
		}
		-- 8 edges
		edges = {
			{verts[2], verts[3], 0}, -- bottom 4
			{verts[3], verts[5], 0},
			{verts[5], verts[4], 0},
			{verts[4], verts[1], 0},
			--
			{verts[1], verts[3], 0}, -- vertical
			--
			{verts[1], verts[2], 0}, -- side diagonals
			{verts[1], verts[5], 0},
			--
			{verts[1], verts[4], 0}, -- middle diagonal
		}
		-- 5 faces
		faces = {
			{verts[2], -yvec, xvec, {verts[2], verts[3], verts[5], verts[4]}}, -- bottom
			--
			{verts[1],  xvec, -yvec, {verts[1], verts[3], verts[2]}}, -- sides
			{verts[1], -zvec, -yvec, {verts[1], verts[3], verts[5]}},
			--
			{verts[1],  slantVec1, xvec, {verts[1], verts[2], verts[4]}}, -- tops
			{verts[1],  slantVec2, zvec, {verts[1], verts[5], verts[4]}},
		}
 
	elseif part:IsA('WedgePart') then
		local slantVec = (-zvec*sy + yvec*sz).unit
		--6 vertices
		verts = {
			pos +xvec*sx  +yvec*sy  +zvec*sz, --top 2
			pos -xvec*sx  +yvec*sy  +zvec*sz,
			--
			pos +xvec*sx  -yvec*sy  +zvec*sz, --bottom 4
			pos +xvec*sx  -yvec*sy  -zvec*sz,
			pos -xvec*sx  -yvec*sy  +zvec*sz,
			pos -xvec*sx  -yvec*sy  -zvec*sz,
		}
		--9 edges
		edges = {
			{verts[1], verts[2], math.min(2*sy, 2*sz)}, --top 1
			--
			{verts[1], verts[4], math.min(2*sy, 2*sz)}, --slanted 2
			{verts[2], verts[6], math.min(2*sy, 2*sz)},
			--
			{verts[3], verts[4], math.min(2*sx, 2*sy)}, --bottom 4
			{verts[5], verts[6], math.min(2*sx, 2*sy)},
			{verts[3], verts[5], math.min(2*sy, 2*sz)},
			{verts[4], verts[6], math.min(2*sy, 2*sz)},
			--
			{verts[1], verts[3], math.min(2*sx, 2*sz)}, --vertical 2
			{verts[2], verts[5], math.min(2*sx, 2*sz)},
		}
		--5 faces
		faces = {
			{verts[1],  xvec, zvec, {verts[1], verts[4], verts[3]}}, --right
			{verts[2], -xvec, zvec, {verts[2], verts[6], verts[5]}}, --left
			{verts[3], -yvec, xvec, {verts[3], verts[4], verts[6], verts[5]}}, --bottom
			{verts[1],  zvec, xvec, {verts[1], verts[2], verts[5], verts[3]}}, --back
			{verts[2], slantVec, slantVec:Cross(xvec), {verts[2], verts[1], verts[4], verts[6]}}, --slanted
		}
	elseif part:IsA('Terrain') then
		local cellPos = game.Workspace.Terrain:WorldToCellPreferSolid(hit)
		local mat, block, orient = game.Workspace.Terrain:GetCell(cellPos.x, cellPos.y, cellPos.z)
		local pos = game.Workspace.Terrain:CellCenterToWorld(cellPos.x, cellPos.y, cellPos.z)
		--
		vertexMargin = 4
		--
		local orientToNumberMap = {
			[Enum.CellOrientation.NegZ] = 0;
			[Enum.CellOrientation.X]    = 1;
			[Enum.CellOrientation.Z]    = 2;
			[Enum.CellOrientation.NegX] = 3;
		}
		--
		local xvec = CFrame.Angles(0, math.pi/2*(orientToNumberMap[orient]-1), 0).lookVector
		local yvec = Vector3.new(0, 1, 0)
		local zvec = xvec:Cross(yvec)
		--
		if block == Enum.CellBlock.Solid then
			--8 vertices
			verts = {
				pos +xvec*2  +yvec*2  +zvec*2, --top 4
				pos +xvec*2  +yvec*2  -zvec*2,
				pos -xvec*2  +yvec*2  +zvec*2,
				pos -xvec*2  +yvec*2  -zvec*2,
				--
				pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
				pos +xvec*2  -yvec*2  -zvec*2,
				pos -xvec*2  -yvec*2  +zvec*2,
				pos -xvec*2  -yvec*2  -zvec*2,
			}
			--12 edges
			edges = {
				{verts[1], verts[2], 4}, --top 4
				{verts[3], verts[4], 4},
				{verts[1], verts[3], 4},
				{verts[2], verts[4], 4},
				--
				{verts[5], verts[6], 4}, --bottom 4
				{verts[7], verts[8], 4},
				{verts[5], verts[7], 4},
				{verts[6], verts[8], 4},
				--
				{verts[1], verts[5], 4}, --verticals
				{verts[2], verts[6], 4},
				{verts[3], verts[7], 4},
				{verts[4], verts[8], 4},
			}
			--6 faces
			faces = {
				{pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[6], verts[5]}}, --right
				{pos-xvec*2, -xvec, zvec, {verts[3], verts[4], verts[8], verts[7]}}, --left
				{pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[4], verts[3]}}, --top
				{pos-yvec*2, -yvec, xvec, {verts[5], verts[6], verts[8], verts[7]}}, --bottom
				{pos+zvec*2,  zvec, xvec, {verts[1], verts[3], verts[7], verts[5]}}, --back
				{pos-zvec*2, -zvec, xvec, {verts[2], verts[4], verts[8], verts[6]}}, --front
			}
 
		elseif block == Enum.CellBlock.VerticalWedge then
			--top wedge. Similar to wedgepart, but we need to flip the Z axis
			zvec = -zvec
			xvec = -xvec
			--
			local slantVec = (-zvec*2 + yvec*2).unit
			--6 vertices
			verts = {
				pos +xvec*2  +yvec*2  +zvec*2, --top 2
				pos -xvec*2  +yvec*2  +zvec*2,
				--
				pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
				pos +xvec*2  -yvec*2  -zvec*2,
				pos -xvec*2  -yvec*2  +zvec*2,
				pos -xvec*2  -yvec*2  -zvec*2,
			}
			--9 edges
			edges = {
				{verts[1], verts[2], 4}, --top 1
				--
				{verts[1], verts[4], 4}, --slanted 2
				{verts[2], verts[6], 4},
				--
				{verts[3], verts[4], 4}, --bottom 4
				{verts[5], verts[6], 4},
				{verts[3], verts[5], 4},
				{verts[4], verts[6], 4},
				--
				{verts[1], verts[3], 4}, --vertical 2
				{verts[2], verts[5], 4},
			}
			--5 faces
			faces = {
				{pos+xvec*2,  xvec, zvec, {verts[1], verts[4], verts[3]}}, --right
				{pos-xvec*2, -xvec, zvec, {verts[2], verts[6], verts[5]}}, --left
				{pos-yvec*2, -yvec, xvec, {verts[3], verts[4], verts[6], verts[5]}}, --bottom
				{pos+zvec*2,  zvec, xvec, {verts[1], verts[2], verts[5], verts[3]}}, --back
				{pos, slantVec, slantVec:Cross(xvec), {verts[2], verts[1], verts[4], verts[6]}}, --slanted
			}
 
		elseif block == Enum.CellBlock.CornerWedge then
			--top corner wedge
			--4 verts
			verts = {
				pos +xvec*2  +yvec*2  -zvec*2, --top 1
				--
				pos +xvec*2  -yvec*2  -zvec*2, --bottom 3
				pos +xvec*2  -yvec*2  +zvec*2,
				pos -xvec*2  -yvec*2  -zvec*2,
			}
			--6 edges
			edges = {
				{verts[1], verts[2], 3},
				{verts[1], verts[3], 3},
				{verts[1], verts[4], 3},
				{verts[2], verts[3], 3},
				{verts[2], verts[4], 3},
				{verts[3], verts[4], 3},
			}
			local centerXZ = ((verts[3]+verts[4])/2 + verts[2])/2
			local slantCenter = Vector3.new(centerXZ.x, pos.y, centerXZ.z)
			local slantFaceDir = ((zvec-xvec).unit*2 + Vector3.new(0, math.sqrt(2), 0)).unit
			--4 faces
			faces = {
				{centerXZ, -yvec, xvec, {verts[2], verts[3], verts[4]}},
				{pos + xvec*2,  xvec, yvec, {verts[1], verts[2], verts[3]}},
				{pos - zvec*2, -zvec, yvec, {verts[1], verts[2], verts[4]}},
				{slantCenter, slantFaceDir, (xvec+zvec).unit, {verts[1], verts[3], verts[4]}},
			}
 
		elseif block == Enum.CellBlock.InverseCornerWedge then
			--block corner cut
			--7 vertices
			verts = {
				pos +xvec*2  +yvec*2  +zvec*2, --top 3
				pos +xvec*2  +yvec*2  -zvec*2,
				pos -xvec*2  +yvec*2  -zvec*2,
				--
				pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
				pos +xvec*2  -yvec*2  -zvec*2,
				pos -xvec*2  -yvec*2  +zvec*2,
				pos -xvec*2  -yvec*2  -zvec*2,
			}
			--12 edges
			edges = {
				{verts[1], verts[2], 4}, --top 4
				{verts[2], verts[3], 4},
				--
				{verts[4], verts[5], 4}, --bottom 4
				{verts[6], verts[7], 4},
				{verts[4], verts[6], 4},
				{verts[5], verts[7], 4},
				--
				{verts[1], verts[4], 4}, --verticals
				{verts[2], verts[5], 4},
				{verts[3], verts[7], 4},
				--
				{verts[1], verts[3], 2.5}, --slants
				{verts[1], verts[6], 2.5},
				{verts[3], verts[6], 2.5},
			}
			--7 faces
			local centerXZ = ((verts[4]+verts[7])/2 + verts[6])/2
			local slantCenter = Vector3.new(centerXZ.x, pos.y, centerXZ.z)
			local slantFaceDir = ((zvec-xvec).unit*2 + Vector3.new(0, math.sqrt(2), 0)).unit
			faces = {
				{pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[5], verts[4]} }, --right
				{pos-xvec*2, -xvec, zvec, {verts[3], verts[7], verts[6]}           }, --left
				{pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[3]}           }, --top
				{pos-yvec*2, -yvec, xvec, {verts[4], verts[5], verts[7], verts[6]} }, --bottom
				{pos+zvec*2,  zvec, xvec, {verts[1], verts[6], verts[4]}           }, --back
				{pos-zvec*2, -zvec, xvec, {verts[2], verts[3], verts[7], verts[5]} }, --front
				{slantCenter, slantFaceDir, (xvec+zvec).unit, {verts[1], verts[3], verts[6]}}, --slant
			}
 
		elseif block == Enum.CellBlock.HorizontalWedge then
			--block side wedge
			--6 vertices
			verts = {
				pos +xvec*2  +yvec*2  +zvec*2, --top 4
				pos +xvec*2  +yvec*2  -zvec*2,
				pos -xvec*2  +yvec*2  -zvec*2,
				--
				pos +xvec*2  -yvec*2  +zvec*2, --bottom 4
				pos +xvec*2  -yvec*2  -zvec*2,
				pos -xvec*2  -yvec*2  -zvec*2,
			}
			--9 edges
			edges = {
				{verts[1], verts[2], 4}, --top 4
				{verts[2], verts[3], 4},
				--
				{verts[4], verts[5], 4}, --bottom 4
				{verts[5], verts[6], 4},
				--
				{verts[1], verts[4], 4}, --verticals
				{verts[2], verts[5], 4},
				{verts[3], verts[6], 4},
				--
				{verts[1], verts[3], 2.5}, --slants
				{verts[4], verts[6], 2.5},
			}
			--5 faces
			faces = {
				{pos+xvec*2,  xvec, zvec, {verts[1], verts[2], verts[5], verts[4]} }, --right
				{pos+yvec*2,  yvec, xvec, {verts[1], verts[2], verts[3]}           }, --top
				{pos-yvec*2, -yvec, xvec, {verts[4], verts[5], verts[6]}           }, --bottom
				{pos-zvec*2, -zvec, xvec, {verts[2], verts[3], verts[6], verts[5]} }, --front
				{pos, (zvec-xvec).unit, yvec, {verts[1], verts[3], verts[4], verts[6]}}, --slant
			}
 
		else
			assert(false, "unreachable")
		end
	end
	--
	local geometry = {
		part = part;
		vertices = verts;
		edges = edges;
		faces = faces;
		vertexMargin = vertexMargin or math.min(sx, sy, sz)*2;
	}
	--
	local geomId = 0
	--
	for i, dat in pairs(faces) do
		geomId = geomId + 1
		dat.id = geomId
		dat.point = dat[1]
		dat.normal = dat[2]
		dat.direction = dat[3]
		dat.vertices = dat[4]
		dat.type = 'Face'
		--avoid Event bug (if both keys + indicies are present keys are discarded when passing tables)
		dat[1], dat[2], dat[3], dat[4] = nil, nil, nil, nil
	end
	for i, dat in pairs(edges) do
		geomId = geomId + 1
		dat.id = geomId
		dat.a, dat.b = dat[1], dat[2]
		dat.direction = (dat.b-dat.a).unit
		dat.length = (dat.b-dat.a).magnitude
		dat.edgeMargin = dat[3]
		dat.type = 'Edge'
		--avoid Event bug (if both keys + indicies are present keys are discarded when passing tables)
		dat[1], dat[2], dat[3] = nil, nil, nil
	end
	for i, dat in pairs(verts) do
		geomId = geomId + 1
		verts[i] = {
			position = dat;
			id = geomId;
			ignoreUnlessNeeded =false;
			type = 'Vertex';
		}
	end
	--
	return geometry
end

local function rightVector(cf)
	local _,_,_,r4,_,_,r7,_,_,r10,_,_ = cf:components()
	return Vector3.new(r4,r7,r10)
end
local function leftVector(cf)
	local _,_,_,r4,_,_,r7,_,_,r10,_,_ = cf:components()
	return Vector3.new(-r4,-r7,-r10)
end
local function topVector(cf)
	local _,_,_,_,r5,_,_,r8,_,_,r11,_ = cf:components()
	return Vector3.new(r5,r8,r11)
end
local function bottomVector(cf)
	local _,_,_,_,r5,_,_,r8,_,_,r11,_ = cf:components()
	return Vector3.new(-r5,-r8,-r11)
end
local function backVector(cf)
	local _,_,_,_,_,r6,_,_,r9,_,_,r12 = cf:components()
	return Vector3.new(r6,r9,r12)
end
local function frontVector(cf)
	local _,_,_,_,_,r6,_,_,r9,_,_,r12 = cf:components()
	return Vector3.new(-r6,-r9,-r12)
end

local function otherNormals(dir)
	if math.abs(dir.X) > 0 then
		return Vector3.new(0, 1, 0), Vector3.new(0, 0, 1)
	elseif math.abs(dir.Y) > 0 then
		return Vector3.new(1, 0, 0), Vector3.new(0, 0, 1)
	else
		return Vector3.new(1, 0, 0), Vector3.new(0, 1, 0)
	end
end

local function extend(v, amount)
	return v.unit * (v.magnitude + amount) 
end

local function drawFace(parent, part, normalId, color, trans)
	local tb = {}
	--
	local hsize = part.Size / 2
	local faceDir = Vector3.FromNormalId(normalId)
	local faceA, faceB = otherNormals(faceDir)
	faceDir, faceA, faceB = faceDir*hsize, faceA*hsize, faceB*hsize
	--
	local function seg(size, cf)
		local segment = Instance.new('Part', parent)
		segment.BrickColor = color
		segment.Anchored = true
		segment.Locked = true
		segment.Archivable = false
		segment.Transparency = trans
		segment.TopSurface = 'Smooth'
		segment.BottomSurface = 'Smooth'
		segment.FormFactor = 'Custom'
		segment.Size = size
		segment.CFrame = part.CFrame * cf
		table.insert(tb, segment)
	end
	--
	seg(extend(faceA, 0.1)*2, CFrame.new(faceDir + faceB))
	seg(extend(faceA, 0.1)*2, CFrame.new(faceDir - faceB))
	seg(extend(faceB, 0.1)*2, CFrame.new(faceDir + faceA))
	seg(extend(faceB, 0.1)*2, CFrame.new(faceDir - faceA))
	--
	return tb
end

local function getFacePoints(face)
	local hsize = face.Object.Size / 2
 	local faceDir = Vector3.FromNormalId(face.Normal)
	local faceA, faceB = otherNormals(faceDir)
	faceDir, faceA, faceB = faceDir*hsize, faceA*hsize, faceB*hsize
	--
	local function sp(offset)
		return (face.Object.CFrame * CFrame.new(offset)).p
	end
	--
	return {
		sp(faceDir + faceA + faceB);
		sp(faceDir + faceA - faceB);
		sp(faceDir - faceA - faceB);
		sp(faceDir - faceA + faceB);
	}
end

local function getPoints(part)
	local hsize = part.Size / 2
	local cf = part.CFrame
	local points = {}
	for i = -1, 1, 2 do
		for j = -1, 1, 2 do
			for k = -1, 1, 2 do
				table.insert(points, cf:pointToWorldSpace(Vector3.new(i, j, k) * hsize))
			end
		end
	end
	return points
end

local function getNormal(face)
	return face.Object.CFrame:vectorToWorldSpace(Vector3.FromNormalId(face.Normal))
end

local function getDimension(face)
	local dir = Vector3.FromNormalId(face.Normal)
	return Vector3.new(math.abs(dir.X), math.abs(dir.Y), math.abs(dir.Z))
end

function cl0(n)
	return (n > 0) and n or 0
end
function RealDistanceFrom(point, part)
	local p = part.CFrame:pointToObjectSpace(part.Position)
	local hz = part.Size/2
	local sep = Vector3.new(cl0(math.abs(p.x)-hz.x), cl0(math.abs(p.y)-hz.y), cl0(math.abs(p.z)-hz.z))
	return sep.magnitude
end

function getClosestPointTo(part, points)
	local closestDistance = math.huge
	local closestPoint = nil
	for _, point in pairs(points) do
		local dist = RealDistanceFrom(point, part)
		if dist < closestDistance then
			closestDistance = dist
			closestPoint = point
		end
	end
	return closestPoint
end

function getFurthestPointTo(part, points)
	local furthestDistance = -math.huge
	local furthestPoint = nil
	for _, point in pairs(points) do
		local dist = RealDistanceFrom(point, part)
		if dist > furthestDistance then
			furthestDistance = dist
			furthestPoint = point
		end
	end
	return furthestPoint
end

-- Get the point in the list most "out" of the face
function getPositivePointToFace(face, points)
	local hsize = face.Object.Size / 2
	local faceDir = Vector3.FromNormalId(face.Normal)
	local faceNormal = face.Object.CFrame:vectorToWorldSpace(faceDir)
	local facePoint = face.Object.CFrame:pointToWorldSpace(faceDir * hsize)
	--
	local maxDist = -math.huge
	local maxPoint = nil
	for _, point in pairs(points) do
		local dist = (point - facePoint):Dot(faceNormal)
		if dist > maxDist then
			maxDist = dist
			maxPoint = point
		end
	end
	return maxPoint
end

function getNegativePointToFace(face, points)
	local hsize = face.Object.Size / 2
	local faceDir = Vector3.FromNormalId(face.Normal)
	local faceNormal = face.Object.CFrame:vectorToWorldSpace(faceDir)
	local facePoint = face.Object.CFrame:pointToWorldSpace(faceDir * hsize)
	--
	local minDist = math.huge
	local minPoint = nil
	for _, point in pairs(points) do
		local dist = (point - facePoint):Dot(faceNormal)
		if dist < minDist then
			minDist = dist
			minPoint = point
		end
	end
	return minPoint
end

function resizePart(part, normal, delta)
	local axis = Vector3.FromNormalId(normal)
	local cf = part.CFrame
	local targetSize = part.Size + Vector3.new(math.abs(axis.X), math.abs(axis.Y), math.abs(axis.Z))*delta
	if not part:IsA('FormFactorPart') then
		-- Nothing to do, can't modify formfactor anyways
	elseif part.FormFactor == Enum.FormFactor.Brick then
		if targetSize.X % 1 ~= 0 or targetSize.Y % 1.2 ~= 0 or targetSize.Z % 1 ~= 0 then
			part.FormFactor = 'Custom'
		end
	elseif part.FormFactor == Enum.FormFactor.Symmetric then
		if targetSize.X % 1 ~= 0 or targetSize.Y % 1 ~= 0 or targetSize.Z % 1 ~= 0 then
			part.FormFactor = 'Custom'
		end
	elseif part.FormFactor == Enum.FormFactor.Plate then
		if targetSize.X % 1 ~= 0 or targetSize.Y % 0.4 ~= 0 or targetSize.Z % 1 ~= 0 then
			part.FormFactor = 'Custom'
		end
	else
		-- nothing to do, is custom
	end
	part:BreakJoints()
	part.Size = targetSize
	part:BreakJoints()
	part.CFrame = cf * CFrame.new(axis * (delta/2))
end

------------------
--IMPLEMENTATION--
------------------

-- Target finding (Taking into account currently selected faces / target filter

-- Hover Face


-- Calculate the result
function DoExtend(faceA, faceB)
	--
	local pointsA = getFacePoints(faceA)
	local pointsB = getFacePoints(faceB)
	--
	local extendPointA, extendPointB;
	
	extendPointA = getPositivePointToFace(faceB, pointsA)
	extendPointB = getPositivePointToFace(faceA, pointsB)
	
	local startSep = extendPointB - extendPointA
	--
	local localDimensionA = getDimension(faceA)
	local localDimensionB = getDimension(faceB)
	local dirA = getNormal(faceA)
	local dirB = getNormal(faceB)
	--
	-- Find the closest distance between the rays (extendPointA, dirA) and (extendPointB, dirB):
	-- See: http://geomalgorithms.com/a07-_distance.html#dist3D_Segment_to_Segment
	local a, b, c, d, e = dirA:Dot(dirA), dirA:Dot(dirB), dirB:Dot(dirB), dirA:Dot(startSep), dirB:Dot(startSep)
	local denom = a*c - b*b

	-- Is this a degenerate case?
	if math.abs(denom) < 0.001 then
		-- Parts are parallel, extend faceA to faceB
		local lenA = (extendPointA - extendPointB):Dot(getNormal(faceB))
		local extendableA = (localDimensionA * faceA.Object.Size).magnitude
		if getNormal(faceA):Dot(getNormal(faceB)) > 0 then
			lenA = -lenA
		end
		if lenA < -extendableA then
			return
		end
		resizePart(faceA.Object, faceA.Normal, lenA)

		return
	end

	-- Get the distances to extend by
	local lenA = -(b*e - c*d) / denom
	local lenB = -(a*e - b*d) / denom

	

	-- Are both extents doable?
	-- Note: Negative amounts to extend by *are* allowed, but only
	-- up to the size of the part on the dimension being extended on.
	local extendableA = (localDimensionA * faceA.Object.Size).magnitude
	local extendableB = (localDimensionB * faceB.Object.Size).magnitude
	if lenA < -extendableA then
		return
	end
	if lenB < -extendableB then
		return
	end

	-- Both are doable, execute:
	resizePart(faceA.Object, faceA.Normal, lenA)
	resizePart(faceB.Object, faceB.Normal, lenB)
end

local function getMag(p1,p2)
	return (p1 - p2).magnitude
end

local function getPositionFromFace(face, part)
	local c = part.CFrame
	local rv = c.RightVector
	local uv = c.UpVector
	local lv = c.LookVector
	local s = part.Size / 2
	local rightFacePos = Vector3.new(0,rv * s.X,0)
	local leftFacePos = Vector3.new(0, rv * -s.X)
	local topFacePos = Vector3.new(0, uv * s.Y,0)
	local bottomFacePos = Vector3.new(0, uv * -s.Y,0)
	local frontFacePos = Vector3.new(0, uv * s.Z,0)
	local backFacePos = Vector3.new(0, uv * -s.Z,0)
	
	if face == "Front" then return frontFacePos end if face == "Back" then return backFacePos end if face == "Right" then return rightFacePos end if face == "Left" then return leftFacePos end if face == "Top" then return topFacePos end if face == "Bottom" then return bottomFacePos end
end

Implementation

local startPoint = cframe[1].p
local endpoint = cframe[2].p
local wall = Instance.new("Part")
wall.Size = Vector3.new(10, 0.5, (endPoint - startPoint).Magnitude)
wall.Anchored = true

wall.Name = "Base"
wall.Material = Enum.Material.SmoothPlastic

wall.CFrame = CFrame.new(startPoint, endPoint) * CFrame.Angles(0,0,math.rad(90))

wall.CFrame = wall.CFrame + wall.CFrame.LookVector * ((endPoint - startPoint).Magnitude/2)

local gridPoint = Instance.new("Part")
gridPoint.Size = Vector3.new(10, 0, (endPoint - startPoint).Magnitude)
gridPoint.Anchored = true
gridPoint.CanCollide = false


gridPoint.Name = "GridPoint"

gridPoint.Transparency = 1
gridPoint.Material = Enum.Material.SmoothPlastic

gridPoint.CFrame = wall.CFrame + wall.CFrame.UpVector * 0.55


local model = Instance.new("Model")
model.Parent = plane.ArchitectureHolder
model.Name = "Wall"

wall.Parent = model
gridPoint.Parent = model
model.PrimaryPart = wall

for _, v in pairs(wall:GetTouchingParts()) do
	if v.Parent.Name == "Wall" then
		local function gN(f)
			return Enum.NormalId[f]
		end
		
		local f1Pos = getPositionFromFace("Front", wall)
		local f2Pos = getPositionFromFace("Front", v)
		local b1Pos = getPositionFromFace("Back", wall)
		local b2Pos = getPositionFromFace("Back", v)
		
		local closestFace = {"Front", "Front", getMag(f1Pos, f2Pos)}
		
		if closestFace[3] > getMag(f1Pos, b2Pos) then closestFace = {"Front", "Back", getMag(f1Pos, b2Pos)} end
		if closestFace[3] > getMag(b1Pos, f2Pos) then closestFace = {"Back", "Front", getMag(b1Pos, f2Pos)} end
		if closestFace[3] > getMag(b1Pos, b2Pos)then closestFace = {"Back", "Back", getMag(b1Pos, b2Pos)} end
		local face1 = {Object = wall; Normal = gN(closestFace[1])}
		local face2 = {Object = v; Normal = gN(closestFace[2])}
		
		print(wall, v, face1.Object, face2.Object)
		
		DoExtend(face1, face2)
	end
end

Im just gonna link the game cause its hard to describe. Sometimes when you place 3 touching walls, they all get resized down to like 0.3 studs. And some other times its perfect

How would you make a room detector aka. an enclosed shape for a grid building system?