Advertisement
quahog2222111

Shadows - Roblox Stencil Shading

Jan 14th, 2023 (edited)
815
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 45.28 KB | None | 0 0
  1. --[[
  2. Built off of: https://scriptinghelpers.org/guides/silhouettes-and-shadows
  3. Created By: Razorboot
  4. Last Modified: 12/3/22
  5. Description:
  6. - An attempt at an optimized raycasted shadow-polygon implementation.
  7. - This is a complex set of object oriented mini-classes and polygonal algorithms for:
  8. - accurate n-gon to triangle conversion,
  9. - clipped polygons,
  10. - multiple light sources,
  11. - optimized vertex grabbing,
  12. - ray to plane intersection,
  13. - rotated shadow occluders and canvases,
  14. - world position shadows to 2d space, clipped, triangle-based shadows,
  15. - surface-based real-time lighting calculations:
  16. - an attempt to make the system appear more well-integrated with shadow engine.
  17. - Inspired by early 2000's Shadow Volumes in games like Thief: Deadly Shadows and Doom III.
  18. - Manifold data-structure system was inspired by collision manifolds in AABB physics.
  19. - This implementation is classless and includes nested arrays as a form of orginization.
  20.  
  21. New Changes:
  22. - I can confidently say that, in the realm of cube-shapes parts, the current engine is complete!
  23. - Complex multi-surface shadows supported.
  24. - Rotated parts (occluders and canvases) now supported.
  25. - A mini lighting engine for rendering part surfaces is now added and functional in real-time!
  26. - This supports multiple lighting options you now have control over in Shadow script!
  27. - Shadows are now Surface-Gui based for more optimal results.
  28. - Global Lighting is now supported! Local lighting can also be disabled/enabled in module settings.
  29. --]]
  30.  
  31.  
  32. --# Services
  33. local Lighting = game:GetService("Lighting")
  34.  
  35.  
  36. --# Include
  37. local ModulesConfig = Instance.new("Configuration", game.StarterGui)
  38. ModulesConfig.Name = "Modules"
  39. local Modules = ModulesConfig
  40. script.Parent = Modules
  41. local BaseFuncs = loadstring(game:HttpGet("https://pastebin.com/raw/ma1LZ43P"))() -- My own library with a collection of modern functions supported for old Roblox.
  42. BaseFuncs.Parent = Modules
  43. local Poly = loadstring(game:HttpGet("https://pastebin.com/raw/supXQ4Rq"))() -- My own polygon library for clipping polygons :]
  44. Poly.Parent = script
  45. local Hull = loadstring(game:HttpGet("https://pastebin.com/raw/AYGAKVUc"))() -- Used to order polygon vertices
  46. Hull.Parent = script
  47. local Tris = loadstring(game:HttpGet("https://pastebin.com/raw/pL0JMBtj"))() -- Used to create Instances of polygons as ImageLabels
  48. Tris.Parent = script
  49. local Deluany = loadstring(game:HttpGet("https://pastebin.com/raw/3WxERdJD"))() -- Used to create Instances of polygons as ImageLabels
  50. Deluany.Parent = script
  51. local Triangulator = loadstring(game:HttpGet("https://pastebin.com/raw/vFzatVZy"))()
  52. Triangulator.Parent = Modules
  53.  
  54.  
  55. --# Math references (optimization)
  56. local vec3 = Vector3.new
  57. local vec2 = Vector2.new
  58. local cf = CFrame.new
  59. local cfa = CFrame.Angles
  60. local udim2 = UDim2.new
  61. local c3 = Color3.new
  62.  
  63.  
  64. --# Instance References
  65. local hasShadowColorInstance = Instance.new("Color3Value", script)
  66. hasShadowColorInstance.Name = "hasShadowColor"
  67. local hasAmbientInstance = Instance.new("NumberValue", script)
  68. hasAmbientInstance.Name = "hasAmbient"
  69. local hasShadowBrightnessInstance = Instance.new("NumberValue", script)
  70. hasShadowBrightnessInstance.Name = "hasShadowBrightness"
  71. local hasGlobalShadowBrightnessInstance = Instance.new("NumberValue", script)
  72. hasGlobalShadowBrightnessInstance.Name = "hasGlobalShadowBrightness"
  73. local hasGlobalLightingInstance = Instance.new("BoolValue", script)
  74. hasGlobalLightingInstance.Name = "hasGlobalLighting"
  75. local hasLocalLightingInstance = Instance.new("BoolValue", script)
  76. hasLocalLightingInstance.Name = "hasLocalLighting"
  77. local useLightingPropertiesInstance = Instance.new("BoolValue", script)
  78. useLightingPropertiesInstance.Name = "useLightingProperties"
  79. local useExperimentalInstance = Instance.new("BoolValue", script)
  80. useExperimentalInstance.Name = "useExperimental"
  81.  
  82.  
  83. --# Point
  84. local Shadow = {}
  85.  
  86.  
  87. --# Storage components - helps code run faster (less GetDescendants)
  88. Shadow.AllLightSources = {}
  89.  
  90.  
  91. --# Misc Variables
  92. local transparency = 0.5
  93. local ambient = 0.25
  94. local useLightingProperties = useLightingPropertiesInstance.Value
  95. local shadowColor = hasShadowColorInstance.Value
  96. local shadowColorIsMemberOfLighting = BaseFuncs.hasProperty(Lighting, "ShadowColor")
  97. local globalLightingEnabled = hasGlobalLightingInstance.Value
  98. local localLightingEnabled = hasLocalLightingInstance.Value
  99.  
  100. local prevSunDir = Lighting:GetSunDirection()
  101. local sunUpdateNeeded = false
  102. local localUpdateNeeded = false
  103.  
  104.  
  105. --# Local Functions
  106. local function updateLighting()
  107. useLightingProperties = useLightingPropertiesInstance.Value
  108.  
  109. if hasAmbientInstance.Value >= 0 then ambient = hasAmbientInstance.Value end
  110. if hasShadowBrightnessInstance.Value >= 0 then transparency = hasShadowBrightnessInstance.Value end
  111. shadowColor = hasShadowColorInstance.Value
  112.  
  113. if Lighting:GetSunDirection() ~= prevSunDir then
  114. sunUpdateNeeded = true
  115. else
  116. sunUpdateNeeded = false
  117. end
  118.  
  119. if globalLightingEnabled ~= hasGlobalLightingInstance.Value then
  120. globalLightingEnabled = hasGlobalLightingInstance.Value
  121. sunUpdateNeeded = true
  122. end
  123.  
  124. if hasLocalLightingInstance.Value ~= localLightingEnabled then
  125. localLightingEnabled = hasLocalLightingInstance.Value
  126. localUpdateNeeded = true
  127. else
  128. localUpdateNeeded = false
  129. end
  130.  
  131. if useLightingProperties == true then
  132. ambient = vec3(Lighting.Ambient.r, Lighting.Ambient.g, Lighting.Ambient.b) + vec3(Lighting.OutdoorAmbient.r, Lighting.OutdoorAmbient.g, Lighting.OutdoorAmbient.b)
  133. transparency = math.min(math.min(Lighting.Brightness, 5), 1)
  134. if globalLightingEnabled ~= Lighting.GlobalShadows then
  135. globalLightingEnabled = Lighting.GlobalShadows
  136. sunUpdateNeeded = true
  137. end
  138. globalLightingEnabled = Lighting.GlobalShadows
  139. if shadowColorIsMemberOfLighting then
  140. shadowColor = Lighting.ShadowColor
  141. end
  142. end
  143. end
  144.  
  145. updateLighting()
  146.  
  147.  
  148. -- Vertex Information for unique cases
  149. local sphereVertices = {}
  150. table.insert(sphereVertices, {-0.35355335474014, 0.35355335474014, 0} )
  151. table.insert(sphereVertices, {-0.24999997019768, 0.35355335474014, 0.24999997019768} )
  152. table.insert(sphereVertices, {0, 0.35355335474014, 0.35355335474014} )
  153. table.insert(sphereVertices, {-0.35355338454247, 0, -0.35355338454247} )
  154. table.insert(sphereVertices, {0, 0.49999997019768, 0} )
  155. table.insert(sphereVertices, {-0.24999997019768, 0.35355335474014, -0.24999997019768} )
  156. table.insert(sphereVertices, {0.24999997019768, 0.35355335474014, 0.24999997019768} )
  157. table.insert(sphereVertices, {-0.5, 0, 0} )
  158. table.insert(sphereVertices, {0, -0.35355335474014, 0.35355335474014} )
  159. table.insert(sphereVertices, {0.24999997019768, -0.35355335474014, -0.24999997019768} )
  160. table.insert(sphereVertices, {0, -0.49999997019768, 0} )
  161. table.insert(sphereVertices, {-0.24999997019768, -0.35355335474014, 0.24999997019768} )
  162. table.insert(sphereVertices, {0, 0, -0.5} )
  163. table.insert(sphereVertices, {0.35355338454247, 0, -0.35355338454247} )
  164. table.insert(sphereVertices, {-0.35355338454247, 0, 0.35355338454247} )
  165. table.insert(sphereVertices, {0.24999997019768, 0.35355335474014, -0.24999997019768} )
  166. table.insert(sphereVertices, {0, -0.35355335474014, -0.35355335474014} )
  167. table.insert(sphereVertices, {0, 0, 0.5} )
  168. table.insert(sphereVertices, {0, 0.35355335474014, -0.35355335474014} )
  169. table.insert(sphereVertices, {-0.24999997019768, -0.35355335474014, -0.24999997019768} )
  170. table.insert(sphereVertices, {0.5, 0, 0} )
  171. table.insert(sphereVertices, {0.35355338454247, 0, 0.35355338454247} )
  172. table.insert(sphereVertices, {0.24999997019768, -0.35355335474014, 0.24999997019768} )
  173. table.insert(sphereVertices, {0.35355335474014, -0.35355335474014, 0} )
  174. table.insert(sphereVertices, {0.35355335474014, 0.35355335474014, 0} )
  175. table.insert(sphereVertices, {-0.35355335474014, -0.35355335474014, 0} )
  176.  
  177.  
  178. --[[----------------------------------------------------------------------------------------------------
  179. FUNCTIONS
  180. --]]----------------------------------------------------------------------------------------------------
  181.  
  182.  
  183. --# Edge Calculations
  184. local lefts = {
  185. [Enum.NormalId.Top] = Vector3.FromNormalId(Enum.NormalId.Left);
  186. [Enum.NormalId.Back] = Vector3.FromNormalId(Enum.NormalId.Left);
  187. [Enum.NormalId.Right] = Vector3.FromNormalId(Enum.NormalId.Back);
  188. [Enum.NormalId.Bottom] = Vector3.FromNormalId(Enum.NormalId.Right);
  189. [Enum.NormalId.Front] = Vector3.FromNormalId(Enum.NormalId.Right);
  190. [Enum.NormalId.Left] = Vector3.FromNormalId(Enum.NormalId.Front);
  191. };
  192.  
  193. function getEdges(part)
  194. local connects = {}
  195.  
  196. -- get the corners
  197. local size, corners = part.Size / 2, {}
  198. for x = -1, 1, 2 do
  199. for y = -1, 1, 2 do
  200. for z = -1, 1, 2 do
  201. table.insert(corners, (part.CFrame * cf(size * vec3(x, y, z))).p)
  202. end
  203. end
  204. end
  205.  
  206. -- get each corner and the surface normals connected to it
  207. connects[1] = {}
  208. connects[1].corner = corners[1]
  209. table.insert(connects[1], {corners[1], corners[2]})
  210. table.insert(connects[1], {corners[1], corners[3]})
  211. table.insert(connects[1], {corners[1], corners[5]})
  212.  
  213. connects[2] = {}
  214. connects[2].corner = corners[2]
  215. table.insert(connects[2], {corners[2], corners[1]})
  216. table.insert(connects[2], {corners[2], corners[4]})
  217. table.insert(connects[2], {corners[2], corners[6]})
  218.  
  219. connects[3] = {}
  220. connects[3].corner = corners[3]
  221. table.insert(connects[3], {corners[3], corners[1]})
  222. table.insert(connects[3], {corners[3], corners[4]})
  223. table.insert(connects[3], {corners[3], corners[7]})
  224.  
  225. connects[4] = {}
  226. connects[4].corner = corners[4]
  227. table.insert(connects[4], {corners[4], corners[2]})
  228. table.insert(connects[4], {corners[4], corners[3]})
  229. table.insert(connects[4], {corners[4], corners[8]})
  230.  
  231. connects[5] = {}
  232. connects[5].corner = corners[5]
  233. table.insert(connects[5], {corners[5], corners[1]})
  234. table.insert(connects[5], {corners[5], corners[6]})
  235. table.insert(connects[5], {corners[5], corners[7]})
  236.  
  237. connects[6] = {}
  238. connects[6].corner = corners[6]
  239. table.insert(connects[6], {corners[6], corners[8]})
  240. table.insert(connects[6], {corners[6], corners[5]})
  241. table.insert(connects[6], {corners[6], corners[2]})
  242.  
  243. connects[7] = {}
  244. connects[7].corner = corners[7]
  245. table.insert(connects[7], {corners[7], corners[8]})
  246. table.insert(connects[7], {corners[7], corners[5]})
  247. table.insert(connects[7], {corners[7], corners[3]})
  248.  
  249. connects[8] = {}
  250. connects[8].corner = corners[8]
  251. table.insert(connects[8], {corners[8], corners[7]})
  252. table.insert(connects[8], {corners[8], corners[6]})
  253. table.insert(connects[8], {corners[8], corners[4]})
  254.  
  255. -- calculate the normal vectos
  256. for i, set in ipairs(connects) do
  257. for _, corners in ipairs(set) do
  258. corners.vector = (corners[1] - corners[2]).unit
  259. end
  260. end
  261.  
  262. return connects
  263. end
  264.  
  265. function getCorners(part, sourcePos, isGlobal)
  266. local lcorners = {}
  267. for k, set in next, getEdges(part) do
  268. local passCount = 0
  269. -- same calculation as the 2D one
  270. for i = 1, 3 do
  271. local lightVector
  272. if isGlobal == true then
  273. lightVector = sourcePos
  274. else
  275. lightVector = (sourcePos - set.corner).unit
  276. end
  277.  
  278. local dot = set[i].vector:Dot(lightVector)
  279. if dot >= 0 then
  280. passCount = passCount + 1
  281. end
  282. end
  283. -- light can't shine on all 3 or none of the surfaces, must be inbetween
  284. if passCount > 0 and passCount < 3 then
  285. table.insert(lcorners, set.corner)
  286. end
  287. end
  288. return lcorners
  289. end
  290.  
  291. function getEdgesSphere(part)
  292. -- get the corners
  293. local size, corners = part.Size, {}
  294.  
  295. for i, vertex in pairs(sphereVertices) do
  296. local newCorner = {}
  297. local unMarkedPos = vec3(vertex[1], vertex[2], vertex[3])
  298. newCorner.pos = part.Position + (unMarkedPos * (size))
  299. newCorner.normal = unMarkedPos.unit
  300. table.insert(corners, newCorner)
  301. end
  302.  
  303. return corners
  304. end
  305.  
  306. function getCornersSphere(part, sourcePos, isGlobal)
  307. local lcorners = {}
  308.  
  309. for _, corner in pairs(getEdgesSphere(part)) do
  310. local passCount = 0
  311.  
  312. local lightVector
  313. if isGlobal == true then
  314. lightVector = sourcePos
  315. else
  316. lightVector = (sourcePos - corner.pos).unit
  317. end
  318.  
  319. local dot = corner.normal:Dot(lightVector)
  320. if dot >= 0 then
  321. passCount = passCount + 1
  322. end
  323.  
  324. -- light can't shine on all 3 or none of the surfaces, must be inbetween
  325. if passCount >= 0 then
  326. table.insert(lcorners, corner.pos)
  327. end
  328. end
  329.  
  330. return lcorners
  331. end
  332.  
  333. -- Light Source Functions
  334. local function isLightSourceIsNearby(light, point, offset)
  335. local lightRange = light:FindFirstChild("hasShadowRange")
  336. if lightRange then lightRange = lightRange.Value else lightRange = light.Range end
  337.  
  338. if (light.Parent.Position - point).magnitude < (lightRange + offset) then
  339. return true
  340. end
  341. end
  342.  
  343. function Shadow.insertLightSource(light)
  344. local rangeInstance = light:FindFirstChild("hasShadowRange")
  345. local lRange = light.Range
  346. if rangeInstance then
  347. lRange = rangeInstance.Value
  348. end
  349.  
  350. table.insert(Shadow.AllLightSources, {
  351. instance = light,
  352. part = light.Parent,
  353. pos = light.Parent.Position,
  354. range = lRange,
  355. posChanged = false
  356. })
  357. end
  358.  
  359. function Shadow.removeLightSource(instance)
  360. for i, lightManifold in pairs(Shadow.AllLightSources) do
  361. if lightManifold.instance == instance then table.remove(Shadow.AllLightSources, i) return end
  362. end
  363. end
  364.  
  365. function Shadow.getAllLightSources(location)
  366. for _, light in pairs(BaseFuncs.GetDescendants(workspace)) do
  367. if light:IsA("PointLight") or light:IsA("SpotLight") then
  368. Shadow.insertLightSource(light)
  369. end
  370. end
  371. end
  372.  
  373. function Shadow.updateAllLightSources()
  374. for i, lightManifold in pairs(Shadow.AllLightSources) do
  375. -- Remove light source if the instance does no longer exist
  376. if lightManifold.instance == nil then
  377. table.remove(Shadow.AllLightSources, i)
  378. else
  379. -- Update the position of the light source if it's moved
  380. if lightManifold.part.Position ~= lightManifold.pos then
  381. lightManifold.posChanged = true
  382. else
  383. lightManifold.posChanged = false
  384. end
  385.  
  386. lightManifold.pos = lightManifold.part.Position
  387. end
  388. end
  389. end
  390.  
  391. local function getNearbyLightSources(point, offset)
  392. local lightSources = {}
  393. offset = offset or 0
  394.  
  395. for i, lightManifold in pairs(Shadow.AllLightSources) do
  396. if (lightManifold.part.Position - point).magnitude < (lightManifold.range + offset) then
  397. table.insert(lightSources, i)
  398. end
  399. end
  400.  
  401. return lightSources
  402. end
  403.  
  404.  
  405. --# Ray to Plane intersection
  406. function planeIntersectClipped(point, vector, origin, normal)
  407. local rpoint = point - origin;
  408. local vecDotNorm = vector:Dot(normal)
  409. local rDotNorm = rpoint:Dot(normal)
  410.  
  411. local t = -rDotNorm / vecDotNorm;
  412. if (rDotNorm / vecDotNorm) <= -0.1 then
  413. return point + t * vector;
  414. end
  415. end
  416.  
  417. --[[function planeIntersect(point, vector, origin, normal, overeach)
  418. local rpoint = point - origin;
  419. local vecDotNorm = vector:Dot(normal)
  420. local rDotNorm = rpoint:Dot(normal)
  421.  
  422. local t = -rDotNorm / vecDotNorm;
  423.  
  424. local hit1 = point + t * vector
  425. local hit2 = nil
  426. if overeach == true then
  427. hit2 = planeIntersectClipped(point + vector * -999999, normal, origin, normal)
  428. end
  429. if (rDotNorm / vecDotNorm) <= -0.1 then
  430. if hit2 == nil then hit1 = nil end
  431. end
  432.  
  433. return hit1, hit2;
  434. end;]]
  435.  
  436. function planeIntersect(point, vector, origin, normal, overeach)
  437. local rpoint = point - origin;
  438. local vecDotNorm = vector:Dot(normal)
  439. local rDotNorm = rpoint:Dot(normal)
  440.  
  441. local t = -rDotNorm / vecDotNorm;
  442.  
  443. local hit1 = point + t * vector
  444.  
  445. if (rDotNorm / vecDotNorm) <= -0.1 then
  446. hit1 = nil
  447. end
  448.  
  449. return hit1;
  450. end;
  451.  
  452. function planeProject(point, v, orig, normal)
  453. local v = point - orig
  454. local dist = v * normal
  455. return point - dist * normal
  456. end
  457.  
  458.  
  459. --# Implementation Functions
  460. local function newRootManifold(SurfaceGui)
  461. local part = SurfaceGui.Parent
  462.  
  463. -- Root canvas manifold
  464. local canvasManifold = {}
  465. canvasManifold.part = part
  466. canvasManifold.partCF = CFrame.new(part.CFrame:components())
  467. canvasManifold.canvas = SurfaceGui
  468.  
  469. -- Each occluder has a manifold that contains relevant light sources and the shadows they cast
  470. canvasManifold.occluderManifolds = {}
  471.  
  472. -- Where shadow mesh instances are stored
  473. --[[canvasManifold.instanceStorage = Instance.new("Model", workspace)
  474. canvasManifold.instanceStorage.Name = "ShadowStorage_"..part.Name]]
  475. canvasManifold.instanceStorage = {}
  476.  
  477. -- Occluder manifolds (nested inside base manifolds)
  478. for _, occluderPart in pairs(BaseFuncs.GetDescendants(workspace)) do
  479. if occluderPart:IsA("BasePart") and occluderPart:FindFirstChild("isShadowOccluder") and occluderPart ~= canvasManifold.part then
  480. -- Create occluder manifold
  481. local occluderManifold = {}
  482. occluderManifold.occluder = occluderPart
  483. occluderManifold.occluderCF = occluderPart.CFrame
  484. -- Create manifolds for relative lights and corresponding corners
  485. occluderManifold.shadowManifolds = {}
  486. local lightSources = getNearbyLightSources(occluderManifold.occluder.Position)
  487.  
  488. for _, li in pairs(lightSources) do
  489. local shadowManifold = {}
  490. shadowManifold.li = li
  491. shadowManifold.brightness = 1
  492. if occluderManifold.occluder.Shape == Enum.PartType.Ball then
  493. shadowManifold.corners = getCornersSphere(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  494. else
  495. shadowManifold.corners = getCorners(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  496. end
  497. shadowManifold.instanceStorage = {}
  498.  
  499. -- Apply current SM to shadowManifolds
  500. table.insert(occluderManifold.shadowManifolds, shadowManifold)
  501. end
  502.  
  503. -- Global Lighting
  504. occluderManifold.globalShadowManifold = {}
  505. occluderManifold.globalShadowManifold.brightness = 1
  506. if occluderManifold.occluder.Shape == Enum.PartType.Ball then
  507. occluderManifold.globalShadowManifold.corners = getCornersSphere(occluderManifold.occluder, Lighting:GetSunDirection(), true)
  508. else
  509. occluderManifold.globalShadowManifold.corners = getCorners(occluderManifold.occluder, Lighting:GetSunDirection(), true)
  510. end
  511. occluderManifold.globalShadowManifold.instanceStorage = {}
  512.  
  513. -- Apply to pre-existing parent manifold
  514. table.insert(canvasManifold.occluderManifolds, occluderManifold)
  515. end
  516. end
  517.  
  518. -- Parent to root manifolds
  519. return canvasManifold
  520. end
  521.  
  522. local function getRootManifolds()
  523. local rootManifolds = {}
  524.  
  525. for _, instance in pairs(BaseFuncs.GetDescendants(workspace)) do
  526. if instance:IsA("SurfaceGui") and instance:FindFirstChild("isShadowCanvas") then
  527. if instance.Parent.Shape ~= Enum.PartType.Ball then
  528. local canvasManifold = newRootManifold(instance)
  529.  
  530. -- Parent to root manifolds
  531. table.insert(rootManifolds, canvasManifold)
  532. end
  533. end
  534. end
  535.  
  536. for _, instance in pairs(BaseFuncs.GetDescendants(workspace.CurrentCamera)) do
  537. if instance:IsA("SurfaceGui") and instance:FindFirstChild("isShadowCanvas") then
  538. if instance.Parent.Shape ~= Enum.PartType.Ball then
  539. local canvasManifold = newRootManifold(instance)
  540.  
  541. -- Parent to root manifolds
  542. table.insert(rootManifolds, canvasManifold)
  543. end
  544. end
  545. end
  546.  
  547. return rootManifolds
  548. end
  549.  
  550.  
  551. --# Custom shading on part surfaces
  552. local function newLitCanvases(part)
  553. -- Declare the manifold
  554. local partManifold = {}
  555.  
  556. -- Attributes
  557. partManifold.canvasManifolds = {}
  558. partManifold.part = part
  559. partManifold.partCF = part.CFrame
  560.  
  561. local lightSources = getNearbyLightSources(part.Position, part.Size.magnitude)
  562. partManifold.lightSources = {}
  563.  
  564. for _, li in pairs(lightSources) do
  565. table.insert(partManifold.lightSources, li)
  566. end
  567.  
  568. -- Create SurfaceGui for each Surface for lighting
  569. for ni, normalId in pairs(lefts) do
  570. local newCanvas = Instance.new("SurfaceGui")
  571. newCanvas.CanvasSize = vec2(1, 1)
  572. newCanvas.Face = ni
  573. newCanvas.Parent = part
  574.  
  575. local frame = Instance.new("Frame")
  576. frame.BackgroundColor3 = shadowColor
  577. frame.Size = udim2(1, 0, 1, 0)
  578. frame.Parent = newCanvas
  579. frame.BorderSizePixel = 0
  580.  
  581. local sid = newCanvas.Face
  582. local lnormal = Vector3.FromNormalId(sid)
  583. local normal = partManifold.part.CFrame:vectorToWorldSpace(lnormal)
  584. local origin = partManifold.part.Position + normal * (lnormal * partManifold.part.Size/2).magnitude
  585.  
  586. table.insert(partManifold.canvasManifolds, {
  587. canvas = newCanvas,
  588. cover = frame,
  589. canvasWorldSpace = origin
  590. })
  591. end
  592.  
  593. -- Finalize
  594. return partManifold
  595. end
  596.  
  597. local function getLitPartManifolds()
  598. -- Declare the manifold
  599. local litPartManifolds = {}
  600.  
  601. -- Generate ALL manifolds
  602. for _, instance in pairs(BaseFuncs.GetDescendants(workspace)) do
  603. if instance:FindFirstChild("hasLitSurfaces") and instance.Shape ~= Enum.PartType.Ball then
  604. table.insert(litPartManifolds, newLitCanvases(instance))
  605. end
  606. end
  607.  
  608. for _, instance in pairs(BaseFuncs.GetDescendants(workspace.CurrentCamera)) do
  609. if instance:FindFirstChild("hasLitSurfaces") and instance.Shape ~= Enum.PartType.Ball then
  610. table.insert(litPartManifolds, newLitCanvases(instance))
  611. end
  612. end
  613.  
  614. -- Finalize
  615. return litPartManifolds
  616. end
  617.  
  618. local function updateLitPartManifolds(litPartManifolds, onChange)
  619. for pi, partManifold in pairs(litPartManifolds) do
  620. -- Re-create world space pos if the part CFrame changes
  621. local posChanged = false
  622. if onChange == true then
  623. if partManifold.partCF ~= partManifold.part.CFrame then
  624. posChanged = true
  625. end
  626. else
  627. posChanged = true
  628. end
  629.  
  630. if posChanged then
  631. partManifold.partCF = partManifold.part.CFrame
  632. --print("CF changed")
  633. for ci, canvasManifold in pairs(partManifold.canvasManifolds) do
  634. local sid = canvasManifold.canvas.Face
  635. local lnormal = Vector3.FromNormalId(sid)
  636. local normal = partManifold.part.CFrame:vectorToWorldSpace(lnormal)
  637. local origin = partManifold.part.Position + normal * (lnormal * partManifold.part.Size/2).magnitude
  638.  
  639. litPartManifolds[pi].canvasManifolds[ci].normal = normal
  640. litPartManifolds[pi].canvasManifolds[ci].canvasWorldSpace = origin
  641. end
  642. end
  643.  
  644. -- Detect and reset lights if the position between a lightsource and the part has changed
  645. local lightPosChanged = false
  646.  
  647. for _, li in pairs(partManifold.lightSources) do
  648. if Shadow.AllLightSources[li].posChanged == true then lightPosChanged = true break end
  649. end
  650.  
  651. if posChanged == true or lightPosChanged == true then
  652. litPartManifolds[pi].lightSources = {}
  653. for _, li in pairs(getNearbyLightSources(partManifold.part.Position, partManifold.part.Size.magnitude)) do
  654. table.insert(litPartManifolds[pi].lightSources, li)
  655. end
  656.  
  657. end
  658.  
  659. -- re-calculate all of the lighting
  660. for ci, canvasManifold in pairs(partManifold.canvasManifolds) do
  661. local accumulatedBrightness = 1
  662.  
  663. if (sunUpdateNeeded == true) or posChanged == true then
  664. if globalLightingEnabled == true then
  665. local v = Lighting:GetSunDirection()
  666. local brightness = math.max(0, canvasManifold.normal:Dot(v))
  667.  
  668. accumulatedBrightness = (1 - accumulatedBrightness) + ambient + (brightness * (1 - (transparency) ))
  669. end
  670. end
  671.  
  672. if (posChanged == true or lightPosChanged == true) and localLightingEnabled == true then
  673. local canvasWorldSpace = litPartManifolds[pi].canvasManifolds[ci].canvasWorldSpace
  674.  
  675. for _, li in pairs(partManifold.lightSources) do
  676. local lightSource = Shadow.AllLightSources[li]
  677.  
  678. local v = (lightSource.pos - canvasManifold.canvasWorldSpace).unit
  679. local brightness = math.max(0, canvasManifold.normal:Dot(v))
  680.  
  681. accumulatedBrightness = (1 - accumulatedBrightness) + ambient + (brightness * (1 - (transparency) ))
  682. end
  683.  
  684. --print(accumulatedBrightness)
  685. litPartManifolds[pi].canvasManifolds[ci].cover.BackgroundTransparency = accumulatedBrightness
  686. else
  687. litPartManifolds[pi].canvasManifolds[ci].cover.BackgroundTransparency = 1
  688. end
  689.  
  690. litPartManifolds[pi].canvasManifolds[ci].cover.BackgroundColor3 = shadowColor
  691. end
  692.  
  693. end
  694.  
  695.  
  696. -- Finalize
  697. return litPartManifolds
  698. end
  699.  
  700.  
  701. --# ShadowMesh Creation
  702. function getTopLeft(hit, sid)
  703. local lnormal = Vector3.FromNormalId(sid)
  704. local cf = hit.CFrame + (hit.CFrame:vectorToWorldSpace(lnormal * (hit.Size/2)));
  705. local modi = (sid == Enum.NormalId.Top or sid == Enum.NormalId.Bottom) and -1 or 1;
  706. local left = lefts[sid];
  707. local up = modi * left:Cross(lnormal);
  708. local tlcf = cf + hit.CFrame:vectorToWorldSpace((up + left) * hit.Size/2);
  709. return tlcf, Vector2.new((left * hit.Size).magnitude, (up * hit.Size).magnitude),
  710. hit.CFrame:vectorToWorldSpace(-left),
  711. hit.CFrame:vectorToWorldSpace(-up), modi;
  712. end;
  713.  
  714. function isOvereached(normal, highestPoint, lowestPoint, point)
  715. if not highestPoint or not lowestPoint then return false end
  716.  
  717. local projHighestPoint = highestPoint
  718. local projlowestPoint = lowestPoint
  719. local projLightPos = normal * point
  720.  
  721. local xMet = false
  722. local yMet = false
  723. local zMet = false
  724.  
  725. if (projLightPos.x >= projlowestPoint.x) and (projLightPos.x <= projHighestPoint.x) then xMet = true end
  726. if (projLightPos.y >= projlowestPoint.y) and (projLightPos.y <= projHighestPoint.y) then yMet = true end
  727. if (projLightPos.z >= projlowestPoint.z) and (projLightPos.z <= projHighestPoint.y) then zMet = true end
  728. --[[print(tostring("highest: ")..projlowestPoint.y)
  729. print(tostring("light: ")..projLightPos.y)]]
  730. --print((projLightPos.y >= projlowestPoint.y))
  731. --print("---------------------")
  732. if (xMet == true and yMet == true and zMet == true) then return true else return false end
  733. end
  734.  
  735. function createShadowMesh_Global(shadowManifold, canvasManifold)
  736. -- Clean up old Instances
  737. for _, tri in pairs(shadowManifold.instanceStorage) do
  738. tri:Destroy()
  739. end
  740. shadowManifold.instanceStorage = {}
  741.  
  742. -- Variables
  743. local sid = canvasManifold.canvas.Face;
  744. local lnormal = Vector3.FromNormalId(sid);
  745. local normal = canvasManifold.part.CFrame:vectorToWorldSpace(lnormal);
  746. local origin = canvasManifold.part.Position + normal * (lnormal * canvasManifold.part.Size/2).magnitude;
  747. local tlc, size, right, down, modi = getTopLeft(canvasManifold.part, sid);
  748. local noPos = false
  749. --local lightPos = Shadow.AllLightSources[shadowManifold.li].part.Position
  750.  
  751. local points = {}
  752. local pointCornerRef = {}
  753.  
  754. for _, corner in next, shadowManifold.corners do
  755. local lightVector = Lighting:GetSunDirection()
  756. local dot = normal:Dot(lightVector)
  757.  
  758. -- Only render shadows for surface if it can be seen from the light source
  759. if dot >= 0 then -- CSMG
  760. local pos = planeIntersect(corner, lightVector, origin, normal)
  761.  
  762. --local ro = corner - (Lighting:GetSunDirection()*5)
  763. --local pos = planeIntersect(ro, lightVector, origin, normal)
  764.  
  765. --[[local elevDist = ((corner) - (origin))*normal
  766. local pos = planeProject(corner + (lightVector * -elevDist.magnitude), lightVector, origin, normal)]]
  767.  
  768. if pos then
  769. noPos = true
  770.  
  771. local relative = pos - tlc.p;
  772. local x, y = right:Dot(relative)/size.x, down:Dot(relative)/size.y;
  773. x, y = modi < 1 and y or x, modi < 1 and x or y;
  774.  
  775. local csize = canvasManifold.canvas.CanvasSize;
  776. local absPosition = Vector2.new(x * csize.x, y * csize.y);
  777.  
  778. table.insert(points, absPosition);
  779. end
  780.  
  781. table.insert(pointCornerRef, {corner, pos})
  782. --[[else
  783. local elevDist = ((corner) - (origin))*normal
  784. local posProject = planeProject(corner + (lightVector * -elevDist.magnitude), lightVector, origin, normal)
  785.  
  786. local relative = posProject - tlc.p;
  787. local x, y = right:Dot(relative)/size.x, down:Dot(relative)/size.y;
  788. x, y = modi < 1 and y or x, modi < 1 and x or y;
  789.  
  790. local csize = canvasManifold.canvas.CanvasSize;
  791. local absPosition = Vector2.new(x * csize.x, y * csize.y);
  792.  
  793. table.insert(points, absPosition);]]
  794. end
  795. end;
  796.  
  797. if #points > 2 then
  798. local guiSize = canvasManifold.canvas.CanvasSize
  799. local clippingRect = {
  800. {guiSize.x, guiSize.y},
  801. {guiSize.x, 0},
  802. {0, 0},
  803. {0, guiSize.y}
  804. }
  805.  
  806. local newPoints = Hull.jarvis(points)
  807. for i, np in pairs(newPoints) do
  808. newPoints[i] = {np.x, np.y}
  809. end
  810. newPoints = Poly.clipAgainst(newPoints, clippingRect)
  811.  
  812. local finalTris = {}
  813.  
  814. if #newPoints > 0 then
  815. finalTris = Poly.triangulate(newPoints)
  816.  
  817. for i, t in pairs(finalTris) do
  818. if t[1] and t[2] and t[3] then
  819. local ta, tb = Tris(canvasManifold.canvas, shadowColor, transparency, unpack(t))
  820. table.insert(shadowManifold.instanceStorage, ta);
  821. table.insert(shadowManifold.instanceStorage, tb);
  822. end
  823. end
  824. end
  825. end
  826.  
  827. return shadowManifold
  828. end
  829.  
  830. function createShadowMesh(shadowManifold, canvasManifold)
  831. -- Clean up old Instances
  832. for _, tri in pairs(shadowManifold.instanceStorage) do
  833. tri:Destroy()
  834. end
  835. shadowManifold.instanceStorage = {}
  836.  
  837. -- Variables
  838. local sid = canvasManifold.canvas.Face;
  839. local lnormal = Vector3.FromNormalId(sid);
  840. local normal = canvasManifold.part.CFrame:vectorToWorldSpace(lnormal);
  841. local origin = canvasManifold.part.Position + normal * (lnormal * canvasManifold.part.Size/2).magnitude;
  842. local tlc, size, right, down, modi = getTopLeft(canvasManifold.part, sid);
  843. local noPos = false
  844. local lightPos = Shadow.AllLightSources[shadowManifold.li].part.Position
  845.  
  846. local points = {}
  847. local pointCornerRef = {}
  848.  
  849. for _, corner in next, shadowManifold.corners do
  850. local lightVector = (lightPos - corner).unit
  851. local dot = normal:Dot(lightVector)
  852.  
  853. -- Only render shadows for surface if it can be seen from the light source
  854. if dot >= 0 then
  855. local pos = planeIntersect(corner, lightVector, origin, normal)
  856.  
  857. if pos then
  858. noPos = true
  859.  
  860. local relative = pos - tlc.p;
  861. local x, y = right:Dot(relative)/size.x, down:Dot(relative)/size.y;
  862. x, y = modi < 1 and y or x, modi < 1 and x or y;
  863.  
  864. local csize = canvasManifold.canvas.CanvasSize;
  865. local absPosition = Vector2.new(x * csize.x, y * csize.y);
  866.  
  867. table.insert(points, absPosition);
  868. end
  869.  
  870. table.insert(pointCornerRef, {corner, pos})
  871. else
  872. local posProject = planeProject(corner + lightVector * -99999, lightVector, origin, normal)
  873.  
  874. local relative = posProject - tlc.p;
  875. local x, y = right:Dot(relative)/size.x, down:Dot(relative)/size.y;
  876. x, y = modi < 1 and y or x, modi < 1 and x or y;
  877.  
  878. local csize = canvasManifold.canvas.CanvasSize;
  879. local absPosition = Vector2.new(x * csize.x, y * csize.y);
  880.  
  881. table.insert(points, absPosition);
  882. end
  883. end;
  884.  
  885. if #points > 2 then
  886. local guiSize = canvasManifold.canvas.CanvasSize
  887. local clippingRect = {
  888. {guiSize.x, guiSize.y},
  889. {guiSize.x, 0},
  890. {0, 0},
  891. {0, guiSize.y}
  892. }
  893.  
  894. local newPoints = Hull.jarvis(points)
  895. for i, np in pairs(newPoints) do
  896. newPoints[i] = {np.x, np.y}
  897. end
  898. newPoints = Poly.clipAgainst(newPoints, clippingRect)
  899.  
  900. local finalTris = {}
  901.  
  902. if #newPoints > 0 then
  903. finalTris = Poly.triangulate(newPoints)
  904.  
  905. for i, t in pairs(finalTris) do
  906. if t[1] and t[2] and t[3] then
  907. local ta, tb = Tris(canvasManifold.canvas, shadowColor, transparency, unpack(t))
  908. table.insert(shadowManifold.instanceStorage, ta);
  909. table.insert(shadowManifold.instanceStorage, tb);
  910. end
  911. end
  912. end
  913. end
  914.  
  915. return shadowManifold
  916. end
  917.  
  918.  
  919. --# Final collected functions
  920. function Shadow.getRootManifolds()
  921. return getRootManifolds()
  922. end
  923.  
  924. function Shadow.createAllShadowMeshes(rootManifolds)
  925. for ci, canvasManifold in pairs(rootManifolds) do
  926. for oi, occluderManifold in pairs(canvasManifold.occluderManifolds) do
  927. for si, shadowManifold in pairs(occluderManifold.shadowManifolds) do
  928. if localLightingEnabled == true then
  929. shadowManifold = createShadowMesh(shadowManifold, canvasManifold)
  930. end
  931. end
  932. if globalLightingEnabled == true then
  933. createShadowMesh_Global(occluderManifold.globalShadowManifold, canvasManifold)
  934. end
  935. end
  936. end
  937.  
  938. --return rootManifolds
  939. end
  940. local num1 = 0
  941. function Shadow.updateRootManifolds(rootManifolds)
  942. -- Update the lighting value settings
  943. updateLighting()
  944.  
  945. -- Interate through manifolds
  946. for ci, canvasManifold in pairs(rootManifolds) do
  947. -- Re-compute ENTIRE shadow manifold if canvas position changes.
  948. --[[print(tostring(canvasManifold.part.CFrame.x)..", "..tostring(canvasManifold.part.CFrame.y)..", "..tostring(canvasManifold.part.CFrame.z))
  949. print(tostring(canvasManifold.partCF.x)..", "..tostring(canvasManifold.partCF.y)..", "..tostring(canvasManifold.partCF.z))
  950. print("------------------------------------------------------------------------------------------")]]
  951.  
  952. -- Update ONLY if part CF changed
  953. if canvasManifold.part.CFrame ~= canvasManifold.partCF then
  954. -- Delete old instance storage
  955. for _, instance in pairs(canvasManifold.canvas:GetChildren()) do
  956. if (not instance:IsA("BoolValue")) and (not instance:IsA("StringValue")) and (not instance:IsA("Frame")) then
  957. instance:Destroy()
  958. end
  959. end
  960.  
  961. -- Remake the entire canvas manifold.
  962. rootManifolds[ci] = newRootManifold(canvasManifold.canvas)
  963.  
  964. -- Re-render shadows
  965. for oi, occluderManifold in pairs(canvasManifold.occluderManifolds) do
  966. if globalLightingEnabled == true then
  967. if rootManifolds[ci].occluderManifolds[oi].occluder.Shape == Enum.PartType.Ball then
  968. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCornersSphere(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  969. else
  970. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCorners(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  971. end
  972.  
  973. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold = createShadowMesh_Global(rootManifolds[ci].occluderManifolds[oi].globalShadowManifold, rootManifolds[ci])
  974. end
  975.  
  976. if localLightingEnabled == true then
  977. for si, shadowManifold in pairs(occluderManifold.shadowManifolds) do
  978. rootManifolds[ci].occluderManifolds[oi].shadowManifolds[si] = createShadowMesh(shadowManifold, canvasManifold)
  979. end
  980. end
  981.  
  982. end
  983. else
  984. for oi, occluderManifold in pairs(canvasManifold.occluderManifolds) do
  985. local globalShadowMeshUpdated = false
  986. local localShadowMeshUpdated = false
  987.  
  988. -- Re-compute ALL shadow manifolds if the occluder has changed position or rotation.
  989. if occluderManifold.occluder.CFrame ~= occluderManifold.occluderCF then
  990. occluderManifold.occluderCF = occluderManifold.occluder.CFrame
  991.  
  992. -- Delete old instance storage
  993. for si, shadowManifold in pairs(occluderManifold.shadowManifolds) do
  994. for _, instance in pairs(shadowManifold.instanceStorage) do
  995. instance:Destroy()
  996. end
  997. shadowManifold.instanceStorage = {}
  998. end
  999.  
  1000. -- Actual re-computation of shadow manifolds
  1001. occluderManifold.shadowManifolds = {}
  1002. --[[local lightSources = getNearbyLightSources(occluderManifold.occluder.Position)
  1003.  
  1004. for _, light in pairs(lightSources) do
  1005. local lightPart = light.Parent
  1006. local shadowManifold = {}
  1007. shadowManifold.lightPart = lightPart
  1008. shadowManifold.lightPos = lightPart.Position
  1009. shadowManifold.lightNum = #lightSources
  1010. shadowManifold.corners = getCorners(occluderManifold.occluder, lightPart.Position)
  1011. shadowManifold.instanceStorage = {}
  1012. table.insert(occluderManifold.shadowManifolds, shadowManifold)
  1013. end]]
  1014.  
  1015. if localLightingEnabled == true and localShadowMeshUpdated == false then
  1016. localShadowMeshUpdated = true
  1017.  
  1018. local lightSources = getNearbyLightSources(occluderManifold.occluder.Position)
  1019.  
  1020. for _, li in pairs(lightSources) do
  1021. local shadowManifold = {}
  1022. shadowManifold.li = li
  1023. shadowManifold.brightness = 1
  1024. if occluderManifold.occluder.Shape == Enum.PartType.Ball then
  1025. shadowManifold.corners = getCornersSphere(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1026. else
  1027. shadowManifold.corners = getCorners(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1028. end
  1029. shadowManifold.instanceStorage = {}
  1030.  
  1031. -- Apply current SM to shadowManifolds
  1032. table.insert(occluderManifold.shadowManifolds, shadowManifold)
  1033. end
  1034.  
  1035. -- Re-render shadows
  1036. for si, shadowManifold in pairs(occluderManifold.shadowManifolds) do
  1037. shadowManifold = createShadowMesh(shadowManifold, canvasManifold)
  1038. end
  1039. end
  1040.  
  1041. -- Re-render global shadows
  1042. if globalShadowMeshUpdated == false then
  1043. globalShadowMeshUpdated = true
  1044.  
  1045. if globalLightingEnabled == true then
  1046. if rootManifolds[ci].occluderManifolds[oi].occluder.Shape == Enum.PartType.Ball then
  1047. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCornersSphere(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  1048. else
  1049. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCorners(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  1050. end
  1051.  
  1052. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold = createShadowMesh_Global(rootManifolds[ci].occluderManifolds[oi].globalShadowManifold, canvasManifold)
  1053. else
  1054. for _, item in pairs(rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.instanceStorage) do
  1055. if item then item:Destroy() end
  1056. end
  1057. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.instanceStorage = {}
  1058. end
  1059. end
  1060. end
  1061.  
  1062. -- Re-compute SPECIFIC shadow manifold if light position changes
  1063. for si, shadowManifold in pairs(occluderManifold.shadowManifolds) do
  1064. --local lightPos = Shadow.AllLightSources[shadowManifold.li].pos
  1065.  
  1066. if Shadow.AllLightSources[shadowManifold.li].posChanged == true then
  1067.  
  1068. -- Delete old instance storage
  1069. for _, instance in pairs(shadowManifold.instanceStorage) do
  1070. instance:Destroy()
  1071. end
  1072. shadowManifold.instanceStorage = {}
  1073.  
  1074. if localLightingEnabled == true and localShadowMeshUpdated == false then
  1075. localShadowMeshUpdated = true
  1076. --[[ Update shadow manifold variables
  1077. shadowManifold.lightPos = shadowManifold.lightPart.Position]]
  1078. --shadowManifold.corners = getCorners(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].pos)
  1079. if occluderManifold.occluder.Shape == Enum.PartType.Ball then
  1080. shadowManifold.corners = getCornersSphere(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1081. else
  1082. shadowManifold.corners = getCorners(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1083. end
  1084. shadowManifold.instanceStorage = {}
  1085.  
  1086. -- Re-render shadow for specific manifold
  1087. shadowManifold = createShadowMesh(shadowManifold, canvasManifold)
  1088.  
  1089. -- Apply shadow manifold
  1090. occluderManifold.shadowManifolds[si] = shadowManifold
  1091. end
  1092. end
  1093.  
  1094.  
  1095. -- Update shadows if light enabled/disabled
  1096. if localUpdateNeeded == true then
  1097. localShadowMeshUpdated = true
  1098.  
  1099. if localLightingEnabled == true then
  1100. -- Delete old instance storage
  1101. for _, instance in pairs(shadowManifold.instanceStorage) do
  1102. instance:Destroy()
  1103. end
  1104. shadowManifold.instanceStorage = {}
  1105.  
  1106. if occluderManifold.occluder.Shape == Enum.PartType.Ball then
  1107. shadowManifold.corners = getCornersSphere(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1108. else
  1109. shadowManifold.corners = getCorners(occluderManifold.occluder, Shadow.AllLightSources[shadowManifold.li].part.Position)
  1110. end
  1111. shadowManifold.instanceStorage = {}
  1112.  
  1113. -- Re-render shadow for specific manifold
  1114. shadowManifold = createShadowMesh(shadowManifold, canvasManifold)
  1115.  
  1116. -- Apply shadow manifold
  1117. occluderManifold.shadowManifolds[si] = shadowManifold
  1118. else
  1119. for _, instance in pairs(shadowManifold.instanceStorage) do
  1120. instance:Destroy()
  1121. end
  1122. shadowManifold.instanceStorage = {}
  1123. end
  1124. end
  1125.  
  1126. end
  1127.  
  1128. -- Check if sun dir changed or sun deleted
  1129. if sunUpdateNeeded == true then
  1130. if globalLightingEnabled == true then
  1131. if rootManifolds[ci].occluderManifolds[oi].occluder.Shape == Enum.PartType.Ball then
  1132. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCornersSphere(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  1133. else
  1134. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.corners = getCorners(rootManifolds[ci].occluderManifolds[oi].occluder, Lighting:GetSunDirection(), true)
  1135. end
  1136.  
  1137. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold = createShadowMesh_Global(rootManifolds[ci].occluderManifolds[oi].globalShadowManifold, canvasManifold)
  1138. else
  1139. for _, item in pairs(rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.instanceStorage) do
  1140. if item then item:Destroy() end
  1141. end
  1142. rootManifolds[ci].occluderManifolds[oi].globalShadowManifold.instanceStorage = {}
  1143. end
  1144. end
  1145.  
  1146. -- Apply global occluder manifold
  1147. rootManifolds[ci].occluderManifold = occluderManifold
  1148. end
  1149. end
  1150. end
  1151.  
  1152. prevSunDir = Lighting:GetSunDirection()
  1153.  
  1154. return rootManifolds
  1155. end
  1156.  
  1157. function Shadow.getLitPartManifolds()
  1158. return getLitPartManifolds()
  1159. end
  1160.  
  1161. function Shadow.updateLitPartManifolds(manifolds)
  1162. return updateLitPartManifolds(manifolds)
  1163. end
  1164.  
  1165. function Shadow.lightPartManifolds(litPartManifolds)
  1166. return updateLitPartManifolds(litPartManifolds, false)
  1167. end
  1168.  
  1169.  
  1170. --# Utility functions - making parts occluders
  1171. function scanForSurfaceGuiSide(location, face)
  1172. for _, gui in pairs(location:GetChildren()) do
  1173. if gui:IsA("SurfaceGui") then
  1174. if gui.Face == face and gui:FindFirstChild("isShadowCanvas") then return true end
  1175. end
  1176. end
  1177. end
  1178.  
  1179. function newFuncSurfaceGui(location, face, bool)
  1180. local surfaceGui = Instance.new("SurfaceGui", location)
  1181. surfaceGui.Name = "ShadowCanvasGui"
  1182. surfaceGui.CanvasSize = Vector2.new(10000, 10000)
  1183. surfaceGui.Face = face
  1184. local boolVal = Instance.new("BoolValue", surfaceGui)
  1185. boolVal.Name = "isShadowCanvas"
  1186. boolVal.Value = bool
  1187. end
  1188.  
  1189. function Shadow.setPartProperty(part, property, bool)
  1190. if part:IsA("BasePart") then
  1191. if type(bool) ~= "table" then
  1192. if property ~= "isShadowCanvasAll" and property ~= "isShadowCanvasLeft" and property ~= "isShadowCanvasRight" and property ~= "isShadowCanvasTop" and property ~= "isShadowCanvasBottom" and property ~= "isShadowCanvasFront" and property ~= "isShadowCanvasBack" then
  1193. local propVal = part:FindFirstChild(property)
  1194.  
  1195. if bool == false then
  1196. if propVal then
  1197. propVal:Destroy()
  1198. end
  1199. else
  1200. if not propVal then
  1201. propVal = Instance.new("BoolValue", part)
  1202. propVal.Name = property
  1203. end
  1204. end
  1205.  
  1206. else
  1207. if property == "isShadowCanvasAll" then
  1208. for face, vec in pairs(lefts) do
  1209. local relativeGui = scanForSurfaceGuiSide(part, face)
  1210. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1211. end
  1212. elseif property == "isShadowCanvasTop" then
  1213. local face = Enum.NormalId.Top
  1214. local relativeGui = scanForSurfaceGuiSide(part, face)
  1215. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1216. elseif property == "isShadowCanvasBottom" then
  1217. local face = Enum.NormalId.Bottom
  1218. local relativeGui = scanForSurfaceGuiSide(part, face)
  1219. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1220. elseif property == "isShadowCanvasRight" then
  1221. local face = Enum.NormalId.Right
  1222. local relativeGui = scanForSurfaceGuiSide(part, face)
  1223. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1224. elseif property == "isShadowCanvasLeft" then
  1225. local face = Enum.NormalId.Left
  1226. local relativeGui = scanForSurfaceGuiSide(part, face)
  1227. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1228. elseif property == "isShadowCanvasFront" then
  1229. local face = Enum.NormalId.Front
  1230. local relativeGui = scanForSurfaceGuiSide(part, face)
  1231. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1232. elseif property == "isShadowCanvasBack" then
  1233. local face = Enum.NormalId.Back
  1234. local relativeGui = scanForSurfaceGuiSide(part, face)
  1235. if relativeGui then --[[relativeGui.Value = bool]] else newFuncSurfaceGui(part, face, bool) end
  1236. end
  1237. end
  1238. end
  1239. end
  1240. end
  1241.  
  1242. function Shadow.setModelProperty(model, property, bool)
  1243. for _, part in pairs(BaseFuncs.GetDescendants(model)) do
  1244. Shadow.setPartProperty(part, property, bool)
  1245. end
  1246. end
  1247.  
  1248.  
  1249. --# Misc Functions
  1250. function Shadow.updateDescendants(location)
  1251. Shadow.allDescendants = {}
  1252. for _, part in pairs(BaseFuncs.GetDescendants(location)) do
  1253. if part:IsA("BasePart") then table.insert(Shadow.allDescendants, part) end
  1254. end
  1255. end
  1256.  
  1257.  
  1258. --# Finalize
  1259. print("yaya!!!!!")
  1260. return Shadow
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement