2

I'm creating an ios painting app for iOS and having the hardest time rotating a paint texture at a particular point to have it face the direction of the stroke.

I'm drawing the texture a few pixels apart between every touch of the user. The vertex points are being represented as a 2d point with x and y coordinates into a vertex buffer which is then rendered to screen. Here's the code that I'm using to draw:

 count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
 GLfloat *vBuffer = malloc(2 * sizeof(GLfloat));
 for(i = 0; i < count; i++) {

    vBuffer[0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
    vBuffer[1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
    CGFloat degrees = atan2(end.y - start.y, end.x - start.x) * 180 / M_PI;

    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glVertexPointer(2, GL_FLOAT, 0, vBuffer);
    glDrawArrays(GL_POINTS, 0, count);
    glRotatef(degrees, 0, 0, 1);
    glPopMatrix();
 }

 // render to screen
 glBindRenderbufferOES(GL_RENDERBUFFER_OES, renderbuffer);
 [context presentRenderbuffer:GL_RENDERBUFFER_OES];

This does not give me the desired effect, which is the rotation of the texture at each vertex by the angle that represents the deviation between the two points.

Questions I have are:

  • How do I rotate just the texture at every point?
  • Is it sufficient to represent each vertex with just x,y coordinates or does it have to be as 3 points or more?
  • Do I need to enable texture mapping? Is that what is preventing me from independently rotating the texture at each vertex? If so, how do I represent the texture co-ordinate array for a vertex array as is represented above? I haven't been able to figure that part out.

Thank you so much for your help in advance!

UPDATE:

I was able to figure this out and posted my answer here: https://stackoverflow.com/a/11298219/111856

Community
  • 1
  • 1
kajham
  • 1,241
  • 15
  • 19

3 Answers3

5

If you have arrived at this page from a google search (which nearly everyone does) You probably want to know how to rotate sprites rendered using gl_PointCoord. The accepted answer by SteveL incorrectly says this isn't possible but Joel Murphy points out how to do this.

Here is some additional information that may be relevant to you if you use Joel's suggestion. (In my book additional, contributory information is as near to an actual answer as makes no difference!)

  1. The image needs to be root 2 times the size of the original i.e. 1.414 x, not 15% bigger
  2. It is significantly more efficient to do the trigonometry work in the vertex shader. So I have:

    precision mediump float;
    
    attribute vec3 vertex;
    attribute vec3 normal;
    
    uniform mat4 modelviewmatrix[2];
    uniform vec3 unib[4];
    
    varying float dist;
    varying mat2 rotn;
    
    void main(void) {
      gl_Position = modelviewmatrix[1] * vec4(vertex,1.0);
      dist = vertex[2];
      rotn = mat2(cos(normal[0]), sin(normal[0]),
                 -sin(normal[0]), cos(normal[0])); 
      gl_PointSize = unib[2][2] / dist;
    }
    

    fragment shader:

    precision mediump float;
    
    uniform sampler2D tex0;
    uniform vec3 unib[4];
    
    varying float dist;
    varying mat2 rotn;
    
    void main(void) {
      vec2 centre = vec2(0.5, 0.5);
      vec2 rot_coord = rotn * (gl_PointCoord - centre) + centre;
      vec4 texc = texture2D(tex0, rot_coord);
      if (dist < 1.0 || texc.a < unib[0][2]) discard;
      gl_FragColor = texc;
    }
    

PS I switched from using highp variables because some of the phone gpus used in the soc boards such as beaglebone and cubitruck don't support it.

PPS As an extension to this approach I have added a version of this shader to pi3d which also uses an offset to use the texture2D() as a sprite atlas. vertex fragment

paddyg
  • 2,153
  • 20
  • 24
3

I have been able to rotate textures within the fragment shader by passing the rotation value along from the vertex shader. Given a vertex shader with the following:

attribute float aRotation;
varying float vRotation;

The attribute is passed from your application while the varying passes information to the fragment shader. Nothing needs to be computed so you can copy the value directly over by putting this in the vertex shader's main() function:

vRotation = aRotation;

Within the fragment shader you'll need to have another varying statement:

varying highp float vRotation;

The value gl_PointCoord is a vec2 with values between 0.0 and 1.0, with (0.0, 0.0) being the lower-left corner and (1.0, 1.0) being the upper-right, so there's very little translation to be done to make this work. In your fragment shader's main, add:

// Set a center position.
highp vec2 center = vec2(0.5, 0.5);

// Translate the center of the point the origin.
highp vec2 centeredPoint = gl_PointCoord - center;

// Create a rotation matrix using the provided angle
highp mat2 rotation = mat2(cos(vRotation), sin(vRotation),
                          -sin(vRotation), cos(vRotation)); 

// Perform the rotation.
centeredPoint = rotation * centeredPoint;

// Translate the point back to its original position and use that point 
// to get your texture color.
gl_FragColor = texture2D(uTexture, centeredPoint + center);

Note: The actual point sprite is still the same square drawn by the engine. If using this method, you'll need to make sure your textures have about 15% padding per side (e.g. if your image is 128x128, you'd need to pad the image with a 56-pixel margin).

Joel Murphy
  • 845
  • 1
  • 6
  • 13
0

You can't rotate the points when you draw as GL_POINTS,You need to use some other way , like drawing your textures as GL_TRIANGLES

SteveL
  • 3,331
  • 4
  • 32
  • 57
  • That makes sense. I was rendering the texture to screen at different points using POINT sprites, and then realized that point sprites cannot be rotated. Thanks for the response – kajham Jul 01 '12 at 23:44