Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --By xXxMoNkEyMaNxXx
- --[[Example usage:
- local Part,Point=workspace:FindPartOnRay(ray)
- local Normal=NormalVector(Part,Point)
- yay now you have the normal vector too
- --]]
- local Terrain=workspace.Terrain
- local GetCell=Terrain.GetCell
- local CellCenterToWorld=Terrain.CellCenterToWorld
- local WorldToCellPreferSolid=Terrain.WorldToCellPreferSolid
- local vec3=Vector3.new
- local IdentityVector=vec3()
- local dot=IdentityVector.Dot
- local cross=IdentityVector.Cross
- local mat3=CFrame.new
- local IdentityCFrame=mat3()
- local ptos=IdentityCFrame.pointToObjectSpace
- local vtws=IdentityCFrame.vectorToWorldSpace
- --Returns:
- --Index of closest plane to p
- --Distance to surface from p
- local function ClosestNormalVector(p,planes)
- local best_d=-math.huge
- local best_i
- for i=1,#planes do
- local plane=planes[i]
- local d=dot(plane[1],p-plane[2])
- if d>best_d then
- best_i,best_d=i,d
- end
- end
- return best_i,best_d
- end
- --Part geometry data
- local UnitaryConvexPlaneMeshes={--I realized that I could make each component of the normal vector dependent on every component of the size using matrices (genius!)
- WedgePart={{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,1),vec3(0,0,0.5)},{mat3(0,0,0, 0,0,0, 0,0,1, 0,-1,0),vec3(0,0,0)},{vec3(1,0,0),vec3(0.5,0,0)},{vec3(-1,0,0),vec3(-0.5,0,0)}},
- CornerWedgePart={{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,0,-1),vec3(0,0,-0.5)},{mat3(0,0,0, 0,-1,0, 1,0,0, 0,0,0),vec3(0,0,0)},{mat3(0,0,0, 0,0,0, 0,0,1, 0,1,0),vec3(0,0,0)}},
- Part={{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,1,0),vec3(0,0.5,0)},{vec3(0,0,1),vec3(0,0,0.5)},{vec3(-1,0,0),vec3(-0.5,0,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)}}
- }
- --Terrain geometry data
- local TerrainCellSize=vec3(4,4,4)--Support arbitrary stuff BECAUSE I CAN
- local TerrainCellOrientations={
- [0]=mat3(0,0,0, 1,0,0, 0,1,0, 0,0,1),
- mat3(0,0,0, 0,0,1, 0,1,0, -1,0,0),
- mat3(0,0,0, -1,0,0, 0,1,0, 0,0,-1),
- mat3(0,0,0, 0,0,-1, 0,1,0, 1,0,0)
- }
- local TerrainCellBlockUnitaryConvexPlaneMeshes={
- [0]={{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,1,0),vec3(0,0.5,0)},{vec3(0,0,1),vec3(0,0,0.5)},{vec3(-1,0,0),vec3(-0.5,0,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)}},
- {{vec3(1,0,0),vec3(0.5,0,0)},{vec3(-1,0,0),vec3(-0.5,0,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)},{mat3(0,0,0, 0,0,0, 0,0,1, 0,1,0),vec3(0,0,0)}},
- {{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)},{mat3(0,0,0, 0,-1,-1, 1,0,1, 1,1,0),vec3(0.5,-0.5,-0.5)/3}},
- {{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,1,0),vec3(0,0.5,0)},{vec3(0,0,1),vec3(0,0,0.5)},{vec3(-1,0,0),vec3(-0.5,0,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)},{mat3(0,0,0, 0,-1,-1, 1,0,1, 1,1,0),vec3(-0.5,0.5,0.5)/3}},
- {{vec3(1,0,0),vec3(0.5,0,0)},{vec3(0,1,0),vec3(0,0.5,0)},{vec3(0,-1,0),vec3(0,-0.5,0)},{vec3(0,0,-1),vec3(0,0,-0.5)},{mat3(0,0,0, 0,0,-1, 0,0,0, 1,0,0),vec3(0,0,0)}}
- }
- local function NormalVector(part,point)
- if part.ClassName=="Part" and (part.Shape==Enum.PartType.Ball or part.Shape==Enum.PartType.Cylinder) then
- return vtws(part.CFrame,ptos(part.CFrame,point).unit)--A bit simpler than the other ones. Just a bit.
- else
- local partCFrame,partSize=part.CFrame,part.Size
- local UCPM
- if part.ClassName=="Terrain" then
- local CellGridLocation=WorldToCellPreferSolid(part,vec3(point.x,point.y-1e-5,point.z))--Ugly floating point fix. Alternatively, one could check the distance to the surrounding cells' CPM, and use the closest one, but I don't feel like it.
- local CellMaterial,CellBlock,CellOrientation=GetCell(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
- partCFrame=TerrainCellOrientations[CellOrientation.Value]+CellCenterToWorld(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
- partSize=TerrainCellSize
- UCPM=TerrainCellBlockUnitaryConvexPlaneMeshes[CellBlock.Value]
- else
- UCPM=UnitaryConvexPlaneMeshes[part.ClassName] or UnitaryConvexPlaneMeshes.Part--Trusses, SpawnLocations, etc.
- end
- local CPM={}
- for i=1,#UCPM do
- local plane=UCPM[i]
- CPM[i]={(plane[1]*partSize).unit,plane[2]*partSize}
- end
- local PlaneIndex,DistanceToSurface=ClosestNormalVector(ptos(partCFrame,point),CPM)
- if PlaneIndex then
- return vtws(partCFrame,CPM[PlaneIndex][1])
- else
- return IdentityVector--Dead code unless the tables are tampered with
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment