[Question] Using shader to stretch quads

So I’m working on a 2D game where I have entities (tiles that move) and I’m try to generate shadows using a shader. The problem is, I don’t know how to manipulate vertices so that the quads I’m sending to the shader can be stretched/squished to be about 20% of the original height and to flip vertically. It seems I would have to do 3 operations: Dilate in the Y direction, Rotate 180 degrees CW, then Translate 1 unit right. I’m just not sure how to do that using GLSL. I’m using LibGDX to handle GL and have a very basic shader program that renders everything normally.

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;

varying vec4 v_color;
varying vec2 v_texCoords;

void main() {
    v_color = a_color;
    v_texCoords = a_texCoord0;
    gl_Position = u_projTrans * a_position;

And Frag:

#ifdef GL_ES
    precision mediump float;

varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;

void main() {
  gl_FragColor = v_color * texture2D(u_texture, v_texCoords);

The above renders everything normally but I wanna feed the shader my entities and spit out shadows.

The calculation is simple enough; the awkward part is getting the data. Presumably each quad is supposed to be vertically scaled (by a factor of -0.2) about a point that varies between quads. So you’re going to need to pass that information somehow.

If the scaling origin is always at one edge of the quad you could use a geometry shader, as that has access to all of the vertices. But there’s a significant performance cost for using a geometry shader (at least on AMD and Nvidia, less so on Intel). The other option is to add an extra attribute, which would need to be replicated for all four vertices of the quad.

Also: you probably want vertical reflection, not 180° rotation (as that’s equivalent to both vertical and horizontal flips).

If the screen position for the main sprite is [x,y0+dy], the shadow position is [x,y0-0.2*dy], where y0 is the screen-space Y coordinate of the ground plane immediately below the sprite (which will be the Y coordinate of the bottom edge of the sprite if it’s standing on the ground) and dy is the height (in screen space) above the ground.

If all shadows are cast on a common ground plane, possibly the simplest option is to render your scene in 3D using an oblique projection, with sprites as cardboard cut-outs. For the original sprite, the screen position is [x,y+z], for shadows it’s [x,-0.2*y+z]. This assumes that +Y is up, +Z is away from the viewer.

Note that for a vertical sprite, either y0 or z will be the same for all four vertices.

I was thinking about it when I went to bed last night, I can send in a “uniform” that contains the vertex that doesn’t move and compare it to the current vertex that’s being manipulated to see which point is being handled. I’ll try this in a few.