Glsl rotation without squishing the shape

Hello, got quite a few more unsolved problems, hope your brilliant brain will help me to perfect my project!
I’m drawing a grid of rectangles in glsl using fract(st) and then rotating those rectangles. Everything works perfect when the height and width of each st square is equal but I want be able to have a grid of lets say 3 by 5 so each st become squished hence the rectangles get squished when I rotate it. Is there any way to avoid this?


uniform float time;

//rotate function
mat2 rotate(float _angle){
    return mat2(cos(_angle),-sin(_angle),

//rectangle function
float rect(vec2 _st, vec2 _size){
  vec2 uv = smoothstep(_size, _size + vec2(1e-4), _st);
  uv *= smoothstep(_size, _size + vec2(1e-4), vec2(1.0)-_st);    
  return uv.x*uv.y;   

out vec4 fragColor;
void main()
	vec2 st =;
	vec3 color = vec3(0.);
  //number of rows and columns in the grid
  vec2 grid = vec2(5.0, 3);
	st = st * grid;
  //I assume I need ti adjust something here to prevent squishing
	st = fract(st);

  vec2 size = vec2(0.4, 0.2);

	st -=0.5;
	st = rotate(time*0.01)*st;
	st +=0.5;

  color += rect (st, size);

//adding color background to see the edges of each st
	color.r += st.x;
  color.b += st.y;

	fragColor = TDOutputSwizzle(vec4( color, 1));

Hi there!

The problem is in the aspect ratio of your cells.
In the start of your shader the uv (st) coordinates go from 0 to 1, then you scale those so uv.x goes from 0 to 5… fract(st) removes the integer part so you’ll end up with 5 rows going from 0 to 1. Though the uv.y is scaled only by 3 and also goes from 0 to 1 (however covering maybe less or more pixels than the x-axis).
It depends on your output resolution and the amount of cells (the ‘grid’ scale vec2). To calculate this, you would first need to move your cell uv coordinate in way that you scale it from the center (similar like you did with the rotation, substracting 0.5)… then multiplying with the correct aspect ratio… and then moving 0.5 back again. This should be done after the fract(st), since it’s the aspect ratio of the cells you want to change.

So something like this:

st = fract(st);
vec2 res = / grid;
st.x = (st.x-0.5)*res.x/res.y + 0.5;

Might feel a bit awkward to find the right aspect ratio, first you need to know the resolution of a cell which is the output resolution divided by the amount of cells (f.e. 1920/5 and 1080/3)… Then depending on if you want to keep the x axis intact or the y axis, you update the other one. (in this example I keep the y axis intact). This is similar to ‘fit horizontal’ and ‘fit vertical’ in the fitTOP. If you want to have a ‘fit best’ you would need to check if the res.x > res.y to see which one fits better.

Hope this helps a bit.

this is brilliant, works perfectly! Thanks so much Tim!