Browse Source

WIP blur update;

bjorn 3 years ago
parent
commit
e5af0b0b80
1 changed files with 39 additions and 57 deletions
  1. 39 57
      examples/Effects/Blur/main.lua

+ 39 - 57
examples/Effects/Blur/main.lua

@@ -4,19 +4,9 @@
 
 local useCanvas = true -- Set this to false to see the scene with no postprocessing.
 
--- A shader program consists of a vertex shader (which describes how to transform polygons)
--- and a fragment shader (which describes how to color pixels).
--- For a full-screen shader, the vertex shader should just pass the polygon through unaltered.
--- This is the same as the "default" full-screen shader used by lovr.graphics.plane:
-local screenShaderVertex = [[
-  vec4 position(mat4 projection, mat4 transform, vec4 vertex) {
-    return vertex;
-  }
-]]
-
 -- For the fragment shader: We are going to create a separable gaussian blur.
 -- A "separable" blur means we first blur horizontally, then blur vertically to get a 2D blur.
-local screenShaderFragment = [[
+local blurShader = [[
   // This one-dimensional blur filter samples five points and averages them by different amounts.
   // Weights and offsets taken from http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
 
@@ -29,25 +19,23 @@ local screenShaderFragment = [[
   #define OFFSET1 1.3846153846
   #define OFFSET2 3.2307692308
 
-  // The Canvas texture to sample from.
-  uniform sampler2DMultiview canvas;
-
-  // UVs are sampled from a texture over the range 0..1.
-  // This uniform is set outside the shader so we know what UV distance "one pixel" is.
-  uniform vec2 resolution;
+  Constants {
+    // This constant will be set every draw to determine whether we are sampling horizontally or vertically.
+    vec2 direction;
+  };
 
-  // This uniform will be set every draw to determine whether we are sampling horizontally or vertically.
-  uniform vec2 direction;
+  // The Canvas texture to sample from.
+  layout(set = 2, binding = 0) uniform texture2DArray canvas;
 
-  // lovr's shader architecture will automatically supply a main(), which will call this color() function
-  vec4 color(vec4 graphicsColor, sampler2D image, vec2 uv) {
-    vec2 pixelOff = direction / resolution;
+  // lovr's shader architecture will automatically supply a main(), which will call this lovrmain() function
+  vec4 lovrmain() {
+    vec2 uvOffset = direction / Resolution.xy; // Convert the offset from pixels to UVs
     vec4 color = vec4(0.0);
-    color += textureMultiview(canvas, uv) * WEIGHT0;
-    color += textureMultiview(canvas, uv + pixelOff * OFFSET1) * WEIGHT1;
-    color += textureMultiview(canvas, uv - pixelOff * OFFSET1) * WEIGHT1;
-    color += textureMultiview(canvas, uv + pixelOff * OFFSET2) * WEIGHT2;
-    color += textureMultiview(canvas, uv - pixelOff * OFFSET2) * WEIGHT2;
+    color += getPixel(canvas, UV, ViewIndex) * WEIGHT0;
+    color += getPixel(canvas, UV + uvOffset * OFFSET1, ViewIndex) * WEIGHT1;
+    color += getPixel(canvas, UV - uvOffset * OFFSET1, ViewIndex) * WEIGHT1;
+    color += getPixel(canvas, UV + uvOffset * OFFSET2, ViewIndex) * WEIGHT2;
+    color += getPixel(canvas, UV - uvOffset * OFFSET2, ViewIndex) * WEIGHT2;
     return color;
   }
 ]]
@@ -67,10 +55,11 @@ function lovr.load()
   -- Creative Commons 0 / Public Domain license
   local texture = lovr.graphics.newTexture('eye-chart-test-vintage-cc0.jpg')
   local textureWidth, textureHeight = texture:getDimensions()
+
   eyechart = {
     scale = .75,
     aspect = textureHeight / textureWidth,
-    material = lovr.graphics.newMaterial( texture )
+    texture = texture
   }
 
   -- Configure the shader
@@ -78,49 +67,42 @@ function lovr.load()
     local width, height = lovr.headset.getDisplayDimensions()
 
     -- Compile the shader
-    screenShader = lovr.graphics.newShader(screenShaderVertex, screenShaderFragment)
-
-    -- Set the resolution uniform
-    screenShader:send("resolution", {width, height})
+    screenShader = lovr.graphics.newShader('fill', blurShader)
 
     -- Create two temporary canvases
     tempCanvas = {
       lovr.graphics.newCanvas(width, height),
       lovr.graphics.newCanvas(width, height)
     }
-
-    tempCanvas[1]:getTexture():setWrap('clamp')
-    tempCanvas[2]:getTexture():setWrap('clamp')
   end
 end
 
 -- The scene is drawn in this callback
-local function sceneDraw()
-  lovr.graphics.clear() -- Because we are drawing to a canvas, we must manually clear
-  lovr.graphics.setShader(nil)
-
+local function sceneDraw(pass)
   -- Draw text on the left and right
-  for _, sign in ipairs {-1, 1} do
-    lovr.graphics.push()
-    lovr.graphics.rotate(sign * math.pi/2, 0, 1, 0)
-    lovr.graphics.print("MOVE CLOSER", 0, 0, -10, 5)
-    lovr.graphics.pop()
+  for _, sign in ipairs { -1, 1 } do
+    pass:push()
+    pass:rotate(sign * math.pi / 2, 0, 1, 0)
+    pass:text('MOVE CLOSER', 0, 0, -10, 5)
+    pass:pop()
   end
 
-  lovr.graphics.plane(eyechart.material, 0, 1.7, -1, eyechart.scale, eyechart.scale * eyechart.aspect)
+  pass:setMaterial(eyechart.texture)
+  pass:plane(0, 1.7, -1, eyechart.scale, eyechart.scale * eyechart.aspect)
+  pass:setMaterial()
 end
 
 -- This simple callback is used to draw one canvas onto another
-local function fullScreenDraw(source)
+local function fullScreenDraw(pass, source)
   screenShader:send('canvas', source:getTexture())
-  lovr.graphics.fill()
+  pass:fill()
 end
 
-function lovr.draw()
+function lovr.draw(pass)
   if not useCanvas then
 
     -- No-postprocessing path: Call scene-draw callback without doing anything fancy
-    sceneDraw()
+    sceneDraw(pass)
 
   else
 
@@ -135,23 +117,23 @@ function lovr.draw()
     -- To achieve these many passes we will render from canvas A into B, and then B back into A, and repeat.
     lovr.graphics.setShader(screenShader)
 
-    screenShader:send("direction", {1, 0})
+    pass:send("direction", {1, 0})
     tempCanvas[2]:renderTo(fullScreenDraw, tempCanvas[1])
 
-    screenShader:send("direction", {0, 1})
+    pass:send("direction", {0, 1})
     tempCanvas[1]:renderTo(fullScreenDraw, tempCanvas[2])
 
-    screenShader:send("direction", {2, 0})
+    pass:send("direction", {2, 0})
     tempCanvas[2]:renderTo(fullScreenDraw, tempCanvas[1])
 
-    screenShader:send("direction", {0, 2})
+    pass:send("direction", {0, 2})
     tempCanvas[1]:renderTo(fullScreenDraw, tempCanvas[2])
 
-    screenShader:send("direction", {4, 0})
+    pass:send("direction", {4, 0})
     tempCanvas[2]:renderTo(fullScreenDraw, tempCanvas[1])
 
-    screenShader:send("direction", {0, 4})
-    screenShader:send("canvas", tempCanvas[2]:getTexture())
-    lovr.graphics.fill() -- On the final pass, render directly to the screen.
+    pass:send("direction", {0, 4})
+    pass:send("canvas", tempCanvas[2]:getTexture())
+    pass:fill() -- On the final pass, render directly to the screen.
   end
 end