3

To lighten the work-load on my artist, I'm working on making a bare-bones skeletal animation system for images. I've conceptualized how all the parts work. But to make it animate how I want to, I need to be able to skew an image in real time. (If I can't do that, I still know how to make it work, but it'd be a lot prettier if I could skew images to add perspective)

I'm using SFML, which doesn't support image skewing. I've been told I'd need to use OpenGL shaders on the image, but all the advice I got on that was "learn GLSL". So I figured maybe someone over here could help me out a bit.

Does anyone know where I should start with this? Or how to do it?

Basically, I want to be able to deforem an image to give it perspective (as shown in the following mockup)

enter image description here The images on the left are being skewed at the top and bottom. The images on the right are being skewed at the left and right.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Legacyblade
  • 335
  • 1
  • 5
  • 18
  • 1
    I'm not familiar with SFML. However, depending on what it is you are skewing, this can be very easy. If you need the whole scene rendered and then skewed, you'll have to learn how to render to texture. If you just need some stock texture you have skewed, then it's as simple as adjusting your texture matrix in your shader according to the skew transform matrix which someone else asked a question about here: http://stackoverflow.com/questions/673216/skew-matrix-algorithm For learning shaders, you should research how to write them here: http://www.lighthouse3d.com/tutorials/glsl-core-tutorial/ – zero298 Feb 07 '14 at 15:49
  • you do not need shaders to skew images. rendering to texture, and then position it should be enough – BЈовић Feb 07 '14 at 16:01
  • @BЈовић SFML can't position in 3 dimensions. So I'm not sure how I'd go about that. – Legacyblade Feb 07 '14 at 16:05
  • SFML is just creating a window. You need to do it in opengl – BЈовић Feb 07 '14 at 16:06
  • @BЈовић, do you have any tutorials on that you recommend? (yeah, I'm googling it too, but I'm assuming you know more about openGL than me, so you'd have a better idea of where to look) – Legacyblade Feb 07 '14 at 16:09
  • This here draws a textured quad: http://www.gamedev.net/page/resources/_/technical/opengl/opengl-texture-mapping-an-introduction-r947 Do that, and move the topmost vertices (defined with the `glVertex3f` calls) either a bit backwards in Z, or a bit more "together" in X, and done. – Damon Feb 07 '14 at 16:12
  • The images that you show don't look like actual skews, they look like they are direct rotation transforms. The first before after is rotation about the X axis and the second is rotation about the Y. Do you want affine or projective? – zero298 Feb 07 '14 at 16:41
  • @zero298, in photoshop, you can achieve the effect with the skew tool. So thus I thought it was skewing. I'm not sure what affine or projective mean though. However, it seems SFML has a built in quad class. So once I figure out how to properly map a texture to it, I'm going to add an answer to this with my code. – Legacyblade Feb 07 '14 at 17:16

2 Answers2

3

An example of how to skew a texture in GLSL would be the following (poorly poorly optimized) shader. Idealy, you would want to actually precompute your transform matrix inside your regular program and pass it in as a uniform so that you aren't recomputing the transform every move through the shader. If you still wanted to compute the transform in the shader, pass the skew factors in as uniforms instead. Otherwise, you'll have to open the shader and edit it every time you want to change the skew factor.

This is for a screen aligned quad as well.

Vert

attribute vec3 aVertexPosition;

varying vec2 texCoord;

void main(void){
   // Set regular texture coords
   texCoord = ((vec2(aVertexPosition.xy) + 1.0) / 2.0);

   // How much we want to skew each axis by
   float xSkew = 0.0;
   float ySkew = 0.0;

   // Create a transform that will skew our texture coords
   mat3 trans = mat3(
      1.0       , tan(xSkew), 0.0,
      tan(ySkew), 1.0,        0.0,
      0.0       , 0.0,        1.0
   );

   // Apply the transform to our tex coords
   texCoord = (trans * (vec3(texCoord.xy, 0.0))).xy;

   // Set vertex position
   gl_Position = (vec4(aVertexPosition, 1.0));
}

Frag

precision highp float;

uniform sampler2D sceneTexture;

varying vec2 texCoord;

void main(void){
   gl_FragColor = texture2D(sceneTexture, texCoord);
}
zero298
  • 25,467
  • 10
  • 75
  • 100
2

This ended up being significantly simpler than I thought it was. SFML has a vertexArray class that allows drawing custom quads without requiring the use of openGL.

The code I ended up going with is as follows (for anyone else who runs into this problem):

sf::Texture texture;
texture.loadFromFile("texture.png");
sf::Vector2u size = texture.getSize();

sf::VertexArray box(sf::Quads, 4);


box[0].position = sf::Vector2f(0, 0);      // top left corner position
box[1].position = sf::Vector2f(0, 100);    // bottom left corner position
box[2].position = sf::Vector2f(100, 100);  // bottom right corner position
box[3].position = sf::Vector2f(100, 100);  // top right corner position

box[0].texCoords = sf::Vector2f(0,0);
box[1].texCoords = sf::Vector2f(0,size.y-1);
box[2].texCoords = sf::Vector2f(size.x-1,size.y-1);
box[3].texCoords = sf::Vector2f(size.x-1,0);

To draw it, you call the following code wherever you usually tell your window to draw stuff.

window.draw(lines,&texture);

If you want to skew the image, you just change the positions of the corners. Works great. With this information, you should be able to create a custom drawable class. You'll have to write a bit of code (set_position, rotate, skew, etc), but you just need to change the position of the corners and draw.

Legacyblade
  • 335
  • 1
  • 5
  • 18