Search code examples
openglglslshaderfragment-shader

Modify scale of texture in GLSL shader based on input


I've created a shader that uses a texture (cursorTex) to show a mouse cursor, and draws it onto a fullscreen texture (bgTex). I'm moving the cursor texture so that the center of the image is positioned on my mouse cursor. I'm designing the cursor for a trackpad that can detect pressure, and am able to adjust the opacity based on the amount of pressure:

cursorColor.rgb *= clamp(.5 - pressure, 0.0,1.0);

Now, I'm trying to also change the scaling of the cursor based on the amount of pressure, so that it shrinks to 50% it's original size if the pressure is 1.0, and stays at its original size if the pressure is 0.0.

I'm having trouble figuring out how to only scale the cursor texture based on the pressure uniform while also retaining its original aspect ratio, and also offsetting it to center on the mouse cursor (half it's original width and height). Below is my full shader code.

// Set the precision
precision highp float;

uniform float time;                 // Time uniform variable
uniform vec2 mouse;                 // Mouse position uniform variable

uniform sampler2D cursorTex;        // Texture sampler for the cursor image
uniform sampler2D bgTex;            // Texture sampler for the background image

uniform vec2 cursorSize;            // Size of the cursor image
varying vec2 vTexCoord;             // Interpolated texture coordinates

uniform float pressure;            // Pressure applied to touchpad/ mouse


void main() {
  vec2 uv = vTexCoord.st;
  // Flip the texture coords
  uv.y = 1.0 - uv.y;

  vec2 texture1Size = vec2(500.0, 500.0);
  vec2 texture2Size = vec2(1080.0, 1920.0);

  // Calculate the cursor position based on the mouse position
  vec2 cursorPosition = mouse;

  // Offset to center on the cursor position
  vec2 texture1Offset = cursorPosition / texture1Size;

  // Color of the cursor image at the adjusted texture coordinates
  vec4 cursorColor = texture2D(cursorTex, uv / (texture1Size / texture2Size) - texture1Offset);
  
  // Modify cursor opacity based on mouse pressure
  cursorColor.rgb *= clamp(.5 - pressure, 0.0,1.0);

  // Color of the background image at the original texture coordinates
  vec4 bgColor = texture2D(bgTex, uv);

  vec4 finalColor = cursorColor + bgColor;

  // Handle clipping if UV coordinates go beyond the texture bounds
  if (uv.x >= 1.0 || uv.y >= 1.0) {
    finalColor = bgColor;
  }

  gl_FragColor = finalColor;    // Set the final fragment color
}


Solution

  • This would be done in the vertex shader, if you post the vertex shader I can help, but here is the basic idea. You scale the position attribute with vec2 pos = Pos * (1 - pressure * 0.5f), scale it by cursorSize and then translate the object to the mouse position.

    // example position attribute
    layout (location = 0) in vec2 Pos;
    
    uniform vec2 mouse;                 // Mouse position uniform variable
    
    uniform vec2 cursorSize;            // Size of the cursor image
    
    uniform float pressure;            // Pressure applied to touchpad/ mouse
    
    void main() {
    
      // scale it by pressure
      vec2 pos = Pos * (1 - pressure * 0.5f);
    
      // scale it by cursorSize (ordering of this and pressure scaling might be reversed)
      pos *= cursorSize;
    
      // move to cursor position
      pos += mouse;
    
      gl_Position = vec4(pos, 0.0, 1.0);
    }