Selaa lähdekoodia

Retab Stencil example;

bjorn 2 vuotta sitten
vanhempi
commit
7c247f4283
2 muutettua tiedostoa jossa 159 lisäystä ja 157 poistoa
  1. 1 1
      examples/Effects/Stencil/conf.lua
  2. 158 156
      examples/Effects/Stencil/main.lua

+ 1 - 1
examples/Effects/Stencil/conf.lua

@@ -4,4 +4,4 @@ function lovr.conf(t)
   -- but we don't know which driver has been picked yet, so we set both.
   t.graphics.stencil = true
   t.headset.stencil = true
-end
+end

+ 158 - 156
examples/Effects/Stencil/main.lua

@@ -5,183 +5,185 @@
 local scene = {}
 
 function scene.load()
-	-- So we can see the effects of the stencils, we want to put some things in our scene.
-
-	-- A checkerboard floor:
-	scene.floorSize = 6
-
-	-- A series of sideways-drifting cubes (these will be stenciled)
-	scene.driftCubeCount = 60
-	scene.boundMin = lovr.math.newVec3(-10, -1, -10)
-	scene.boundMax = lovr.math.newVec3( 10,  9,  10)
-	scene.speed = 1
-	scene.driftCubeSize = 0.6
-	scene.driftCubes = {}
-	for i=1,scene.driftCubeCount do
-		scene.generateDriftCube(i, true)
-	end
-
-	-- A 3x3 cube made of two different stencil types
-	scene.stencilCubeCenter = lovr.math.newVec3(0, 1.5, -0.5)
-	scene.stencilCubeSize = 0.25
-	scene.stencilCubeRotate = 0
-	scene.stencilCubeRotateSpeed = 1
-	scene.stencilCubes = {}
-	for z=-1,1 do for y=-1,1 do for x=-1,1 do -- Iterate over every cube
-		if not (x==0 and y==0 and z==0) then -- Except the center
-			table.insert(scene.stencilCubes, {lovr.math.newVec3(x,y,z), math.random(1,2)}) -- Cube center and stencil type
-		end
-	end end end
-
-	-- Three cubemap skyboxes, of different colors
-	scene.skybox = {}
-	local skyboxTextureSize = 32
-	local bandSize=3
-	for cube_index,colors in ipairs{
-		{{1, 0.5, 1}, {1,1,1}},     -- Fuschia and white
-		{{1, 1, 0.5},   {0,0,0}},   -- Yellow and black
-		{{1,1,1}, {0.9,0.9,0.9}},   -- White and silver
-	} do
-		local layers = {}
-		for layer=1,6 do -- 6 layers to a cubemap
-			local data = lovr.data.newImage(skyboxTextureSize, skyboxTextureSize, "rgba8")
-			for y=1,skyboxTextureSize do for x=1,skyboxTextureSize do
-				local isBorder = x==1 or x==skyboxTextureSize or y==1 or y==skyboxTextureSize -- Solid color in corners
-				local direction = cube_index==3 and -1 or 1                          -- Reverse direction on third cubemap
-				local whichColor = (isBorder or ((x+direction*y-2)%(bandSize*2)>=bandSize)) and 1 or 2 -- Diagonal stripes
-				data:setPixel(x-1,y-1,unpack(colors[whichColor]))
-			end end
-			table.insert(layers, data)
-		end
-		table.insert(scene.skybox, lovr.graphics.newTexture(layers))
-	end
-
-	scene.sampler = lovr.graphics.newSampler({filter="nearest"})
+  -- So we can see the effects of the stencils, we want to put some things in our scene.
+
+  -- A checkerboard floor:
+  scene.floorSize = 6
+
+  -- A series of sideways-drifting cubes (these will be stenciled)
+  scene.driftCubeCount = 60
+  scene.boundMin = lovr.math.newVec3(-10, -1, -10)
+  scene.boundMax = lovr.math.newVec3( 10,  9,  10)
+  scene.speed = 1
+  scene.driftCubeSize = 0.6
+  scene.driftCubes = {}
+  for i=1,scene.driftCubeCount do
+    scene.generateDriftCube(i, true)
+  end
+
+  -- A 3x3 cube made of two different stencil types
+  scene.stencilCubeCenter = lovr.math.newVec3(0, 1.5, -0.5)
+  scene.stencilCubeSize = 0.25
+  scene.stencilCubeRotate = 0
+  scene.stencilCubeRotateSpeed = 1
+  scene.stencilCubes = {}
+  for z=-1,1 do for y=-1,1 do for x=-1,1 do -- Iterate over every cube
+    if not (x==0 and y==0 and z==0) then -- Except the center
+      table.insert(scene.stencilCubes, {lovr.math.newVec3(x,y,z), math.random(1,2)}) -- Cube center and stencil type
+    end
+  end end end
+
+  -- Three cubemap skyboxes, of different colors
+  scene.skybox = {}
+  local skyboxTextureSize = 32
+  local bandSize=3
+  for cube_index,colors in ipairs{
+    {{1, 0.5, 1}, {1,1,1}},     -- Fuschia and white
+    {{1, 1, 0.5},   {0,0,0}},   -- Yellow and black
+    {{1,1,1}, {0.9,0.9,0.9}},   -- White and silver
+  } do
+    local layers = {}
+    for layer=1,6 do -- 6 layers to a cubemap
+      local data = lovr.data.newImage(skyboxTextureSize, skyboxTextureSize, "rgba8")
+      for y=1,skyboxTextureSize do for x=1,skyboxTextureSize do
+        local isBorder = x==1 or x==skyboxTextureSize or y==1 or y==skyboxTextureSize -- Solid color in corners
+        local direction = cube_index==3 and -1 or 1                          -- Reverse direction on third cubemap
+        local whichColor = (isBorder or ((x+direction*y-2)%(bandSize*2)>=bandSize)) and 1 or 2 -- Diagonal stripes
+        data:setPixel(x-1,y-1,unpack(colors[whichColor]))
+      end end
+      table.insert(layers, data)
+    end
+    table.insert(scene.skybox, lovr.graphics.newTexture(layers))
+  end
+
+  scene.sampler = lovr.graphics.newSampler({filter="nearest"})
 end
 
 local function randomQuaternion() -- Generate one random rotation
