将部分纹理(精灵表/纹理贴图)应用于iOS OpenGL ES 2.0中的点精灵

Jam*_*res 13 opengl-es glsl ios opengl-es-2.0

看起来这应该很简单,但是使用点精灵的部分纹理我遇到了很多困难.我已经广泛搜索并提出了各种答案,但这些都没有解决我遇到的具体问题.

到目前为止我学到了什么:

  1. 点精灵绘图的基础知识
  2. 如何处理点精灵呈现为实心方块
  3. 如何改变点精灵的方向
  4. 如何使用点精灵多个纹理,在这里越来越近..
  5. 那点精灵+精灵表已经完成,但只能在OpenGL ES 2.0(不是1.0)中完成

这是我想要实现的图表

点精灵图

我在哪里:

  • 我有一组工作点精灵都使用相同的单个方形图像.例如:16x16的圆形图像效果很好.
  • 我有一个Objective-C方法,它生成一个包含带有多个图像的精灵表的600x600图像.我已经通过将整个精灵表单图像应用于使用GL_TRIANGLES绘制的四边形来验证这是有效的.
  • 我已成功使用上述方法将精灵表的部分绘制到四边形上.我不能让它与点精灵一起工作.
  • 目前我正在生成指向我正在定位的精灵表上的精灵中心的纹理坐标.例如:使用底部的图像; 明星:0.166,0.5; 云:0.5,0.5; 心脏:0.833,0.5.

码:

顶点着色器

uniform mat4 Projection;
uniform mat4 Modelview;
uniform float PointSize;

attribute vec4 Position;
attribute vec2 TextureCoordIn;

varying vec2 TextureCoord;

void main(void)
{
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    gl_PointSize = PointSize;
}
Run Code Online (Sandbox Code Playgroud)

片段着色器

varying mediump vec2 TextureCoord;
uniform sampler2D Sampler;

void main(void)
{
    // Using my TextureCoord just draws a grey square, so
    // I'm likely generating texture coords that texture2D doesn't like.
    gl_FragColor = texture2D(Sampler, TextureCoord);

    // Using gl_PointCoord just draws my whole sprite map
    // gl_FragColor = texture2D(Sampler, gl_PointCoord);
}
Run Code Online (Sandbox Code Playgroud)

我坚持的是:

  1. 我不明白如何gl_PointCoord在片段着色器中使用该变量.gl_PointCoord最初包含什么?为什么?它从何处获取数据?
  2. 我不明白要传入的纹理坐标.例如,点精灵是如何根据纹理坐标选择我的精灵表的哪一部分使用?我习惯于绘制有效的4组纹理坐标(每个顶点一个)的四边形,这有什么不同(显然是这样)?

Jam*_*res 11

我的一位同事帮助解决了问题.事实证明,诀窍是利用点的大小(以OpenGL单位)和精灵的大小(纹理单位,(0..1))结合一点矢量数学,只渲染部分精灵表到每个点上.

顶点着色器

uniform mat4 Projection;
uniform mat4 Modelview;
// The radius of the point in OpenGL units, eg: "20.0"
uniform float PointSize;
// The size of the sprite being rendered. My sprites are square
// so I'm just passing in a float.  For non-square sprites pass in
// the width and height as a vec2.
uniform float TextureCoordPointSize;

attribute vec4 Position;
attribute vec4 ObjectCenter;
// The top left corner of a given sprite in the sprite-sheet
attribute vec2 TextureCoordIn;

varying vec2 TextureCoord;
varying vec2 TextureSize;

void main(void)
{
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    TextureSize = vec2(TextureCoordPointSize, TextureCoordPointSize);

    // This is optional, it is a quick and dirty way to make the points stay the same
    // size on the screen regardless of distance.
    gl_PointSize = PointSize / Position.w;
}
Run Code Online (Sandbox Code Playgroud)

片段着色器

varying mediump vec2 TextureCoord;
varying mediump vec2 TextureSize;
uniform sampler2D Sampler;

void main(void)
{
    // This is where the magic happens.  Combine all three factors to render
    // just a portion of the sprite-sheet for this point
    mediump vec2 realTexCoord = TextureCoord + (gl_PointCoord * TextureSize);
    mediump vec4 fragColor = texture2D(Sampler, realTexCoord);

    // Optional, emulate GL_ALPHA_TEST to use transparent images with
    // point sprites without worrying about z-order.
    // see: http://stackoverflow.com/a/5985195/806988
    if(fragColor.a == 0.0){
        discard;
    }

    gl_FragColor = fragColor;
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*las 6

点精灵由一个位置组成。因此,任何“可变”值实际上都不会变化,因为之间没有可插值的内容。

gl_PointCoordvec2XY值介于[0,1]之间的值。它们代表该点的位置。(0,0)是该点的左下角,而(1,1)是该点的右上角。

因此,您想将(0,0)映射到精灵的左下角,并将(1,1)映射到右上角。要做到这一点,你需要知道的一些事情:精灵的尺寸(假设他们都是一样的大小),纹理的大小(因为纹理拾取功能,采取规范化的纹理坐标,而不是像素位置),以及目前正在渲染精灵。

后者可以通过设置varying。它可以是作为每个顶点数据传递到varying顶点着色器中的值。

您可以使用该值加上子画面的大小来确定要在该纹理中提取该子画面数据的位置。拥有要使用的纹理像素坐标后,将其除以纹理大小即可生成标准化的纹理坐标。

无论如何,点精灵(尽管名称)实际上并不是用于精灵渲染的。为此,使用四边形/三角形会更容易,因为您可以更加准确地确定所有物体的位置。