Shader: efek cahaya
Uji coba apakah shader berfungsi
Umum
Meskipun saya memberi game ini nuansa retro tertentu, saya tetap ingin memakai shader.
Di video di bawah ini kamu bisa melihat saya bereksperimen dengan efek cahaya. Kalau diperhatikan baik-baik, saya berjalan menembus cahaya dan pemain juga ikut terpengaruh oleh efeknya.
Termasuk shader yang bergerak, misalnya untuk obor yang nanti kita butuhkan di petualangan ini.
Desain
Kalau harus saya gambarkan sebagai skema, kira-kira seperti ini, hanya saja sayangnya membuatnya jauh lebih rumit.

Skema shader
Dari pengalaman, di love2d tidak mungkin merender beberapa shader dalam draw loop yang sama. Ini tidak bisa, dan saya baru tahu setelah satu shader berhasil jalan dan saya ingin mengaktifkan shader kedua.
shader1 = love.graphics.newShader('color-dodge.glsl')
shader2 = love.graphics.newShader('color-dodge.glsl')
function love.draw()
love.graphics.push("all")
love.graphics.setCanvas(src)
love.graphics.clear()
love.graphics.setShader()
love.graphics.draw(scene, 0, 0)
love.graphics.draw(player, playerPos.x, playerPos.y)
love.graphics.setShader(shader1)
love.graphics.setShader(shader2)
love.graphics.setCanvas()
love.graphics.setShader()
love.graphics.draw(src, 0, 0)
end
Untungnya ada solusi untuk masalah ini, yaitu rendering multi-pass. Intinya, hasil yang kamu gambar ke canvas ditulis ulang ke canvas lain, lalu shadernya digambar. Ini bisa diulang untuk beberapa shader.
Fungsi di bawah ini untuk sekarang berjalan baik, meskipun masih harus saya uji lebih jauh.
function Engine3:applyIntermediateShader(shader)
if not shader then return end
local src = self.canvas:getCanvas()
local front = self.canvas:getCanvasFront()
-- Store current graphics state
local currentCanvas = love.graphics.getCanvas()
local currentShader = love.graphics.getShader()
-- Apply shader: src -> front
love.graphics.push("all")
love.graphics.origin()
love.graphics.setCanvas(front)
love.graphics.clear()
love.graphics.setShader(shader:getShader())
love.graphics.draw(src, 0, 0)
love.graphics.setShader()
love.graphics.pop()
-- Copy result back to main canvas: front -> src
love.graphics.push("all")
love.graphics.origin()
love.graphics.setCanvas(src)
love.graphics.clear()
love.graphics.draw(front, 0, 0)
love.graphics.pop()
-- Restore graphics state for continued rendering
love.graphics.setCanvas(currentCanvas)
love.graphics.setShader(currentShader)
end
Shader Color Dodge
Di desain Photoshop dan Aseprite saya memakai filter color dodge.

Color Dodge di Photoshop
Jadi di game dan editor saya harus menirunya dengan suatu cara.

Pemilih shader di editor
Saya hampir tidak memakai AI untuk memprogram selama mengembangkan game ini. Tapi kadang saya tahu bahwa ini bagian kecil yang belum saya kuasai dan bisa saya pakai sebagai titik awal. Jadi saya meminta dibuatkan shader glsl bernama ‘Color Dodge’ yang sama dengan yang dilakukan Photoshop.
Tentu saja itu tidak langsung berhasil, karena koordinat yang saya pakai berbeda dan saya juga memakai scaling dan hal lain. File glsl akhirnya saat ini seperti ini.
extern vec2 position;
extern Image image;
extern float scale;
extern float overlayIntensity;
extern vec4 quadRect;
vec3 colorDodge(vec3 base, vec3 blend) {
return vec3(
blend.r >= 0.999 ? 1.0 : min(1.0, base.r / max(0.001, 1.0 - blend.r)),
blend.g >= 0.999 ? 1.0 : min(1.0, base.g / max(0.001, 1.0 - blend.g)),
blend.b >= 0.999 ? 1.0 : min(1.0, base.b / max(0.001, 1.0 - blend.b))
);
}
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc)
{
vec4 base = texture(tex, tc);
vec2 texSize = vec2(textureSize(image, 0));
vec2 qpos = quadRect.xy;
vec2 qsize = quadRect.zw;
vec2 uv = (sc - position) / (qsize * scale);
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
return base;
}
uv = (uv * qsize + qpos) / texSize;
vec4 overlay = texture(image, uv);
if (overlay.a > 0.0) {
vec3 enhancedOverlay = min(vec3(1.0), overlay.rgb * overlayIntensity);
vec3 dodged = colorDodge(base.rgb, enhancedOverlay);
float enhancedAlpha = min(1.0, overlay.a * overlayIntensity);
vec3 result = mix(base.rgb, dodged, enhancedAlpha);
return vec4(result, base.a);
}
return base;
}
Di class shader, saya meneruskan Frameset dan efek yang dipilih ke shader.
if frameset then
self:setImage(frameset.resource)
self:setScale(nil, true)
self:setPosition(frameset:getFrameX(), frameset:getFrameY(), true)
if frameset:getQuad() then
self:setQuad(frameset:getQuad():getViewport())
end
end
Penutup
Saya berhasil membawa color dodge dari Photoshop ke dalam game, tapi masih harus mencoba hal lain seperti bayangan dan kombinasi sistem partikel untuk api dengan efek shader.
Tetap saja menurut saya ini perlu supaya semuanya terlihat sedikit lebih indah. Untungnya filter glsl juga bisa ditemukan di berbagai situs web, jadi saya tidak perlu membuat semuanya dari nol.