Shaders are only for 3D objects, right?
If I apply a shader when I’m drawing some things using ellipse()
for example, the shaders not gonna affect those ellipses, right?
In order to apply a shader to 2D art, I’d have to draw that art to a texture that was on a mesh, is that correct?
Found something here by the esteemed @Ignatz, praise be his name!
Below is my effort to generalize it into code that can be used as a dependency by anyone.
I can’t say it’s robustly tested, but I can say it’s currently working as a dependency in my own projects.
I hope it’s of help to the next traveler this way…
--# Main
--Shader2D
--A way to apply (possibly any) 3D shaders to 2D drawing environments
--can be used in (possibly any) other projects as a dependency, by following the instructions below
function setup()
--your setup function needs two things
--1: call Shader2D.setup() with the shader, your 2Ddrawing function, and a shader updater
--2: setup up any initial values your shader needs *directly on the Shader2D*
Shader2D.setup(shader("Effects:Ripple"), draw2DsStuff, shaderUpdates)
Shader2D.mesh.shader.freq = 2
end
function draw()
-- you already passed your 2D drawing function to Shader2D, so in this function just call:
Shader2D.draw()
end
function draw2DsStuff()
--an example of a 2D drawing function
background(40, 40, 50)
strokeWidth(5)
fill(214, 226, 116, 255)
spriteMode(CORNER)
sprite("Cargo Bot:Game Area", 0, 0, WIDTH, HEIGHT)
ellipse(WIDTH/2,HEIGHT/2,HEIGHT/3)
end
function shaderUpdates()
--a sample updater: this is what the ripple shader needs every frame
Shader2D.mesh.shader.time = ElapsedTime
end
--# CustomFunctions
Shader2D = {}
function Shader2D.setup(thisShader, this2DDrawer, thisShaderUpdater)
--creates the mesh and its texture and defines the drawing functions
Shader2D.screen = image(WIDTH,HEIGHT)
Shader2D.mesh = mesh()
Shader2D.mesh:addRect(0,0,WIDTH,HEIGHT)
Shader2D.mesh.shader = thisShader
Shader2D.mesh.texture = Shader2D.screen
Shader2D.draw2D = this2DDrawer
Shader2D.updateShader = thisShaderUpdater
end
function Shader2D.draw()
--draws the stored 2D drawing function to the mesh texture
setContext(Shader2D.screen)
Shader2D.draw2D()
setContext()
translate(WIDTH/2,HEIGHT/2)
--updates the shader and draws the mesh
if Shader2D.updateShader ~= nil then
Shader2D.updateShader()
end
Shader2D.mesh:draw()
end
Shaders are applied to meshes. Meshes can be displayed in 2D or 3D. 2D is orthogonal projection, with all the objects as planes perpendicular to the camera. Codea’s addRect
/ setRect
API is the best way to display meshes in 2D.
You can’t as far as I know, apply a shader to the 2D primitive drawing commands (ellipse etc). Partly, this is because I believe the ellipse itself is drawn with a shader.
@UberGoober Looking over your posted code, am I right in thinking that it’s setting up a full screen mesh, drawing the 2D operations onto the mesh, and then applying the shader to that mesh?
@mindless that’s correct, I think. It’s not my code originally but that’s what it looks like to me too.
@yojimbo2000 I don’t know anything about addRect/setRect
, I’ll have to look into that. As far as applying shader to an ellipse()
command, I believe that’s what this code does. If you run it, it draws an ellipse and then puts a ripple on it.
Anything that’s drawn on the mesh texture is modified by the shader. Shader2D.screen is an image the size of the screen. The sprite Cargo Bot:Game area is drawn on it along with an ellipse.
Yes that’s the point, this is a modular pre-rolled solution that lets you keep all your existing 2D drawing and easily lay a shader on top of it. It handles the 3D part for you, almost all you need to do is pick a shader and rename your existing draw function.