SkyTheCoder

ShadowMap.lua

May 6th, 2015
223
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. --# Main
  3. -- ShadowMap
  4.  
  5. displayMode(FULLSCREEN)
  6.  
  7. function setup()
  8.     scene = {main = {}, depth = {}}
  9.    
  10.     boxA, boxAdepth = box(0, -4, 0, 8)
  11.     boxA.texture = readImage("Cargo Bot:Crate Yellow 2")
  12.     boxA:setColors(color(255, 255))
  13.     table.insert(scene.main, boxA)
  14.     table.insert(scene.depth, boxAdepth)
  15.    
  16.     local numBoxes = 10 -- The number of boxes to fly around the scene
  17.    
  18.     for i = 1, numBoxes do
  19.         math.randomseed(i)
  20.         boxB, boxBdepth = box(0, 0, 0, 1)--box(math.random(-5, 5), math.random(0, 5), math.random(-5, 5), 0.5)
  21.         boxB.texture = readImage("Cargo Bot:Crate Red 2")
  22.         boxB:setColors(color(255, 255))
  23.         table.insert(scene.main, boxB)
  24.         table.insert(scene.depth, boxBdepth)
  25.     end
  26.    
  27.     local s = 1024 -- The size of the shadowmap (512, 1024, or 2048 offer good FPS, but you can go up to 4096)
  28.    
  29.     depth = image(s / ContentScaleFactor, s / ContentScaleFactor)
  30.    
  31.     light = vec3(5, 5, 5)
  32.    
  33.     lightm = mesh() -- A cube to show where the light is
  34.     lightm.vertices = Primitive:Cube(0.5, 0.5, 0.5, light.x, light.y, light.z)
  35.     lightm:setColors(color(0))
  36.    
  37.     pos = vec3(0, 1, 0) -- Variables to handle camera movement and direction
  38.     ang = vec2(0, 1)
  39.     ang2 = vec2(1, -1):normalize()
  40.     tpos = vec3(pos.x, pos.y, pos.z)
  41.     tang = vec2(ang.x, ang.y)
  42.     tang2 = vec2(ang2.x, ang2.y)
  43.    
  44.     mId = 0
  45.     lId = 0
  46. end
  47.  
  48. function move(k) -- Basic function to move and rotate the cubes to show off the shadowmaps
  49.     if k > 1 then
  50.         math.randomseed(k - 1)
  51.         translate(math.random(-5, 5), math.random(0, 5), math.random(-5, 5))
  52.         local dist = 4
  53.         local rot = 360
  54.         local speed = 0.25
  55.         translate(noise(ElapsedTime * speed + k, 0, k * 16) * dist, noise(ElapsedTime * speed + k, 16, k * 16) * dist, noise(ElapsedTime * speed + k, 32, k * 16) * dist)
  56.         rotate(noise(ElapsedTime * speed + k, 48, k * 16) * rot, 1, 0, 0)
  57.         rotate(noise(ElapsedTime * speed + k, 64, k * 16) * rot, 0, 1, 0)
  58.         rotate(noise(ElapsedTime * speed + k, 80, k * 16) * rot, 0, 0, 1)
  59.     end
  60. end
  61.  
  62. function draw()
  63.     background(178, 211, 223, 255)
  64.    
  65.     local pmix = 0.0375 -- Smoothes the camera movement
  66.     pos.x = pos.x * (1 - pmix) + tpos.x * pmix
  67.     pos.y = pos.y * (1 - pmix) + tpos.y * pmix
  68.     pos.z = pos.z * (1 - pmix) + tpos.z * pmix
  69.     local amix = 0.1
  70.     ang.x = ang.x * (1 - amix) + tang.x * amix
  71.     ang.y = ang.y * (1 - amix) + tang.y * amix
  72.     ang2.x = ang2.x * (1 - amix) + tang2.x * amix
  73.     ang2.y = ang2.y * (1 - amix) + tang2.y * amix
  74.    
  75.     setContext(depth, true) -- Drawing into the depth map
  76.     background(255, 255)
  77.     camera(light.x, light.y, light.z, 0, 0, 0, 0, 1, 0)
  78.     perspective(150, depth.width / depth.height, 0.001, 65536)
  79.    
  80.     local lightModelViewProjection = modelMatrix() * viewMatrix() * projectionMatrix()
  81.    
  82.     for k, v in ipairs(scene.depth) do
  83.         pushMatrix()
  84.        
  85.         move(k)
  86.        
  87.         v.shader.lightPos = light
  88.         v.shader.model = modelMatrix()
  89.         v:draw()
  90.        
  91.         popMatrix()
  92.     end
  93.    
  94.     setContext() -- Drawing onto the screen
  95.    
  96.     camera(pos.x, pos.y, pos.z, pos.x + ang.x * ang2.x, pos.y + ang2.y, pos.z + ang.y * ang2.x, 0, 1, 0)
  97.     --camera(light.x, light.y, light.z, 0, 0, 0, 0, 1, 0) -- Uncomment to show the scene from the light's position
  98.     perspective(80, WIDTH / HEIGHT, 0.001, 65536)
  99.    
  100.     lightm:draw() -- Comment out if you are looking at the scene from the light's position
  101.    
  102.     for k = #scene.main, 1, -1 do
  103.         local v = scene.main[k]
  104.        
  105.         pushMatrix()
  106.        
  107.         move(k)
  108.        
  109.         v.shader.lightModelViewProjection = lightModelViewProjection
  110.         v.shader.shadowMap = depth
  111.         v.shader.lightPos = light
  112.         v.shader.model = modelMatrix()
  113.         v:draw()
  114.        
  115.         popMatrix()
  116.     end
  117.    
  118.     ortho()
  119.     viewMatrix(matrix())
  120.     resetMatrix()
  121.    
  122.     tint(255, 127) -- Small preview of the light's perspective (depth map)
  123.     sprite(depth, 100, 100, 200, 200)
  124.    
  125.     fill(255)
  126.     font("HelveticaNeue-Light")
  127.     fontSize(24)
  128.     local w, h = textSize(FPS)
  129.     text(FPS, w / 2, HEIGHT - h / 2)
  130.    
  131.     collectgarbage()
  132.     collectgarbage()
  133.     collectgarbage()
  134. end
  135.  
  136. function touched(touch) -- Handles camera movement and direction
  137.     if touch.state == BEGAN then
  138.         if touch.x < WIDTH / 2 and mId == 0 then
  139.             mId = touch.id
  140.         elseif touch.x >= WIDTH / 2 and lId == 0 then
  141.             lId = touch.id
  142.         end
  143.     end
  144.    
  145.     if touch.id == mId then
  146.         local speed = 1 / 64
  147.         tpos.x = tpos.x + tang:rotate(math.pi / 2).x * touch.deltaX * speed
  148.         tpos.z = tpos.z + tang:rotate(math.pi / 2).y * touch.deltaX * speed
  149.         tpos.x = tpos.x + tang.x * tang2.x * touch.deltaY * speed
  150.         tpos.z = tpos.z + tang.y * tang2.x * touch.deltaY * speed
  151.         tpos.y = tpos.y + tang2.y * touch.deltaY * speed
  152.     elseif touch.id == lId then
  153.         tang = tang:rotate(math.rad(touch.deltaX / 2))
  154.         tang2 = tang2:rotate(math.rad(touch.deltaY / 2))
  155.         if tang2.x < 0.01 then
  156.             if tang2.y < 0 then
  157.                 tang2 = vec2(0.01, -1):normalize()
  158.             else
  159.                 tang2 = vec2(0.01, 1):normalize()
  160.             end
  161.         end
  162.     end
  163.    
  164.     if touch.state == ENDED then
  165.         if touch.id == mId then
  166.             mId = 0
  167.         elseif touch.id == lId then
  168.             lId = 0
  169.         end
  170.     end
  171. end
  172.  
  173. function box(px, py, pz, pw, ph, pl)
  174.     local x = px or 0
  175.     local y = py or x
  176.     local z = pz or x
  177.     local w = pw or 1
  178.     local h = ph or w
  179.     local l = pl or w
  180.    
  181.     local main = mesh()
  182.     main.vertices = Primitive:Cube(w, h, l, x, y, z)
  183.     main.texCoords = Primitive:CubeTexCoords()
  184.     main:setColors(color(255))
  185.     main.shader = shader("Shadow")
  186.    
  187.     local depth = mesh()
  188.     depth.vertices = Primitive:Cube(w, h, l, x, y, z)
  189.     depth.texCoords = Primitive:CubeTexCoords()
  190.     depth.shader = shader("Depth")
  191.    
  192.     return main, depth
  193. end
  194.  
  195. -- Function tweak to make shaders easier, so I can call shader("Depth") instead of shader(Shaders.Depth.vS, Shaders.Depth.fS)
  196. local _shader = shader
  197. function shader(...)
  198.     if select("#", ...) == 1 then
  199.         local data = Shaders[select(1, ...)]
  200.         if data ~= nil then
  201.             return _shader(data.vS, data.fS)
  202.         else
  203.             return _shader(...)
  204.         end
  205.     else
  206.         return _shader(...)
  207.     end
  208. end
  209.  
  210. --# Shaders
  211. -- Shaders
  212. -- "Depth" shader encodes the distance between a fragment and the light
  213. -- "Shadow" shader takes the encoded distance and calculates shadows with it
  214.  
  215. Shaders = {
  216. --shaderstart:Depth
  217. Depth = {
  218. vS = [[
  219. //
  220. // A basic vertex shader
  221. //
  222.  
  223. //This is the current model * view * projection matrix
  224. // Codea sets it automatically
  225. uniform mat4 modelViewProjection;
  226.  
  227. uniform mat4 model;
  228.  
  229. //This is the current mesh vertex position, color and tex coord
  230. // Set automatically
  231. attribute vec4 position;
  232. attribute vec4 color;
  233. attribute vec2 texCoord;
  234.  
  235. //This is an output variable that will be passed to the fragment shader
  236. varying lowp vec4 vColor;
  237. varying highp vec2 vTexCoord;
  238. varying vec4 vPosition;
  239.  
  240. void main()
  241. {
  242.     //Pass the mesh color to the fragment shader
  243.     vColor = color;
  244.     vTexCoord = texCoord;
  245.     vPosition = model * position;
  246.    
  247.     //Multiply the vertex position by our combined transform
  248.     gl_Position = modelViewProjection * position;
  249. }
  250. ]],
  251. fS = [[
  252. //
  253. // A basic fragment shader
  254. //
  255.  
  256. //Default precision qualifier
  257. precision highp float;
  258.  
  259. //This represents the current texture on the mesh
  260. uniform lowp sampler2D texture;
  261.  
  262. uniform vec3 lightPos;
  263.  
  264. //The interpolated vertex color for this fragment
  265. varying lowp vec4 vColor;
  266.  
  267. //The interpolated texture coordinate for this fragment
  268. varying highp vec2 vTexCoord;
  269.  
  270. varying vec4 vPosition;
  271.  
  272. void main()
  273. {
  274.     highp float dist = distance(lightPos, vPosition.xyz);
  275.     lowp vec4 col = vec4(mod(dist, 1.0), mod(floor(dist) / 50.0, 1.0), floor(dist / 50.0) / 50.0, 1.0);
  276.    
  277.     // Encoded RGB data:
  278.     // full red = 1 unit
  279.     // full green = 50 units
  280.     // full blue = 2500 units
  281.     // Add that all together and you get the encoded distance
  282.  
  283.     //Set the output color to the texture color
  284.     gl_FragColor = col;
  285. }
  286. ]],
  287. },
  288. --shaderend:Depth
  289. --shaderstart:Shadow
  290. Shadow = {
  291. vS = [[
  292. //
  293. // A basic vertex shader
  294. //
  295.  
  296. //This is the current model * view * projection matrix
  297. // Codea sets it automatically
  298. uniform mat4 modelViewProjection;
  299.  
  300. uniform mat4 model;
  301.  
  302. //This is the current mesh vertex position, color and tex coord
  303. // Set automatically
  304. attribute vec4 position;
  305. attribute vec4 color;
  306. attribute vec2 texCoord;
  307.  
  308. //This is an output variable that will be passed to the fragment shader
  309. varying lowp vec4 vColor;
  310. varying highp vec2 vTexCoord;
  311. varying vec4 vPosition;
  312.  
  313. void main()
  314. {
  315.     //Pass the mesh color to the fragment shader
  316.     vColor = color;
  317.     vTexCoord = texCoord;
  318.     vPosition = model * position;
  319.    
  320.     //Multiply the vertex position by our combined transform
  321.     gl_Position = modelViewProjection * position;
  322. }
  323. ]],
  324. fS = [[
  325. //
  326. // A basic fragment shader
  327. //
  328.  
  329. //Default precision qualifier
  330. precision highp float;
  331.  
  332. uniform mat4 lightModelViewProjection;
  333.  
  334. //This represents the current texture on the mesh
  335. uniform lowp sampler2D texture;
  336.  
  337. uniform lowp sampler2D shadowMap;
  338.  
  339. uniform vec3 lightPos;
  340.  
  341. //The interpolated vertex color for this fragment
  342. varying lowp vec4 vColor;
  343.  
  344. //The interpolated texture coordinate for this fragment
  345. varying highp vec2 vTexCoord;
  346.  
  347. varying vec4 vPosition;
  348.  
  349. void main()
  350. {
  351.     if (!gl_FrontFacing) discard;
  352.    
  353.     //Sample the texture at the interpolated coordinate
  354.     lowp vec4 col = texture2D( texture, vTexCoord );
  355.    
  356.     vec4 m = lightModelViewProjection * vPosition;
  357.     vec2 lightTexCoord = vec2((m[0] / m[3] + 1.0) / 2.0, (m[1] / m[3] + 1.0) / 2.0); // The texture coordinate of this fragment from the light's perspective
  358.    
  359.    highp vec4 lightCol = texture2D(shadowMap, lightTexCoord.xy); // The encoded distance
  360.    highp float lightDist = lightCol.r + lightCol.g * 50.0 + floor(lightCol.b * 2500.0); // The decoded distance between whatever fragment in this direction is closest to the light and the light itself
  361.    highp float dist = distance(vPosition.xyz, lightPos); // Distance between this fragment and the light
  362.        
  363.    if (dist > lightDist + 0.2) col.rgb *= 0.5; // You can change the effect here to get different shadows
  364.    
  365.    //Set the output color to the texture color
  366.    gl_FragColor = col * vColor;
  367. }
  368. ]],
  369. },
  370. --shaderend:Shadow
  371. }
  372. --# Primitive
  373. Primitive = class()
  374. -- Primitive class originally by @spacemonkey
  375. -- Edited by @SkyTheCoder to add options for width, height, length, and position, also to generate texture coordinates for the cube
  376.  
  377. --primitves gives basic mesh building for cubes and isospheres
  378. --triangles are wound consistently to avoid gl_facing issues
  379.  
  380. function Primitive:Cube(w, h, l, x, y, z)
  381.    local s = 1
  382.    w = w or 1
  383.    h = h or w
  384.    l = l or h
  385.    x = x or 0
  386.    y = y or 0
  387.    z = z or 0
  388.    local vertices = {
  389.      vec3(-0.5*s, -0.5*s,  0.5*s), -- Left  bottom front
  390.      vec3( 0.5*s, -0.5*s,  0.5*s), -- Right bottom front
  391.      vec3( 0.5*s,  0.5*s,  0.5*s), -- Right top    front
  392.      vec3(-0.5*s,  0.5*s,  0.5*s), -- Left  top    front
  393.      vec3(-0.5*s, -0.5*s, -0.5*s), -- Left  bottom back
  394.      vec3( 0.5*s, -0.5*s, -0.5*s), -- Right bottom back
  395.      vec3( 0.5*s,  0.5*s, -0.5*s), -- Right top    back
  396.      vec3(-0.5*s,  0.5*s, -0.5*s), -- Left  top    back
  397.    }
  398.  
  399.    -- now construct a cube out of the vertices above
  400.    v = {
  401.      -- Front
  402.      vertices[1], vertices[2], vertices[3],
  403.      vertices[1], vertices[3], vertices[4],
  404.      -- Right
  405.      vertices[2], vertices[6], vertices[7],
  406.      vertices[2], vertices[7], vertices[3],
  407.      -- Back
  408.      vertices[6], vertices[5], vertices[8],
  409.      vertices[6], vertices[8], vertices[7],
  410.      -- Left
  411.      vertices[5], vertices[1], vertices[4],
  412.      vertices[5], vertices[4], vertices[8],
  413.      -- Top
  414.      vertices[4], vertices[3], vertices[7],
  415.      vertices[4], vertices[7], vertices[8],
  416.      -- Bottom
  417.      vertices[5], vertices[6], vertices[2],
  418.      vertices[5], vertices[2], vertices[1],
  419.    }
  420.    for i, j in ipairs(v) do
  421.        v[i] = vec3(j.x * w + x, j.y * h + y, j.z * l + z)
  422.    end
  423.    return v
  424. end
  425.  
  426. function Primitive:CubeTexCoords(w, h, x)
  427.    w = w or 1
  428.    h = h or w
  429.    x = x or Primitive:Cube(1)
  430.    local ret = {}
  431.    for i = 1, #x / 3 do
  432.        table.insert(ret, vec2(0.0, 0.0))
  433.        table.insert(ret, vec2(w, 0.0))
  434.        table.insert(ret, vec2(w, h))
  435.        table.insert(ret, vec2(0.0, 0.0))
  436.        table.insert(ret, vec2(w, h))
  437.        table.insert(ret, vec2(0.0, h))
  438.    end
  439.    return ret
  440. end
  441.  
  442.  
  443. --# FPS
  444. FPS = 0 -- Code to calculate accurate frames per secoond
  445. local frames = 0
  446. local time = 0
  447. tween.delay(0.001, function()
  448.    local d = draw
  449.    draw = function()
  450.        frames = frames + 1
  451.        if math.floor(ElapsedTime) ~= math.floor(time) then
  452.            FPS = frames - 1
  453.            frames = 1
  454.        end
  455.        time = ElapsedTime
  456.        d()
  457.    end
  458. end)
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×