当绘制为GL_POINTS(仅指定2个坐标)时,是否可以在顶点处旋转纹理?

时间:2012-06-29 21:10:38

标签: ios opengl-es

我正在为iOS创建一个ios绘画应用程序,并且最难在特定点旋转绘制纹理以使其面向笔划方向。

我在每次触摸用户之间绘制几个像素的纹理。顶点被表示为2d点,x和y坐标进入顶点缓冲区,然后渲染到屏幕。这是我用来绘制的代码:

 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];

这并没有给我所需的效果,即每个顶点的纹理旋转角度,表示两点之间的偏差。

我的问题是:

  • 如何在每个点旋转纹理?
  • 用x,y坐标表示每个顶点是否足够,或者它必须是3点或更多?
  • 我是否需要启用纹理映射?是什么阻止我在每个顶点独立旋转纹理?如果是这样,我如何表示顶点数组的纹理坐标数组,如上所示?我无法弄明白这一部分。

非常感谢您的帮助!

更新:

我能够解决这个问题并在此发布我的答案:https://stackoverflow.com/a/11298219/111856

3 个答案:

答案 0 :(得分:4)

如果你从谷歌搜索到了这个页面(几乎每个人都这样做)你可能想知道如何旋转使用gl_PointCoord渲染的精灵。 SteveL接受的答案错误地说这不可能,但Joel Murphy指出如何做到这一点。

如果您使用Joel的建议,以下是一些可能与您相关的其他信息。 (在我的书中,额外的贡献信息与实际答案接近,因为没有区别!)

  1. 图像需要是原始尺寸的2倍,即1.414 x,而不是15%
  2. 在顶点着色器中进行三角函数工作效率要高得多。所以我有:

    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;
    }
    

    片段着色器:

    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;
    }
    
  3. PS我改变了使用highp变量,因为在诸如beaglebone和cubitruck之类的soc板中使用的一些手机gpus不支持它。

    PPS作为这种方法的扩展,我在pi3d中添加了这个着色器的一个版本,它也使用了一个偏移量来将texture2D()用作精灵地图集。 vertex fragment

答案 1 :(得分:3)

我已经能够通过从顶点着色器传递旋转值来在片段着色器中旋转纹理。给定具有以下内容的顶点着色器:

attribute float aRotation;
varying float vRotation;

当变量将信息传递给片段着色器时,属性从应用程序传递。无需计算任何内容,因此您可以通过将其放在顶点着色器的main()函数中直接复制该值:

vRotation = aRotation;

在片段着色器中,您需要另外一个不同的声明:

varying highp float vRotation;

值gl_PointCoord是vec2,其值介于0.0和1.0之间,左下角为(0.0,0.0),右上角为(1.0,1.0),因此要进行的翻译很少这项工作。在片段着色器的主要部分中,添加:

// 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);

注意:实际的点精灵仍然是引擎绘制的相同方块。如果使用此方法,您需要确保纹理每边有大约15%的填充(例如,如果您的图像是128x128,则需要以56像素的边距填充图像)。

答案 2 :(得分:0)

当您绘制为GL_POINTS时,无法旋转点,您需要使用其他方式,例如将纹理绘制为GL_TRIANGLES