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

看起来这应该很容易,但是使用点精灵的纹理的一部分有很多困难。 我广泛search了各种答案,但没有一个处理我遇到的具体问题。

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

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

这是我想要实现的图表

点精灵图

我在哪里:

  • 我有一组工作点精灵都使用同一个单一的方形图像。 例如:一个16×16的圆圈图像效果很好。
  • 我有一个Objective-C方法,它会生成一个包含多个图像的精灵表的600×600图像。 我已经validation这是通过将整个精灵图片应用于用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; } 

片段着色器

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

我被困在什么地方:

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

我的一位同事帮助了答案。 原来的技巧是利用点的大小(在OpenGL单位)和精灵的大小(在纹理单位,(0..1))结合一个小的向量math来渲染只有部分的精灵表到每个点上。

顶点着色器

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

片段着色器

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

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

gl_PointCoord是XY值在[0,1]之间的vec2值。 他们代表了这一点上的位置。 (0,0)是该点的左下angular,(1,1)是右上angular。

所以你想把(0,0)映射到精灵的左下angular,(1,1)映射到右上angular。 要做到这一点,你需要知道一些事情:精灵的大小(假设它们都是相同的大小),纹理的大小(因为纹理获取函数采用标准化的纹理坐标,而不是像素位置)精灵目前正在呈现。

后者可以通过varying设置。 它可以是一个按顶点数据的值传递给顶点着色器的varying

你使用加上精灵的大小来确定你想要为这个精灵拉取数据的纹理的位置。 一旦你有了要使用的纹理坐标,你可以将它们除以纹理的大小来产生标准化的纹理坐标。

无论如何,点精灵,尽pipe名称,并不真正意味着精灵渲染。 使用四边形/三angular形将会更容易,因为您可以更准确地确定每个位置的位置。