Whitemambaa

Surface Normal Shower

May 5th, 2014
1,002
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.67 KB | None | 0 0
  1. --By xXxMoNkEyMaNxXx
  2. local Terrain=workspace.Terrain
  3. local GetCell=Terrain.GetCell
  4. local CellCenterToWorld=Terrain.CellCenterToWorld
  5. local WorldToCellPreferSolid=Terrain.WorldToCellPreferSolid
  6.  
  7. local vec3=Vector3.new
  8. local IdentityVector=vec3()
  9. local dot=IdentityVector.Dot
  10. local cross=IdentityVector.Cross
  11.  
  12. local mat3=CFrame.new
  13. local IdentityCFrame=mat3()
  14. local ptos=IdentityCFrame.pointToObjectSpace
  15. local vtws=IdentityCFrame.vectorToWorldSpace
  16.  
  17. --Returns:
  18. --Index of closest plane to p
  19. --Distance to surface from p
  20. local function ClosestNormalVector(p,planes)
  21.     local best_d=-math.huge
  22.     local best_i
  23.     for i=1,#planes do
  24.         local plane=planes[i]
  25.         local d=dot(plane[1],p-plane[2])
  26.         if d>best_d then
  27.             best_i,best_d=i,d
  28.         end
  29.     end
  30.     return best_i,best_d
  31. end
  32.  
  33. --Part geometry data
  34. local UnitaryConvexPlaneMeshes={--I realized that I could make each component of the normal vector dependent on every component of the size using matrices (genius!)
  35.     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)}},
  36.     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)}},
  37.     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)}}
  38. }
  39.  
  40. --Terrain geometry data
  41. local TerrainCellSize=vec3(4,4,4)--Support arbitrary stuff BECAUSE I CAN
  42. local TerrainCellOrientations={
  43.     [0]=mat3(0,0,0, 1,0,0, 0,1,0, 0,0,1),
  44.     mat3(0,0,0, 0,0,1, 0,1,0, -1,0,0),
  45.     mat3(0,0,0, -1,0,0, 0,1,0, 0,0,-1),
  46.     mat3(0,0,0, 0,0,-1, 0,1,0, 1,0,0)
  47. }
  48. local TerrainCellBlockUnitaryConvexPlaneMeshes={
  49.     [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)}},
  50.     {{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)}},
  51.     {{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}},
  52.     {{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}},
  53.     {{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)}}
  54. }
  55.  
  56. local function NormalVector(part,point)
  57.     if part.ClassName=="Part" and (part.Shape==Enum.PartType.Ball or part.Shape==Enum.PartType.Cylinder) then
  58.         return vtws(part.CFrame,ptos(part.CFrame,point).unit)--A bit simpler than the other ones.  Just a bit.
  59.     else
  60.         local partCFrame,partSize=part.CFrame,part.Size
  61.         local UCPM
  62.         if part.ClassName=="Terrain" then
  63.             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.
  64.             local CellMaterial,CellBlock,CellOrientation=GetCell(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
  65.             partCFrame=TerrainCellOrientations[CellOrientation.Value]+CellCenterToWorld(part,CellGridLocation.x,CellGridLocation.y,CellGridLocation.z)
  66.             partSize=TerrainCellSize
  67.             UCPM=TerrainCellBlockUnitaryConvexPlaneMeshes[CellBlock.Value]
  68.         else
  69.             UCPM=UnitaryConvexPlaneMeshes[part.ClassName] or UnitaryConvexPlaneMeshes.Part--Trusses, SpawnLocations, etc.
  70.         end
  71.         local CPM={}
  72.         for i=1,#UCPM do
  73.             local plane=UCPM[i]
  74.             CPM[i]={(plane[1]*partSize).unit,plane[2]*partSize}
  75.         end
  76.         local PlaneIndex,DistanceToSurface=ClosestNormalVector(ptos(partCFrame,point),CPM)
  77.         if PlaneIndex then
  78.             return vtws(partCFrame,CPM[PlaneIndex][1])
  79.         else
  80.             return IdentityVector--Dead code unless the tables are tampered with
  81.         end
  82.     end
  83. end
  84.  
  85. --NormalShower part--
  86. local Player=Game:GetService'Players'.LocalPlayer
  87. local Mouse=Player:GetMouse()
  88.  
  89. repeat wait() until Player.Character
  90. local NormalShower=Player.Character:FindFirstChild'NormalShower' or Instance.new("Part",Player.Character)
  91. NormalShower.Name="NormalShower"
  92. NormalShower.FormFactor=3
  93. NormalShower.Size=Vector3.new(0.2,0.2,4)
  94. NormalShower.TopSurface=0
  95. NormalShower.BottomSurface=0
  96. NormalShower.CanCollide=false
  97. NormalShower.Anchored=true
  98.  
  99. local tick=tick
  100. local sqrt=math.sqrt
  101. local data={}
  102. local N=1e3
  103. local dN=1e3
  104. local function Update()
  105.     local MouseTarget=Mouse.Target
  106.     if MouseTarget then
  107.         local HitPoint=Mouse.hit.p
  108.         local t0=tick()
  109.         local Normal=NormalVector(MouseTarget,HitPoint)--Math time!
  110.         local t1=tick()
  111.         data[#data+1]=t1-t0
  112.         NormalShower.Transparency=0
  113.         NormalShower.CFrame=mat3(HitPoint,HitPoint+Normal)*mat3(0,0,-NormalShower.Size.z/2)
  114.     else
  115.         NormalShower.Transparency=1
  116.     end
  117.     if #data>N then
  118.         N=N+dN
  119.         local biggest=0
  120.         local smallest=math.huge
  121.         local sum=0
  122.         for i=1,#data do
  123.             local di=data[i]
  124.             sum=sum+di
  125.             if di>biggest then
  126.                 biggest=di
  127.             end
  128.             if di<smallest then
  129.                 smallest=di
  130.             end
  131.         end
  132.         local avg=sum/#data
  133.         local var=0
  134.         for i=1,#data do
  135.             local d=data[i]-avg
  136.             var=var+d*d
  137.         end
  138.         print("Calls per second: max="..1/smallest.." min="..1/biggest.." avg="..1/avg.."+-"..sqrt(var/(#data*(#data-1)))/(avg*avg))
  139.     end
  140. end
  141.  
  142. Game:GetService'RunService'.RenderStepped:connect(Update)
  143. Mouse.Move:connect(Update)
Add Comment
Please, Sign In to add comment