-	-- Formula from http://planning.cs.uiuc.edu/node198.html
-	local u,v,w = math.random(), math.random(), math.random()
-	return lovr.math.newQuat( math.sqrt(1-u)*math.sin(2*v*math.pi),
-		        math.sqrt(1-u)*math.cos(2*v*math.pi),
-		        math.sqrt(u)*math.sin(2*w*math.pi),
-		        math.sqrt(u)*math.cos(2*w*math.pi),
-		        true ) -- Raw components
+  -- Formula from http://planning.cs.uiuc.edu/node198.html
+  local u,v,w = math.random(), math.random(), math.random()
+  return lovr.math.newQuat(
+    math.sqrt(1-u)*math.sin(2*v*math.pi),
+    math.sqrt(1-u)*math.cos(2*v*math.pi),
+    math.sqrt(u)*math.sin(2*w*math.pi),
+    math.sqrt(u)*math.cos(2*w*math.pi),
+    true -- Raw components
+  )
 end
 
 function scene.generateDriftCube(i, randomX) -- Generate one cube with random position and color and a random rotational velocity
-	local cube = {}
-	cube.at = lovr.math.newVec3()
-	if randomX then
-		cube.at.x = scene.boundMin.x + math.random()*(scene.boundMax.x-scene.boundMin.x)
-	else
-		cube.at.x = scene.boundMin.x
-	end
-	cube.at.y = scene.boundMin.y + math.random()*(scene.boundMax.y-scene.boundMin.y)
-	cube.at.z = scene.boundMin.z + math.random()*(scene.boundMax.z-scene.boundMin.z)
-
-	cube.rotateBasis = randomQuaternion()
-	cube.rotateTarget = lovr.math.newQuat(cube.rotateBasis:conjugate())
-	cube.rotate = cube.rotateBasis
-	scene.driftCubes[i] = cube
+  local cube = {}
+  cube.at = lovr.math.newVec3()
+  if randomX then
+    cube.at.x = scene.boundMin.x + math.random()*(scene.boundMax.x-scene.boundMin.x)
+  else
+    cube.at.x = scene.boundMin.x
+  end
+  cube.at.y = scene.boundMin.y + math.random()*(scene.boundMax.y-scene.boundMin.y)
+  cube.at.z = scene.boundMin.z + math.random()*(scene.boundMax.z-scene.boundMin.z)
+
+  cube.rotateBasis = randomQuaternion()
+  cube.rotateTarget = lovr.math.newQuat(cube.rotateBasis:conjugate())
+  cube.rotate = cube.rotateBasis
+  scene.driftCubes[i] = cube
 end
 
 function scene.update(dt) -- On each frame, move each cube and spin it a little
