Is it possible to edit the Y Scale for just the left or right side of a sprite?
I'm trying to create a perspective effect.

  • xyz replied to this.
  • BlueJellyCat Not from the editor because the third column of the 2d transformation matrix which would let you fake it is not accessible.

    However, anything is possible from the vertex shader. To move two upper points of a sprite vertically, simply do:

    void vertex(){
    	float y1 = -64.0;
    	float y2 = -32.0;
    	VERTEX.y += y1 * step(.5, VERTEX.x) * step(VERTEX.y, .5);
    	VERTEX.y += y2 * step(VERTEX.x, .5) * step(VERTEX.y, .5);
    }

    You can even do full 3d perspective projection. Simply add skip_vertex_transform to shader's render mode, do modelview matrix multiplication manually, and multiply the vertex again with a custom projection matrix. Since sprite's unavoidable built in projection is orthographic, it shouldn't interfere with your custom projection. If it does, you can just multiply with shader's inverse projection matrix as a last step to nullify it.

    BlueJellyCat Not from the editor because the third column of the 2d transformation matrix which would let you fake it is not accessible.

    However, anything is possible from the vertex shader. To move two upper points of a sprite vertically, simply do:

    void vertex(){
    	float y1 = -64.0;
    	float y2 = -32.0;
    	VERTEX.y += y1 * step(.5, VERTEX.x) * step(VERTEX.y, .5);
    	VERTEX.y += y2 * step(VERTEX.x, .5) * step(VERTEX.y, .5);
    }

    You can even do full 3d perspective projection. Simply add skip_vertex_transform to shader's render mode, do modelview matrix multiplication manually, and multiply the vertex again with a custom projection matrix. Since sprite's unavoidable built in projection is orthographic, it shouldn't interfere with your custom projection. If it does, you can just multiply with shader's inverse projection matrix as a last step to nullify it.

      Here's the full perspective projection of a 2d sprite I was mentioning above:

      shader_type canvas_item;
      render_mode skip_vertex_transform;
      
      void vertex(){
      	// model rotation/translation matrix
      	float a = TIME; // rotation angle
      	mat4 model_matrix = mat4(
      		vec4(cos(a), 0.0, sin(a), 0.0),
      		vec4(0.0, 1.0, 0.0, 0.0),
      		vec4(-sin(a), 0.0, cos(a), 0.0),
      		vec4(0.0, -3.0, -400.0, 1.0) // translation
      	);
      	
      	// perspective projection matrix
      	float near = .015;
      	float far = 1000.0;
      	float fov = .3;
      	mat4 proj_matrix = mat4(
      		vec4(1.0/tan(fov/2.0), 0.0, 0.0, 0.0),
      		vec4(0.0, 1.0/tan(fov/2.0), 0.0, 0.0),
      		vec4(0.0, 0.0, far/(far-near), -far*near/(far-near)),
      		vec4(0.0, 0.0, 1.0, 0.0)
      	);	
      
      	// transform and project vertex
      	vec4 v = proj_matrix * model_matrix * vec4(VERTEX, 0.0, 1.0);
      	// perspective divide
      	VERTEX = v.xy / v.w;
      }

        xyz This rotation effect is exactly what I was trying to do.
        Do you think you could break this down for me a bit, so I can understand it better?
        I just tried implementing it in my game, but now the object is stuck in the top left corner and the scale was changed from 3 to 1.

        • xyz replied to this.

          BlueJellyCat Why not just use 3d if you need it to look 3d?

          My second example was just to demonstrate it's possible to do full mathematically correct projection of a 2d sprite. To understand what it does you need to be familiar with basics of linear algebra, at least the parts that are important in 3d graphics, like vectors and transformation/projection matrices. It's just too broad of a topic to get into here and there are plenty of quality resources around the web.

          In short, the shader constructs two transformation matrices and multiplies positions of sprite's vertices with them to transform those vertices first from 2d screen space to 3d space, and then from 3d space to perspective projected space (which is again 2d).