Browse Source

Update shader syntax/guide;

bjorn 9 months ago
parent
commit
49af210cec

File diff suppressed because it is too large
+ 1 - 1
api/init.lua


+ 1 - 1
api/lovr/graphics/Pass/compute.lua

@@ -101,7 +101,7 @@ return {
       function lovr.load()
         shader = lovr.graphics.newShader([[
           layout(local_size_x = 8, local_size_y = 8) in;
-          layout(set = 0, binding = 0, rgba8) uniform image2D image;
+          layout(rgba8) uniform image2D image;
 
           void lovrmain() {
             ivec2 size = imageSize(image);

+ 4 - 7
api/lovr/graphics/Pass/send.lua

@@ -86,13 +86,10 @@ return {
   example = [=[
     function lovr.load()
       shader = lovr.graphics.newShader([[
-        layout(set = 2, binding = 0) uniform sampler mySampler;
-        layout(set = 2, binding = 1) uniform Colors { vec4 colors[256]; };
-        layout(set = 2, binding = 2) uniform texture2D rocks;
-
-        Constants {
-          uint constant;
-        };
+        uniform sampler mySampler;
+        uniform Colors { vec4 colors[256]; };
+        uniform texture2D rocks;
+        uniform uint constant;
 
         vec4 lovrmain() {
           return DefaultPosition;

+ 1 - 1
api/lovr/graphics/Sampler/init.lua

@@ -7,7 +7,7 @@ return {
     Each `Pass` has a default sampler that will be used by default, which can be changed using
     `Pass:setSampler`.  Also, samplers can be declared in shaders using the following syntax:
 
-        layout(set = 2, binding = X) uniform sampler mySampler;
+        uniform sampler mySampler;
 
     A Sampler can be sent to the variable using `Pass:send('mySampler', sampler)`.
 

+ 3 - 3
api/lovr/graphics/Shader/getBufferFormat.lua

@@ -37,7 +37,7 @@ return {
     of a single-field struct with an array in it.  Example:
 
         shader = lovr.graphics.newShader([[
-          layout(set = 0, binding = 0) buffer Numbers {
+          buffer Numbers {
             uint numbers[64];
           };
 
@@ -58,7 +58,7 @@ return {
             float grip;
           };
 
-          layout(set = 0, binding = 0) buffer Hand {
+          buffer Hand {
             HandParams params;
           };
 
@@ -71,7 +71,7 @@ return {
   ]=],
   example = [=[
     shader = lovr.graphics.newShader([[
-      layout(set = 2, binding = 0) uniform Transforms {
+      uniform Transforms {
         mat4 transforms[32];
       };
 

+ 1 - 3
api/lovr/graphics/Shader/hasAttribute.lua

@@ -30,7 +30,7 @@ return {
   example = [=[
     function lovr.load()
       shader = lovr.graphics.newShader([[
-        layout(location = 7) in uint coolAttribute;
+        in uint coolAttribute;
 
         vec4 lovrmain() {
           return DefaultPosition;
@@ -42,8 +42,6 @@ return {
       ]])
 
       print(shader:hasAttribute('coolAttribute')) --> true
-      print(shader:hasAttribute(7)) --> true
-      print(shader:hasAttribute(8)) --> false
     end
   ]=]
 }

+ 1 - 1
examples/Effects/Blur/main.lua

@@ -25,7 +25,7 @@ local blurShader = [[
   };
 
   // The texture to sample from.
-  layout(set = 2, binding = 0) uniform texture2DArray sourceTexture;
+  uniform texture2DArray sourceTexture;
 
   // lovr's shader architecture will automatically supply a main(), which will call this lovrmain() function
   vec4 lovrmain() {

+ 1 - 1
examples/Effects/Cubemap_Generate/main.lua

@@ -118,7 +118,7 @@ function cubemap.load()
 
 	-- Create reflection shader
 	cubemap.shader = lovr.graphics.newShader('unlit', [[
-		layout(set = 2, binding = 0) uniform textureCube cubemap;
+		uniform textureCube cubemap;
 
 		vec4 lovrmain() {
 			vec3 V = normalize(CameraPositionWorld - PositionWorld);

+ 3 - 3
examples/Effects/Cubemap_Texturing/main.lua

@@ -12,14 +12,14 @@ function lovr.load()
   })
 
   shader = lovr.graphics.newShader([[
-    layout(location = 0) out vec3 pos;
+    out vec3 pos;
     vec4 lovrmain() {
       pos = VertexPosition.xyz;
       return DefaultPosition;
     }
   ]], [[
-    layout(set = 2, binding = 0) uniform textureCube cube;
-    layout(location = 0) in vec3 pos;
+    in vec3 pos;
+    uniform textureCube cube;
     vec4 lovrmain() {
       return getPixel(cube, pos);
     }

+ 4 - 6
examples/Environment/Terrain_-_Heightmap/main.lua

@@ -1,7 +1,7 @@
 local shaderCode = {[[
 /* VERTEX shader */
-layout(location = 0) out vec4 fragmentClip;
-layout(set = 2) uniform texture2D heightmap;
+out vec4 fragmentClip;
+uniform texture2D heightmap;
 
 vec4 lovrmain() {
   vec3 position = VertexPosition.xyz;
@@ -10,11 +10,9 @@ vec4 lovrmain() {
   return fragmentClip;
 } ]], [[
 /* FRAGMENT shader */
-layout(location = 0) in vec4 fragmentView;
+vec4 fragmentView;
 
-Constants {
-  vec3 fogColor;
-};
+uniform vec3 fogColor;
 
 vec4 lovrmain() {
   float fogAmount = atan(length(fragmentView) * 0.1) * 2.0 / PI;

+ 2 - 2
examples/Lighting/PBR_Materials/main.lua

@@ -11,8 +11,8 @@ function lovr.load()
       return DefaultPosition;
     }
   ]], [[
-    layout(set = 2, binding = 0) uniform textureCube cubemap;
-    layout(set = 2, binding = 1) uniform sphericalHarmonics { vec3 sh[9]; };
+    uniform textureCube cubemap;
+    uniform sphericalHarmonics { vec3 sh[9]; };
 
     vec4 lovrmain() {
       Surface surface;

+ 4 - 6
examples/Lighting/Shadows/main.lua

@@ -55,13 +55,11 @@ local function lighting_shader()
   ]]
 
   local fs = [[
-    Constants {
-      vec3 lightPos;
-      mat4 lightSpaceMatrix;
-      bool lightOrthographic;
-    };
+    uniform vec3 lightPos;
+    uniform mat4 lightSpaceMatrix;
+    uniform bool lightOrthographic;
 
-    layout(set = 2, binding = 0) uniform texture2D shadowMapTexture;
+    uniform texture2D shadowMapTexture;
 
     vec4 diffuseLighting(vec3 lightDir, vec3 normal, float shadow) {
       float diff = max(dot(normal, lightDir), 0.0);

+ 1 - 1
examples/Optimization/Instancing/main.lua

@@ -18,7 +18,7 @@ function lovr.load()
 
   -- Make a shader that uses transforms from a buffer
   shader = lovr.graphics.newShader([[
-    layout(set = 2, binding = 0) uniform Transforms {
+    uniform Transforms {
       mat4 transforms[500];
     };
 

+ 1 - 1
examples/Optimization/Instancing_-_Blob/main.lua

@@ -25,7 +25,7 @@ function lovr.load()
   buffer = lovr.graphics.newBuffer('mat4', transformBlob)
 
   shader = lovr.graphics.newShader([[
-    layout(set = 2, binding = 0) uniform TransformBuffer { mat4 transforms[500]; };
+    uniform TransformBuffer { mat4 transforms[500]; };
 
     vec4 lovrmain() {
       return Projection * View * Transform * transforms[InstanceIndex] * VertexPosition;

+ 4 - 6
examples/Optimization/Instancing_-_Compute/main.lua

@@ -33,12 +33,10 @@ function lovr.load()
   computeShader = lovr.graphics.newShader([[
     layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in;
 
-    layout(set = 0, binding = 0) buffer TransformBuffer { mat4 Transforms[]; };
-    layout(set = 0, binding = 1) buffer OffsetBuffer { mat4 Offsets[]; };
+    buffer TransformBuffer { mat4 Transforms[]; };
+    buffer OffsetBuffer { mat4 Offsets[]; };
 
-    Constants {
-      uint monkeyCount;
-    };
+    uniform uint monkeyCount;
 
     void lovrmain() {
       uint i = GlobalThreadID.x;
@@ -49,7 +47,7 @@ function lovr.load()
 
   -- Create the display shader, injecting the shader code for the block
   shader = lovr.graphics.newShader([[
-    layout(set = 2, binding = 0) buffer TransformBuffer { mat4 Transforms[]; };
+    buffer TransformBuffer { mat4 Transforms[]; };
 
     vec4 lovrmain() {
       return Projection * View * Transforms[InstanceIndex] * Transform * VertexPosition;

+ 38 - 42
guides/Shaders.md

@@ -98,6 +98,16 @@ the code of one or both of the stages:
 
     shader = lovr.graphics.newShader('vertex.glsl', 'unlit')
 
+Finally, for advanced use, `lovr.graphics.newShader` takes a `raw` option that will use raw GLSL
+code without any LÖVR helpers:
+
+    shader = lovr.graphics.newShader([[
+      #version 460
+      void main() {
+        //
+      }
+    ]], { raw = true })
+
 Shader Builtins
 ---
 
@@ -302,7 +312,7 @@ The following built-in variables and macros are available only in fragment shade
     </tr>
     <tr>
       <td><code>Tangent</code></td>
-      <td>vec3</td>
+      <td>vec4</td>
       <td>The tangent vector of the current pixel, in world space.</td>
     </tr>
     <tr>
@@ -425,25 +435,21 @@ Shader Inputs
 It's also possible to send values or objects from Lua to a Shader.  There are a few different ways
 to do this, each with their own tradeoffs (speed, size, ease of use, etc.).
 
-### Constants
+### Uniforms
 
-Shaders can declare constants, which can be booleans, numbers, vectors, or matrices.  There is a
-very limited amount of space for constants (usually 128 or 256 bytes, depends on the GPU), but they
-are very easy and inexpensive to update.
+Shaders can declare uniforms, which can be booleans, numbers, vectors, or matrices.  These have a
+constant or "uniform" value for all vertices/pixels that are drawn.  They are easy to use and
+inexpensive to update, but they must be resent every frame and whenever the shader changes.
 
-Constants are declared in shader code in a `Constants` block, then individual constants are modified
-from Lua using `Pass:send`:
+Uniforms are declared in shader code with the `uniform` keyword, and can be set with `Pass:send`:
 
     function lovr.load()
       shader = lovr.graphics.newShader('unlit', [[
-        Constants {
-          vec4 color1;
-          vec4 color2;
-        };
-
-        // Apply a vertical gradient using the 2 colors from the constants:
+        uniform vec4 color1;
+        uniform vec4 color2;
 
         vec4 lovrmain() {
+          // Apply a vertical gradient using the 2 colors from the uniforms:
           return mix(color1, color2, dot(Normal, vec3(0, 1, 0)) * .5 + .5);
         }
       ]])
@@ -451,17 +457,12 @@ from Lua using `Pass:send`:
 
     function lovr.draw(pass)
       pass:setShader(shader)
-
       pass:send('color1', { 1, 0, 1, 1 })
       pass:send('color2', { 0, 1, 1, 1 })
-
       pass:sphere(0, 1.7, -2)
     end
 
-The vertex and fragment stages share the constants block, so they should match or one should be a
-subset of the other.
-
-When the active shader is changed, constants will be preserved.
+When the active shader is changed, uniforms with the same name and type will be preserved.
 
 ### Vertex Attributes
 
@@ -500,28 +501,22 @@ the following default vertex attributes for shapes and meshes:
     </tr>
     <tr>
       <td>VertexTangent</td>
-      <td>vec3</td>
+      <td>vec4</td>
       <td>14</td>
     </tr>
   </tbody>
 </table>
 
-Custom vertex attributes can be declared for locations 0 through 9:
+Custom vertex attributes can be declared like this:
 
-    layout(location = 3) in vec3 customAttribute;
+    in vec3 customAttribute;
 
-The data in a buffer can then be associated with the attribute, either by name:
+The data in a buffer can then be associated with the attribute, by name:
 
     vertices = lovr.graphics.newBuffer(vertexCount, {
       { type = 'vec3', name = 'customAttribute' }
     })
 
-Or by location:
-
-    vertices = lovr.graphics.newBuffer(vertexCount, {
-      { type = 'vec3', location = 3 }
-    })
-
 ### Buffers
 
 Shaders can access data in `Buffer` objects.  Buffers can store large arrays of data from Lua tables
@@ -534,22 +529,20 @@ Data in buffers can be accessed in 2 ways:
 
 First, the buffer should be declared in the shader.  Here's an example declaring a uniform buffer:
 
-    layout(set = 2, binding = 0) uniform Colors {
+    uniform Colors {
       vec4 colors[100];
     };
 
 And an example storage buffer:
 
-    layout(set = 2, binding = 0) buffer Colors {
+    buffer Colors {
       vec4 colors[100];
     };
 
-The first part declares the set and binding of the variable.  Right now the set should always be 2
-(LÖVR uses set 0 and 1 internally).  The binding is a number that can be used to identify the
-variable.  After that, `uniform` or `buffer` is used to declare which type of buffer it is, followed
-by the name of the variable.  Finally, there is a block declaring the format of the data in the
-buffer, which should match the format used to create the Buffer in Lua (structs can be used if the
-buffer has multiple fields per element).
+First the `uniform` or `buffer` keyword is used to declare which type of buffer it is, followed by
+the name of the variable.  Finally, there is a block declaring the format of the data in the buffer,
+which should match the format used to create the Buffer in Lua (structs can be used if the buffer
+has multiple fields per element).
 
 A Buffer can be sent to one of the above variables like this:
 
@@ -561,6 +554,9 @@ A Buffer can be sent to one of the above variables like this:
 
 The shader can then use the `colors` array to access the data from the `palette` table.
 
+There is a very handy `Shader:getBufferFormat` method that will return a Buffer format from a
+variable in a shader, so you don't have to duplicate it in the Lua code.
+
 It's possible to bind a subset of a buffer to the shader by passing the range as extra arguments to
 `Pass:send`.
 
@@ -569,19 +565,19 @@ It's possible to bind a subset of a buffer to the shader by passing the range as
 Shaders can also access data from `Texture` objects.  Similar to buffers, textures can be accessed
 in 2 ways:
 
-- Sampled textures are read-only, and can use `Sampler` objects.
-- Storage textures can be written to using compute shaders.
+- **Sampled** textures are read-only, and can use `Sampler` objects.
+- **Storage** textures can be written to using compute shaders.
 
 Sampled textures are declared like this:
 
-    layout(set = 2, binding = 0) uniform texture2D myTexture;
+    uniform texture2D myTexture;
 
 The texture type can be `texture2D`, `textureCube`, `texture2DArray`, or `texture3D` (see
 `TextureType`).
 
 Storage textures are declared like this:
 
-    layout(set = 2, binding = 0) uniform image2D myImage;
+    uniform image2D myImage;
 
 A texture can be sent to the shader variable using `Pass:send`.
 
@@ -596,7 +592,7 @@ This will sample from the texture using the UV coordinates and the default sampl
 
 It's also possible to declare a custom sampler variable and use it to sample textures:
 
-    layout(set = 2, binding = 0) uniform sampler mySampler;
+    uniform sampler mySampler;
 
     // texture(sampler2D(myTexture, mySampler), UV)
 

+ 6 - 6
showcase/Break/shader.lua

@@ -1,9 +1,9 @@
 return lovr.graphics.newShader([[
 
 // All of these are in view-space.
-layout(location = 0) out vec3 lightDirection; // A vector from the vertex to the light
-layout(location = 1) out vec3 normalDirection;
-layout(location = 2) out vec3 vertexPosition;
+out vec3 lightDirection; // A vector from the vertex to the light
+out vec3 normalDirection;
+out vec3 vertexPosition;
 
 const vec3 lightPosition = vec3(0, 10, 3);
 
@@ -18,9 +18,9 @@ vec4 lovrmain() {
   return DefaultPosition;
 }
 ]], [[
-layout(location = 0) in vec3 lightDirection;
-layout(location = 1) in vec3 normalDirection;
-layout(location = 2) in vec3 vertexPosition;
+in vec3 lightDirection;
+in vec3 normalDirection;
+in vec3 vertexPosition;
 
 const vec3 cAmbient = vec3(.25);
 const vec3 cDiffuse = vec3(1);

Some files were not shown because too many files changed in this diff