Advertisement
SkyTheCoder

ShadowMap.lua

May 6th, 2015
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.28 KB | None | 0 0
  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)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement