在LibGDX中实现梯形精灵

时间:2015-02-03 02:36:46

标签: java opengl animation libgdx

我试图为一个简单的2D游戏创建一个程序动画引擎,让我可以用少量图像创建漂亮的动画(类似于这种方法,但对于2D:{{3} })

目前我有关键帧来保存不同动画对象的数据,关键帧是代表以下内容的浮点数组:

translateX,translateY,scaleX,scaleY,rotation(degrees)

我想将skewX,skewY,taperTop和taperBottom添加到此列表中,但我无法正确呈现它们。

这是我尝试在精灵顶部实现锥度以使其呈梯形形状:

float[] vert = sprite.getVertices();
vert[5] += 20; // top-left vertex x co-ordinate
vert[10] -= 20; // top-right vertex x co-ordinate

batch.draw(texture, vert, 0, vert.length);

不幸的是,这会产生一些奇怪的纹理变形。

我有一点谷歌,看看StackOverflow并找到了这个,这似乎是我遇到的问题:

http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach

但是我不理解它背后的数学(什么是s,t,r和q?)。

有人可以解释一下吗?

1 个答案:

答案 0 :(得分:3)

基本上,四边形越接近矩形,由于在整个形状上线性插值纹理坐标的效果,外观越差。构成四边形的两个三角形被拉伸到不同的尺寸,因此线性插值使得接缝非常明显。

对于片段着色器处理的每个片段,对每个顶点的纹理坐标进行线性插值。纹理坐标通常以已经分割出的对象的大小存储,因此坐标在0-1的范围内,与纹理的边缘相对应(并且该范围之外的值被夹住或缠绕)。这通常也是3D建模程序导出网格的方式。

使用梯形,我们可以通过将纹理坐标预先乘以宽度来限制失真,然后在线性插值后将宽度后分割出纹理坐标。这就像弯曲两个三角形之间的对角线,使得其斜坡在梯形较宽侧的拐角处更加水平。这是一张有助于说明它的图片。

enter image description here

纹理坐标通常表示为具有分量U和V的2D矢量,也称为S和T.但是如果要将大小除以组件之外,还需要另外一个组件来划分插值后,这称为Q分量。 (如果您在3D纹理中查找某些内容而不是2D纹理,P组件将用作纹理中的第三个位置。)

现在出现了困难的部分...... libgdx的SpriteBatch不支持Q组件所需的额外顶点属性。因此,您可以克隆SpriteBatch并仔细检查并修改它以在texCoord属性中有一个额外的组件,或者您可以尝试重新使用现有的颜色属性,尽管它存储为无符号字节。

无论如何,您将需要预宽度划分的纹理坐标。简化这种方法的一种方法是,不是使用四个顶点的四边形的实际尺寸,而是获得梯形的顶部宽度和底部宽度的比率,因此我们可以将顶部部分视为1的宽度,因此留下它们单独

float bottomWidth = taperBottom / taperTop;

然后,您需要修改TextureRegion的现有纹理坐标,以便将它们预先乘以宽度。由于上述简化,我们可以将顶点单独留在梯形的顶部,但是两个窄边顶点的U和V坐标需要乘以bottomWidth。每次更改TextureRegion或其中一个锥形值时,您都需要重新计算它们并将它们放入顶点数组中。

在顶点着色器中,您需要将额外的Q分量传递给片段着色器。在片段着色器中,我们通常使用像这样的大小分隔的纹理坐标来查找纹理颜色:

vec4 textureColor = texture2D(u_texture, v_texCoords);

但在我们的情况下,我们仍需要除以Q分量:

vec4 textureColor = texture2D(u_texture, v_texCoords.st / v_texCoords.q);

但是,这会导致依赖纹理读取,因为我们在将矢量传递到纹理函数之前修改它。 GLSL提供了一个自动执行上述操作的函数(我假设不会导致依赖纹理读取):

vec4 textureColor = texture2DProj(u_texture, v_texCoords); //first two components automatically divided by last component