Scaling a shader centered at the mouse point

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
progress
Prole
Posts: 4
Joined: Sat Mar 04, 2023 12:20 pm

Scaling a shader centered at the mouse point

Post by progress »

I'm working with shaders in my project to get a more interesting background than flat colour. Ideally, these shaders will remain in a logical position and scale when I manipulate the camera (using StalkerX: https://github.com/a327ex/STALKER-X).

I'm new to GLSL and after following a YouTube tutorial I created this shader that uses perlin noise to make a cool, pixellated water effect for the background: https://pastebin.com/Z7bMRq67

I then put this in the project and draw it as a background. I send time using love.time.getTime() and the other two in my code.

When the player drags the mouse around, I move the offset variable using this code (self refers to the current game 'board'):

Code: Select all

if input:down('mouse1') then
        mouse_pos(self.parent.camera) -- https://pastebin.com/qmfLiG0N
        local x, y = (self.camera_lock[1] - mouse.x), (self.camera_lock[2] - mouse.y)
        shader_offset[1] = shader_offset[1] + x
        shader_offset[2] = shader_offset[2] + y
        self.camera.x = self.camera.x + x/self.camera.scale
        self.camera.y = self.camera.y + y/self.camera.scale
        self.camera_lock = {mouse.x, mouse.y}
    end
self.parent.camera refers to a camera that is just the size of the window and never changes. This code works well and the shader moves along with all the other contents drawn with the camera without going too fast or too slow. However, the issue lies in updating the zoom of the camera and thus the shader. For that I use this code:

Code: Select all

function Board:wheelmoved(dx, dy)
    dy = math.sign(dy) * math.min(math.abs(dy), 2)
    mouse_pos(self.camera)
    local mx, my = mouse.x, mouse.y
    local scale_limit = {out = 0.14, inn = 0.65}
    if (self.camera.scale > scale_limit.out or dy > 0) and (self.camera.scale < scale_limit.inn or dy < 0) then
        self.camera.scale = self.camera.scale + dy/50
        self.camera.x = self.camera.x + (mx - self.camera.x) * dy/50 / self.camera.scale
        self.camera.y = self.camera.y + (my - self.camera.y) * dy/50 / self.camera.scale

        shader_zoom = shader_zoom + dy/50
        shader_offset[1] = shader_offset[1] + (mx - shader_offset[1]) * dy/50 / shader_zoom
        shader_offset[2] = shader_offset[2] + (my - shader_offset[2]) * dy/50 / shader_zoom
    end
end
I copied the code I'm using for the camera scaling to just update shader_zoom and shader_offset, but it doesn't work at all. This is resulting in the offset moving too far and becoming misaligned with the camera. I thought I'd be able to sort this out myself but I'm quite confused as to what's actually going on and why these effects are happening. Here's what it looks like in game: https://youtu.be/Sk2Y5r5v5qw

Some more points of knowledge that might be helpful is that the self.camera.scale starts at 0.5 and shader_zoom starts at 1. I don't see how this could have this effect though but it might have some impact I'm not noticing. Additionally the shader is updated in main.update(dt) each frame with these values and they're used as shown in the shader code.

Any help would be greatly appreciated!
RNavega
Party member
Posts: 389
Joined: Sun Aug 16, 2020 1:28 pm

Re: Scaling a shader centered at the mouse point

Post by RNavega »

A zoom is a scale operation, and if you want to scale something (like a UV coordinate) based on some point other than the origin, then you need to chain the operations carefully so the scale happens relative to that point.
So say you have a 2D space, with a point A somewhere and a point B somewhere. You want to scale A using B as the scale center. The operations would be something like:

Code: Select all

A = A - B -- Make A relative to B, so B becomes the origin of space.
A = A * zoom -- Zoom from that relative space.
A = A + B -- Undo the relative space, bringing A back to the scene space.
https://dirsig.cis.rit.edu/docs/new/aff ... _sequences

That's what the OX, OY parameters to love.math.newTransform are for, it's great: https://love2d.org/wiki/love.math.newTransform
I see in your shader this line here:

Code: Select all

    vec2 uv = (screen_coords + offset) / (love_ScreenSize.y * zoom);
Seems like the scale center right now is just the origin of the UV space (0, 0), not the mouse. So maybe sending in a Transform object to the shader (as a mat4 uniform, because shader:send(transform) plugs in naturally to that) with the OX,OY properly set up, as well as SX,SY, so the scale happens from that point that's not the origin.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 4 guests