In this post, I'll be sharing my ongoing notes on writing GLSL shaders, insights into SparkSL Shaders, and tips on converting GLSL to SparkSL shaders.
Using shaders in Spark AR can be a game changer, allowing you to move away from static textures towards more dynamic artworks.
GLSL Shaders
Tutorials:
Helpful Links:
SparkSL Shaders
Getting Started:
Always save the Spark AR Project before starting a new shader, else you'll have to re-initiate the file.
Tutorials:
Helpful Links:
Converting GLSL shaders into SparkSL
Getting Started:
Always save the Spark AR Project before starting a new shader, else you'll have to re-initiate the file.
Tutorials:
Helpful Links:
Conversions:
Convert define into declarations (with 'const') or functions. SparkSL does not use #define.
iResolution:
Add ‘using namespace std;’ at the beginning of the code
Replace ‘iResolution’ with ‘getRenderTargetSize()’
iTime:
Add ‘using namespace std;’ at the beginning of the code
Replace ‘iTime’ with 'getTime()'
To convert a screen shader to fit a 3D object:
Best to refer to the Vertex shader section by Adam Ferris
Instead of using 'fragCoord', you can directly calculate UVs
The 'position' is also returned in this method
// SparkSL has built in functions for accessing the transform matrices and vertex attributes vec4 Position = getModelViewProjectionMatrix() * getVertexPosition(); // By default vertex attributes or calculations will happen in the vertex shader // You can force a calculation to the fragment shader by surrounding the function with fragment() vec2 uv = fragment(getVertexTexCoord()); |
texture():
In SparkSL, each texture has .sample() as part of its member functions.
We also need to pass in the function as a uniform via the parameters in the main function declaration
vec4 main(std::Texture2d myTex){ vec2 uv = fragment(std::getVertexTexCoord()); vec4 color = myTex.sample(uv) ; return color;} |
Eg. to replace texture here:
float lookup(vec2 p, float dx, float dy){ vec2 uv = (p.xy + vec2(dx d, dy d)) / iResolution.xy; vec4 c = texture(iChannel0, uv.xy); // return as luma return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;} |
I added a ‘Texture2d myTex’ in the function declaration and replaced ‘texture’ and ‘iChannel0’ (which is the name of the texture), by myTex.sample(uv.xy) - keeping the uv input the same.
Updated:
float lookup(Texture2d myTex, vec2 p, float dx, float dy){ vec2 uv = (p.xy + vec2(dx d, dy d)) / getRenderTargetSize().xy; vec4 c = myTex.Sample(uv.xy); // return as luma return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;} |
‘const’:
Add ‘const’ before all the declarations outside the functions.
'mat2':
There is only mat4 in SparkSL. Use ChatGPT to convert it.
Update ‘in’ and ‘out’ sequence in main()
Remove the out parameter and put it before the ‘main()’ instead of void. There can be only one output.
Anything in the brackets after ‘main’ is input. It does not need the ‘in’ word. There can be multiple inputs.
Eg.
vec4 main(std::Texture2d tex, float test){} |
fragCoord:
Remove ‘fragCoord’ from the ‘in’ part of void main, if present
Read the fragCoord section from Adam Ferris’s Github if needed
In a fullscreen shader you can use:
vec2 fragCoord = fragment(floor(std::getRenderTargetSize() * std::getVertexTexCoord())); |
UV coordinates:
To output the UV’s to debug-
using namespace std;vec4 main(){vec2 uv = getVertexTexCoord(); return vec4(uv, 0.0, 1.0);} |
Texture coordinates are (0.0, 0.0) where there is black
Refer to: UV Coordinates for Spark AR & GLSL
fragment():
What fragment() is doing is it's telling the Shader that I want to use this value only in the fragment Shader.
Shaders come in pairs - they come in a Vertex Shader and a Fragment Shader. The Vertex shader manipulates the vertices, puts them on the screen and the Fragment shader manipulates the pixels and changes the actual colour of things.
You can optimise your shaders sometimes by doing computation within the vertex Shader. It only executes for each vertex rather than for each pixel but in our case we actually need to execute for each pixel and so we need to move this computation into the fragment Shader and we can do that with this fragment function.
So it's really important to remember this - if you don't do it you might see some kind of weird artefacts when you try and sample your textures.
Comments