Whitemambaa

Surface Normal

Jul 6th, 2014
329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.92 KB | None | 0 0
  1. --By xXxMoNkEyMaNxXx
  2. --[[Example usage:
  3. local Part,Point=workspace:FindPartOnRay(ray)
  4. local Normal=NormalVector(Part,Point)
  5. yay now you have the normal vector too
  6. --]]
  7. local Terrain=workspace.Terrain
  8. local GetCell=Terrain.GetCell
  9. local CellCenterToWorld=Terrain.CellCenterToWorld
  10. local WorldToCellPreferSolid=Terrain.WorldToCellPreferSolid
  11.  
  12. local vec3=Vector3.new
  13. local IdentityVector=vec3()
  14. local dot=IdentityVector.Dot
  15. local cross=IdentityVector.Cross
  16.  
  17. local mat3=CFrame.new
  18. local IdentityCFrame=mat3()
  19. local ptos=IdentityCFrame.pointToObjectSpace
  20. local vtws=IdentityCFrame.vectorToWorldSpace
  21.  
  22. --Returns:
  23. --Index of closest plane to p
  24. --Distance to surface from p
  25. local function ClosestNormalVector(p,planes)
  26.         local best_d=-math.huge
  27.         local best_i
  28.         for i=1,#planes do
  29.                 local plane=planes[i]
  30.                 local d=dot(plane[1],p-plane[2])
  31.                 if d>best_d then
  32.                         best_i,best_d=i,d
  33.                 end
  34.         end
  35.         return best_i,best_d
  36. end
  37.  
  38. --Part geometry data
  39. local UnitaryConvexPlaneMeshes={--I realized that I could make each component of the normal vector dependent on every component of the size using matrices (genius!)
  40.         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)}},
  41.         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)}},
  42.         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)}}
  43. }
  44.  
  45. --Terrain geometry data
  46. local TerrainCellSize=vec3(4,4,4)--Support arbitrary stuff BECAUSE I CAN
  47. local TerrainCellOrientations={
  48.         [0]=mat3(0,0,0, 1,0,0, 0,1,0, 0,0,1),
  49.         mat3(0,0,0, 0,0,1, 0,1,0, -1,0,0),
  50.         mat3(0,0,0, -1,0,0, 0,1,0, 0,0,-1),
  51.         mat3(0,0,0, 0,0,-1, 0,1,0, 1,0,0)
  52. }
  53. local TerrainCellBlockUnitaryConvexPlaneMeshes={
  54.         [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)}},
  55.         {{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)}},
  56.         {{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}},
  57.         {{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}},
  58.         {{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)}}
  59. }
  60.  
  61. local function NormalVector(part,point)
  62.         if part.ClassName=="Part" and (part.Shape==Enum.PartType.Ball or part.Shape==Enum.PartType.Cylinder) then
  63.                 return vtws(part.CFrame,ptos(part.CFrame,point).unit)--A bit simpler than the other ones.  Just a bit.
  64.         else
  65.                 local partCFrame,partSize=part.CFrame,part.Size
  66.                 local UCPM
  67.                 if part.ClassName=="Terrain" then
  68.                         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.
  69.                         local CellMaterial,CellBlock,CellOrientation=GetCell(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
  70.                         partCFrame=TerrainCellOrientations[CellOrientation.Value]+CellCenterToWorld(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
  71.                         partSize=TerrainCellSize
  72.                         UCPM=TerrainCellBlockUnitaryConvexPlaneMeshes[CellBlock.Value]
  73.                 else
  74.                         UCPM=UnitaryConvexPlaneMeshes[part.ClassName] or UnitaryConvexPlaneMeshes.Part--Trusses, SpawnLocations, etc.
  75.                 end
  76.                 local CPM={}
  77.                 for i=1,#UCPM do
  78.                         local plane=UCPM[i]
  79.                         CPM[i]={(plane[1]*partSize).unit,plane[2]*partSize}
  80.                 end
  81.                 local PlaneIndex,DistanceToSurface=ClosestNormalVector(ptos(partCFrame,point),CPM)
  82.                 if PlaneIndex then
  83.                         return vtws(partCFrame,CPM[PlaneIndex][1])
  84.                 else
  85.                         return IdentityVector--Dead code unless the tables are tampered with
  86.                 end
  87.         end
  88. end
Advertisement
Add Comment
Please, Sign In to add comment