Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --By xXxMoNkEyMaNxXx
- 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
- --NormalShower part--
- local Player=Game:GetService'Players'.LocalPlayer
- local Mouse=Player:GetMouse()
- repeat wait() until Player.Character
- local NormalShower=Player.Character:FindFirstChild'NormalShower' or Instance.new("Part",Player.Character)
- NormalShower.Name="NormalShower"
- NormalShower.FormFactor=3
- NormalShower.Size=Vector3.new(0.2,0.2,4)
- NormalShower.TopSurface=0
- NormalShower.BottomSurface=0
- NormalShower.CanCollide=false
- NormalShower.Anchored=true
- local tick=tick
- local sqrt=math.sqrt
- local data={}
- local N=1e3
- local dN=1e3
- local function Update()
- local MouseTarget=Mouse.Target
- if MouseTarget then
- local HitPoint=Mouse.hit.p
- local t0=tick()
- local Normal=NormalVector(MouseTarget,HitPoint)--Math time!
- local t1=tick()
- data[#data+1]=t1-t0
- NormalShower.Transparency=0
- NormalShower.CFrame=mat3(HitPoint,HitPoint+Normal)*mat3(0,0,-NormalShower.Size.z/2)
- else
- NormalShower.Transparency=1
- end
- if #data>N then
- N=N+dN
- local biggest=0
- local smallest=math.huge
- local sum=0
- for i=1,#data do
- local di=data[i]
- sum=sum+di
- if di>biggest then
- biggest=di
- end
- if di<smallest then
- smallest=di
- end
- end
- local avg=sum/#data
- local var=0
- for i=1,#data do
- local d=data[i]-avg
- var=var+d*d
- end
- print("Calls per second: max="..1/smallest.." min="..1/biggest.." avg="..1/avg.."+-"..sqrt(var/(#data*(#data-1)))/(avg*avg))
- end
- end
- Game:GetService'RunService'.RenderStepped:connect(Update)
- Mouse.Move:connect(Update)
Add Comment
Please, Sign In to add comment