-	for i,cube in ipairs(scene.driftCubes) do
-		cube.at.x = cube.at.x + scene.speed*dt
-		if cube.at.x > scene.boundMax.x then -- If cube left the scene bounds respawn it
-			scene.generateDriftCube(i)
-		else
-			local rotateAmount = (cube.at.x - scene.boundMin.x)/(scene.boundMax.x-scene.boundMin.x)
-			cube.rotate = cube.rotateBasis:slerp( cube.rotateTarget, rotateAmount )
-		end
-	end
-
-	-- Also rotate the center cube
-	scene.stencilCubeRotate = scene.stencilCubeRotate + dt*scene.stencilCubeRotateSpeed
+  for i,cube in ipairs(scene.driftCubes) do
+    cube.at.x = cube.at.x + scene.speed*dt
+    if cube.at.x > scene.boundMax.x then -- If cube left the scene bounds respawn it
+      scene.generateDriftCube(i)
+    else
+      local rotateAmount = (cube.at.x - scene.boundMin.x)/(scene.boundMax.x-scene.boundMin.x)
+      cube.rotate = cube.rotateBasis:slerp( cube.rotateTarget, rotateAmount )
+    end
+  end
+
+  -- Also rotate the center cube
+  scene.stencilCubeRotate = scene.stencilCubeRotate + dt*scene.stencilCubeRotateSpeed
 end
 
 function scene.draw(pass)
