Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Main
- -- ShadowMap
- displayMode(FULLSCREEN)
- function setup()
- scene = {main = {}, depth = {}}
- boxA, boxAdepth = box(0, -4, 0, 8)
- boxA.texture = readImage("Cargo Bot:Crate Yellow 2")
- boxA:setColors(color(255, 255))
- table.insert(scene.main, boxA)
- table.insert(scene.depth, boxAdepth)
- local numBoxes = 10 -- The number of boxes to fly around the scene
- for i = 1, numBoxes do
- math.randomseed(i)
- boxB, boxBdepth = box(0, 0, 0, 1)--box(math.random(-5, 5), math.random(0, 5), math.random(-5, 5), 0.5)
- boxB.texture = readImage("Cargo Bot:Crate Red 2")
- boxB:setColors(color(255, 255))
- table.insert(scene.main, boxB)
- table.insert(scene.depth, boxBdepth)
- end
- local s = 1024 -- The size of the shadowmap (512, 1024, or 2048 offer good FPS, but you can go up to 4096)
- depth = image(s / ContentScaleFactor, s / ContentScaleFactor)
- light = vec3(5, 5, 5)
- lightm = mesh() -- A cube to show where the light is
- lightm.vertices = Primitive:Cube(0.5, 0.5, 0.5, light.x, light.y, light.z)
- lightm:setColors(color(0))
- pos = vec3(0, 1, 0) -- Variables to handle camera movement and direction
- ang = vec2(0, 1)
- ang2 = vec2(1, -1):normalize()
- tpos = vec3(pos.x, pos.y, pos.z)
- tang = vec2(ang.x, ang.y)
- tang2 = vec2(ang2.x, ang2.y)
- mId = 0
- lId = 0
- end
- function move(k) -- Basic function to move and rotate the cubes to show off the shadowmaps
- if k > 1 then
- math.randomseed(k - 1)
- translate(math.random(-5, 5), math.random(0, 5), math.random(-5, 5))
- local dist = 4
- local rot = 360
- local speed = 0.25
- 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)
- rotate(noise(ElapsedTime * speed + k, 48, k * 16) * rot, 1, 0, 0)
- rotate(noise(ElapsedTime * speed + k, 64, k * 16) * rot, 0, 1, 0)
- rotate(noise(ElapsedTime * speed + k, 80, k * 16) * rot, 0, 0, 1)
- end
- end
- function draw()
- background(178, 211, 223, 255)
- local pmix = 0.0375 -- Smoothes the camera movement
- pos.x = pos.x * (1 - pmix) + tpos.x * pmix
- pos.y = pos.y * (1 - pmix) + tpos.y * pmix
- pos.z = pos.z * (1 - pmix) + tpos.z * pmix
- local amix = 0.1
- ang.x = ang.x * (1 - amix) + tang.x * amix
- ang.y = ang.y * (1 - amix) + tang.y * amix
- ang2.x = ang2.x * (1 - amix) + tang2.x * amix
- ang2.y = ang2.y * (1 - amix) + tang2.y * amix
- setContext(depth, true) -- Drawing into the depth map
- background(255, 255)
- camera(light.x, light.y, light.z, 0, 0, 0, 0, 1, 0)
- perspective(150, depth.width / depth.height, 0.001, 65536)
- local lightModelViewProjection = modelMatrix() * viewMatrix() * projectionMatrix()
- for k, v in ipairs(scene.depth) do
- pushMatrix()
- move(k)
- v.shader.lightPos = light
- v.shader.model = modelMatrix()
- v:draw()
- popMatrix()
- end
- setContext() -- Drawing onto the screen
- 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)
- --camera(light.x, light.y, light.z, 0, 0, 0, 0, 1, 0) -- Uncomment to show the scene from the light's position
- perspective(80, WIDTH / HEIGHT, 0.001, 65536)
- lightm:draw() -- Comment out if you are looking at the scene from the light's position
- for k = #scene.main, 1, -1 do
- local v = scene.main[k]
- pushMatrix()
- move(k)
- v.shader.lightModelViewProjection = lightModelViewProjection
- v.shader.shadowMap = depth
- v.shader.lightPos = light
- v.shader.model = modelMatrix()
- v:draw()
- popMatrix()
- end
- ortho()
- viewMatrix(matrix())
- resetMatrix()
- tint(255, 127) -- Small preview of the light's perspective (depth map)
- sprite(depth, 100, 100, 200, 200)
- fill(255)
- font("HelveticaNeue-Light")
- fontSize(24)
- local w, h = textSize(FPS)
- text(FPS, w / 2, HEIGHT - h / 2)
- collectgarbage()
- collectgarbage()
- collectgarbage()
- end
- function touched(touch) -- Handles camera movement and direction
- if touch.state == BEGAN then
- if touch.x < WIDTH / 2 and mId == 0 then
- mId = touch.id
- elseif touch.x >= WIDTH / 2 and lId == 0 then
- lId = touch.id
- end
- end
- if touch.id == mId then
- local speed = 1 / 64
- tpos.x = tpos.x + tang:rotate(math.pi / 2).x * touch.deltaX * speed
- tpos.z = tpos.z + tang:rotate(math.pi / 2).y * touch.deltaX * speed
- tpos.x = tpos.x + tang.x * tang2.x * touch.deltaY * speed
- tpos.z = tpos.z + tang.y * tang2.x * touch.deltaY * speed
- tpos.y = tpos.y + tang2.y * touch.deltaY * speed
- elseif touch.id == lId then
- tang = tang:rotate(math.rad(touch.deltaX / 2))
- tang2 = tang2:rotate(math.rad(touch.deltaY / 2))
- if tang2.x < 0.01 then
- if tang2.y < 0 then
- tang2 = vec2(0.01, -1):normalize()
- else
- tang2 = vec2(0.01, 1):normalize()
- end
- end
- end
- if touch.state == ENDED then
- if touch.id == mId then
- mId = 0
- elseif touch.id == lId then
- lId = 0
- end
- end
- end
- function box(px, py, pz, pw, ph, pl)
- local x = px or 0
- local y = py or x
- local z = pz or x
- local w = pw or 1
- local h = ph or w
- local l = pl or w
- local main = mesh()
- main.vertices = Primitive:Cube(w, h, l, x, y, z)
- main.texCoords = Primitive:CubeTexCoords()
- main:setColors(color(255))
- main.shader = shader("Shadow")
- local depth = mesh()
- depth.vertices = Primitive:Cube(w, h, l, x, y, z)
- depth.texCoords = Primitive:CubeTexCoords()
- depth.shader = shader("Depth")
- return main, depth
- end
- -- Function tweak to make shaders easier, so I can call shader("Depth") instead of shader(Shaders.Depth.vS, Shaders.Depth.fS)
- local _shader = shader
- function shader(...)
- if select("#", ...) == 1 then
- local data = Shaders[select(1, ...)]
- if data ~= nil then
- return _shader(data.vS, data.fS)
- else
- return _shader(...)
- end
- else
- return _shader(...)
- end
- end
- --# Shaders
- -- Shaders
- -- "Depth" shader encodes the distance between a fragment and the light
- -- "Shadow" shader takes the encoded distance and calculates shadows with it
- Shaders = {
- --shaderstart:Depth
- Depth = {
- vS = [[
- //
- // A basic vertex shader
- //
- //This is the current model * view * projection matrix
- // Codea sets it automatically
- uniform mat4 modelViewProjection;
- uniform mat4 model;
- //This is the current mesh vertex position, color and tex coord
- // Set automatically
- attribute vec4 position;
- attribute vec4 color;
- attribute vec2 texCoord;
- //This is an output variable that will be passed to the fragment shader
- varying lowp vec4 vColor;
- varying highp vec2 vTexCoord;
- varying vec4 vPosition;
- void main()
- {
- //Pass the mesh color to the fragment shader
- vColor = color;
- vTexCoord = texCoord;
- vPosition = model * position;
- //Multiply the vertex position by our combined transform
- gl_Position = modelViewProjection * position;
- }
- ]],
- fS = [[
- //
- // A basic fragment shader
- //
- //Default precision qualifier
- precision highp float;
- //This represents the current texture on the mesh
- uniform lowp sampler2D texture;
- uniform vec3 lightPos;
- //The interpolated vertex color for this fragment
- varying lowp vec4 vColor;
- //The interpolated texture coordinate for this fragment
- varying highp vec2 vTexCoord;
- varying vec4 vPosition;
- void main()
- {
- highp float dist = distance(lightPos, vPosition.xyz);
- lowp vec4 col = vec4(mod(dist, 1.0), mod(floor(dist) / 50.0, 1.0), floor(dist / 50.0) / 50.0, 1.0);
- // Encoded RGB data:
- // full red = 1 unit
- // full green = 50 units
- // full blue = 2500 units
- // Add that all together and you get the encoded distance
- //Set the output color to the texture color
- gl_FragColor = col;
- }
- ]],
- },
- --shaderend:Depth
- --shaderstart:Shadow
- Shadow = {
- vS = [[
- //
- // A basic vertex shader
- //
- //This is the current model * view * projection matrix
- // Codea sets it automatically
- uniform mat4 modelViewProjection;
- uniform mat4 model;
- //This is the current mesh vertex position, color and tex coord
- // Set automatically
- attribute vec4 position;
- attribute vec4 color;
- attribute vec2 texCoord;
- //This is an output variable that will be passed to the fragment shader
- varying lowp vec4 vColor;
- varying highp vec2 vTexCoord;
- varying vec4 vPosition;
- void main()
- {
- //Pass the mesh color to the fragment shader
- vColor = color;
- vTexCoord = texCoord;
- vPosition = model * position;
- //Multiply the vertex position by our combined transform
- gl_Position = modelViewProjection * position;
- }
- ]],
- fS = [[
- //
- // A basic fragment shader
- //
- //Default precision qualifier
- precision highp float;
- uniform mat4 lightModelViewProjection;
- //This represents the current texture on the mesh
- uniform lowp sampler2D texture;
- uniform lowp sampler2D shadowMap;
- uniform vec3 lightPos;
- //The interpolated vertex color for this fragment
- varying lowp vec4 vColor;
- //The interpolated texture coordinate for this fragment
- varying highp vec2 vTexCoord;
- varying vec4 vPosition;
- void main()
- {
- if (!gl_FrontFacing) discard;
- //Sample the texture at the interpolated coordinate
- lowp vec4 col = texture2D( texture, vTexCoord );
- vec4 m = lightModelViewProjection * vPosition;
- 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
- highp vec4 lightCol = texture2D(shadowMap, lightTexCoord.xy); // The encoded distance
- 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
- highp float dist = distance(vPosition.xyz, lightPos); // Distance between this fragment and the light
- if (dist > lightDist + 0.2) col.rgb *= 0.5; // You can change the effect here to get different shadows
- //Set the output color to the texture color
- gl_FragColor = col * vColor;
- }
- ]],
- },
- --shaderend:Shadow
- }
- --# Primitive
- Primitive = class()
- -- Primitive class originally by @spacemonkey
- -- Edited by @SkyTheCoder to add options for width, height, length, and position, also to generate texture coordinates for the cube
- --primitves gives basic mesh building for cubes and isospheres
- --triangles are wound consistently to avoid gl_facing issues
- function Primitive:Cube(w, h, l, x, y, z)
- local s = 1
- w = w or 1
- h = h or w
- l = l or h
- x = x or 0
- y = y or 0
- z = z or 0
- local vertices = {
- vec3(-0.5*s, -0.5*s, 0.5*s), -- Left bottom front
- vec3( 0.5*s, -0.5*s, 0.5*s), -- Right bottom front
- vec3( 0.5*s, 0.5*s, 0.5*s), -- Right top front
- vec3(-0.5*s, 0.5*s, 0.5*s), -- Left top front
- vec3(-0.5*s, -0.5*s, -0.5*s), -- Left bottom back
- vec3( 0.5*s, -0.5*s, -0.5*s), -- Right bottom back
- vec3( 0.5*s, 0.5*s, -0.5*s), -- Right top back
- vec3(-0.5*s, 0.5*s, -0.5*s), -- Left top back
- }
- -- now construct a cube out of the vertices above
- v = {
- -- Front
- vertices[1], vertices[2], vertices[3],
- vertices[1], vertices[3], vertices[4],
- -- Right
- vertices[2], vertices[6], vertices[7],
- vertices[2], vertices[7], vertices[3],
- -- Back
- vertices[6], vertices[5], vertices[8],
- vertices[6], vertices[8], vertices[7],
- -- Left
- vertices[5], vertices[1], vertices[4],
- vertices[5], vertices[4], vertices[8],
- -- Top
- vertices[4], vertices[3], vertices[7],
- vertices[4], vertices[7], vertices[8],
- -- Bottom
- vertices[5], vertices[6], vertices[2],
- vertices[5], vertices[2], vertices[1],
- }
- for i, j in ipairs(v) do
- v[i] = vec3(j.x * w + x, j.y * h + y, j.z * l + z)
- end
- return v
- end
- function Primitive:CubeTexCoords(w, h, x)
- w = w or 1
- h = h or w
- x = x or Primitive:Cube(1)
- local ret = {}
- for i = 1, #x / 3 do
- table.insert(ret, vec2(0.0, 0.0))
- table.insert(ret, vec2(w, 0.0))
- table.insert(ret, vec2(w, h))
- table.insert(ret, vec2(0.0, 0.0))
- table.insert(ret, vec2(w, h))
- table.insert(ret, vec2(0.0, h))
- end
- return ret
- end
- --# FPS
- FPS = 0 -- Code to calculate accurate frames per secoond
- local frames = 0
- local time = 0
- tween.delay(0.001, function()
- local d = draw
- draw = function()
- frames = frames + 1
- if math.floor(ElapsedTime) ~= math.floor(time) then
- FPS = frames - 1
- frames = 1
- end
- time = ElapsedTime
- d()
- end
- end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement