How would you apple a blur shader to an ellipse? Doing it to a rectangle is easy enough. Write screen to image, Apple shader, draw, but for a circle you’d have to write part of the screen to a circle, but not have it distorted, then apply a shader. Not sure how I would go about doing this.
I would write a mask shader that takes two textures, 1 the image to be drawn, as usual (ie the blurred image), and the second texture a mask to draw it with, eg in this case a white circle on a transparent background
Voila!
-- Mask Shader
-- by Yojimbo2000
function setup()
centre = vec2(WIDTH, HEIGHT)/2
--make blur image
local imgBlur = readImage("Cargo Bot:Starry Background")
w,h = imgBlur.width, imgBlur.height
local img1 = image(w ,h)
local mBlur = mesh()
mBlur.shader = shader("Filters:Blur")
mBlur.shader.conPixel = vec2(1,1)/200
mBlur.shader.conWeight = 1/9
mBlur.texture = imgBlur
mBlur:addRect(w*0.5,h*0.5,w,h)
setContext(img1)
mBlur:draw()
--make mask image
local img2 = image(w, h)
local falloff = 50 --how thickly to feather the edges of the mask
setContext(img2)
noStroke()
local diameter = math.min(w,h)
local alpha = 255/ falloff
for i = 1, falloff do
fill(255,i*alpha) --grey value = brightness, alpha = opacity
ellipse(w*0.5,h*0.5,diameter - i) --or whatever drawing you want your mask to be
end
setContext()
--build mesh
m = mesh()
m.shader = shader(maskShader.vert, maskShader.frag)
m.texture = img1
m.shader.texture2 = img2 --nb note texture2 has to be set differently
m:addRect(centre.x, centre.y, w, h)
pos = vec2(50, centre.y) --some animation
tween(5, pos, {x=WIDTH-50}, {easing = tween.easing.sineInOut, loop = tween.loop.pingpong})
end
function draw()
background(40, 40, 50)
sprite("Cargo Bot:Game Area", centre.x, centre.y)
m:setRect(1,pos.x,pos.y,w,h)
m:draw()
end
maskShader={
vert=[[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
// varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
// vColor = color;
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
frag=[[
precision highp float;
uniform lowp sampler2D texture;
uniform lowp sampler2D texture2;
//varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
lowp vec4 col = texture2D( texture, vTexCoord ) * texture2D( texture2, vTexCoord );
gl_FragColor = col;
}
]]
}
Thanks!
Hmmm, seem to be having more problems implementing it. For some reason, the mask never masks. Here’s a little demo I made showing the problem. I create two images, the background and the mask shape, as well as a mesh with the shader applied, set the image variables to the mesh and draw it, but the shape doesn’t draw correctly. Here’s the code. Thanks!
--# Main
function setup()
--Creates background image (codea icon) and Circle image for mask
image1=image(WIDTH,HEIGHT)
circle=image(WIDTH,HEIGHT)
--Makes mesh for mask, applies shader and adds a rectangle to it
c=mesh()
c:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
c.shader=shader(MS.vertexShader,MS.fragmentShader)
--loads codea logo to image1
setContext(image1)
sprite("Cargo Bot:Codea Icon",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
setContext()
--creates a circle for the mask image
setContext(circle)
fill(255, 255, 255, 255)
ellipse(WIDTH/2,HEIGHT/2, math.min(WIDTH,HEIGHT)/1.5)
setContext()
--sets mesh textures
c.texture=image1
c.texture2=circle
end
function draw()
--draws image
background(0, 0, 0, 255)
c:draw()
end
--# Shader
--shader roughly based from ignatz's on coolcodea and yojimbo2000s
MS={
vertexShader=[[
//
// A basic vertex shader
//
//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;
//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
//Pass the mesh color to the fragment shader
vColor = color;
vTexCoord = texCoord;
//Multiply the vertex position by our combined transform
gl_Position = modelViewProjection * position;
}
]],
fragmentShader=[[
//
// A basic fragment shader
//
//Default precision qualifier
precision highp float;
//This represents the current texture on the mesh
uniform lowp sampler2D texture;
uniform lowp sampler2D texture2;
//The interpolated vertex color for this fragment
varying lowp vec4 vColor;
//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;
void main()
{
//Sample the texture at the interpolated coordinate
lowp vec4 col = texture2D( texture, vTexCoord );
lowp vec4 col2 = texture2D(texture2, vTexCoord) ;
//Set the output color to the texture color
if (col2.a>0.) gl_FragColor = col; else discard;
}
]]
}
Texture 2 must be defined as c.shader.texture2
(whereas texture1 is c.texture
) as there is only a built-in slot for 1 texture.
Thank you! I would’ve never gotten that on my own.