-	-- Drawing without culling can make stencils or transparency look weird. We'll be using both...
-	pass:setCullMode('back')
-
-	-- First, draw the skybox
-	pass:setSampler(scene.sampler)
-	pass:skybox(scene.skybox[3])
-
-	-- Next, draw a floor
-	local floorRecenter = scene.floorSize/2 + 0.5
-	for x=1,scene.floorSize do for y=1,scene.floorSize do
-		if (x+y)%2==0 then
-			pass:setColor(0.25,0.25,0.25)
-		else
-			pass:setColor(0.35,0.35,0.35)
-		end
-		pass:plane(x-floorRecenter,0,y-floorRecenter, 1,1, -math.pi/2,1,0,0) -- Face up
-	end end
-	pass:setColor(1,1,1,1)
-
-	-- Stencils here
-	-- Using stencils involves drawing twice, once with a stencil write set and once with a stencil test set.
-
-	-- Example 1: Using stencils to "paint" scenes
-
-	-- Each sub-cube in our 3x3 cube will write a different value to the stencil buffer, 1 or 2.
-	pass:setColorWrite() -- In the color spectrum, these cubes are completely invisible! They write only stencil and depth.
-	pass:push() -- Position ourselves in the right place
-	pass:translate(scene.stencilCubeCenter)
-	pass:rotate(scene.stencilCubeRotate, 0,1,0)
-	for _, cube in ipairs(scene.stencilCubes) do
-		local center, stencilValue = unpack(cube)
-
-		-- Draw to stencil (but only when we pass the depth test)
-		pass:setStencilWrite({"keep", "keep", "replace"}, stencilValue)
-		pass:cube(center*scene.stencilCubeSize, scene.stencilCubeSize)
-
-	end
-	pass:pop()
-
-	pass:setStencilWrite() -- Reset stencil write
-	pass:setColorWrite(true) -- Reset color write
-
-	-- Now that we've painted the stencil buffer, let's draw something with depth-- like a skybox
-	pass:setDepthTest() -- Turn off depth test because the skybox is "behind" the cubes
-	for stencilValue=1,2 do
-		pass:setStencilTest("equal", stencilValue) -- Commands after here will only draw on pixels where the stencil value is right
-
-		pass:skybox(scene.skybox[stencilValue])
-	end
-	pass:setDepthTest("gequal") -- Turn depth test back on
-
-	-- Example 2: Using stencils to prevent collision
-
-	-- Here we will write AND test the stencil at the same time! In this step we want to draw a bunch of 50%-transparent cubes,
-	-- But we don't want any cubes to overlap each other. We want each cube to look like a "world of shadow".
-	-- The cubes can darken the skybox and the 3x3 cube, but not any pixel where another cube has already drawn.
-
-	pass:setStencilTest("notequal", 3) -- We will write the value "3", but refuse to write any pixel where a 3 is already present.
-	pass:setStencilWrite("replace", 3) -- Note we haven't cleared the stencil buffer, so we can't reuse values 1 or 2.
-	for _,cube in ipairs(scene.driftCubes) do
-		pass:setColor(0.75,0.5,0.5,0.5)
-		pass:cube(cube.at.x, cube.at.y, cube.at.z, scene.driftCubeSize, cube.rotate:unpack())
-	end
-
-	-- The stencil state will reset at the end of this lovr.draw, but let's clear it anyway.
-	pass:setStencilWrite()
-	pass:setStencilTest()
+  -- Drawing without culling can make stencils or transparency look weird. We'll be using both...
+  pass:setCullMode('back')
+
+  -- First, draw the skybox
+  pass:setSampler(scene.sampler)
+  pass:skybox(scene.skybox[3])
+
+  -- Next, draw a floor
+  local floorRecenter = scene.floorSize/2 + 0.5
+  for x=1,scene.floorSize do for y=1,scene.floorSize do
+    if (x+y)%2==0 then
+      pass:setColor(0.25,0.25,0.25)
+    else
+      pass:setColor(0.35,0.35,0.35)
+    end
+    pass:plane(x-floorRecenter,0,y-floorRecenter, 1,1, -math.pi/2,1,0,0) -- Face up
+  end end
+  pass:setColor(1,1,1,1)
+
+  -- Stencils here
+  -- Using stencils involves drawing twice, once with a stencil write set and once with a stencil test set.
+
+  -- Example 1: Using stencils to "paint" scenes
+
+  -- Each sub-cube in our 3x3 cube will write a different value to the stencil buffer, 1 or 2.
+  pass:setColorWrite() -- In the color spectrum, these cubes are completely invisible! They write only stencil and depth.
+  pass:push() -- Position ourselves in the right place
+  pass:translate(scene.stencilCubeCenter)
+  pass:rotate(scene.stencilCubeRotate, 0,1,0)
+  for _, cube in ipairs(scene.stencilCubes) do
+    local center, stencilValue = unpack(cube)
+
+    -- Draw to stencil (but only when we pass the depth test)
+    pass:setStencilWrite({"keep", "keep", "replace"}, stencilValue)
+    pass:cube(center*scene.stencilCubeSize, scene.stencilCubeSize)
+
+  end
+  pass:pop()
+
+  pass:setStencilWrite() -- Reset stencil write
+  pass:setColorWrite(true) -- Reset color write
+
+  -- Now that we've painted the stencil buffer, let's draw something with depth-- like a skybox
+  pass:setDepthTest() -- Turn off depth test because the skybox is "behind" the cubes
+  for stencilValue=1,2 do
+    pass:setStencilTest("equal", stencilValue) -- Commands after here will only draw on pixels where the stencil value is right
+
+    pass:skybox(scene.skybox[stencilValue])
+  end
+  pass:setDepthTest("gequal") -- Turn depth test back on
+
+  -- Example 2: Using stencils to prevent collision
+
+  -- Here we will write AND test the stencil at the same time! In this step we want to draw a bunch of 50%-transparent cubes,
+  -- But we don't want any cubes to overlap each other. We want each cube to look like a "world of shadow".
+  -- The cubes can darken the skybox and the 3x3 cube, but not any pixel where another cube has already drawn.
+
+  pass:setStencilTest("notequal", 3) -- We will write the value "3", but refuse to write any pixel where a 3 is already present.
+  pass:setStencilWrite("replace", 3) -- Note we haven't cleared the stencil buffer, so we can't reuse values 1 or 2.
+  for _,cube in ipairs(scene.driftCubes) do
+    pass:setColor(0.75,0.5,0.5,0.5)
+    pass:cube(cube.at.x, cube.at.y, cube.at.z, scene.driftCubeSize, cube.rotate:unpack())
+  end
+
+  -- The stencil state will reset at the end of this lovr.draw, but let's clear it anyway.
+  pass:setStencilWrite()
+  pass:setStencilTest()
 end
 
 -- Handle lovr
 
 function lovr.load()
-	lovr.graphics.setBackgroundColor(1,0,0) -- Red to show up clearly if something goes wrong
-	scene.load()
+  lovr.graphics.setBackgroundColor(1,0,0) -- Red to show up clearly if something goes wrong
+  scene.load()
 end
 
 function lovr.update(dt)
-	scene.update(dt)
+  scene.update(dt)
 end
 
 function lovr.draw(pass)
-	scene.draw(pass)
+  scene.draw(pass)
 end