Java 旋转时为二维精灵添加厚度
在我的游戏中,我的实体像一张纸一样旋转,如图所示,以半速旋转:Java 旋转时为二维精灵添加厚度,java,libgdx,glsl,Java,Libgdx,Glsl,在我的游戏中,我的实体像一张纸一样旋转,如图所示,以半速旋转: 我想在实体转动时给它们一点厚度,使它们比纸薄得多。 我考虑过使用Pixmap来检测和扩展边缘像素,并为图像提供一些三维度。我还考虑过沿x轴复制图像以获得相同的效果。在这两个想法中,Pixmap在我心目中最有希望。但是,我想知道是否有更好的解决方案。 我使用GLSL着色器在旋转时为实体提供高光和阴影,如gif中所示。我认为有了正确的知识,我可以使用相同的着色器程序实现我的目标。 我的着色器如下所示: #ifdef GL_ES prec
我想在实体转动时给它们一点厚度,使它们比纸薄得多。
我考虑过使用Pixmap来检测和扩展边缘像素,并为图像提供一些三维度。我还考虑过沿x轴复制图像以获得相同的效果。在这两个想法中,Pixmap在我心目中最有希望。但是,我想知道是否有更好的解决方案。
我使用GLSL着色器在旋转时为实体提供高光和阴影,如gif中所示。我认为有了正确的知识,我可以使用相同的着色器程序实现我的目标。
我的着色器如下所示:
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform vec3 color;
void main()
{
vec4 col = vec4(color, 0.0);
gl_FragColor = texture2D(u_texture, v_texCoords) * v_color + col;
}
我认为人们可以根据我传递给它的统一vec3颜色
进行计算(其值范围从0,0,0
到1,1,1
。1是高亮,0是阴影)。不幸的是,我不了解着色器可以这样做。如果你们中有人有诀窍的话,你能把我引向正确的方向吗?或者让我知道我是否应该坚持Pixmap的想法。
编辑:我正试图避免使用3D模型,因为我使用2d正交相机时有6.4k行代码深度。
编辑2:我认为如果我尝试使精灵看起来是3D的,反射着色器就不好看了。我放弃了着色器,采用了Pixmap的想法,并计划在没有任何着色器的情况下实现Pixmap的阴影和反射。尽管到目前为止它看起来还不错,没有任何反射。我最终还是坚持了我的pixmap想法。我想分享我的代码,以便其他人知道我是如何获得2D厚度的。
请注意,在以下代码中:
dir
是介于-1.0到1.0之间的浮点值。它告诉程序精灵的位置<代码>-1表示完全向左<代码>1表示正确<代码>0表示它“面向”相机
right
是一个布尔值,它告诉程序实体的旋转方向true
表示实体从左向右旋转<代码>假表示从右到左。
代码:
结果如下:D我最终还是接受了我的pixmap想法。我想分享我的代码,以便其他人知道我是如何获得2D厚度的。
请注意,在以下代码中:
dir
是介于-1.0到1.0之间的浮点值。它告诉程序精灵的位置<代码>-1表示完全向左<代码>1表示正确<代码>0表示它“面向”相机
right
是一个布尔值,它告诉程序实体的旋转方向true
表示实体从左向右旋转<代码>假表示从右到左。
代码:
结果如下:D我认为您需要创建矩形块的3d网格,精灵的uv纹理坐标对于块的正面和背面是相同的。然后当你旋转方块时,你应该看到方块的宽度。我认为混合应该有效,但这不是我以前尝试过的。我不确定它在2D相机上的效果如何。是的,我想你需要在网格上添加额外的矩形来显示两条边。扩展Pixmap或在着色器中执行某些操作不会创建额外的几何体,当它垂直于摄影机视图时,您需要为其提供任何厚度。从理论上讲,你可以使用Pixmap计算边缘的适当图像,但要将其作为地图集的一部分,我只需手动绘制。你是否考虑过在旋转时简单地以3D绘制它?@user253751我考虑过,但除了建模之外,我以前从未在3D中工作过。我很犹豫是否要学习它,如果你不在3D中翻转区域,我可以想象一个着色器可以实现你所描述的效果。当精灵水平缩小时,它需要以增加的间距水平地对纹理进行多次采样。在采样点中,取最大不透明度和非零不透明度点的最近RGB。我认为您需要创建矩形块的3d网格,精灵的uv纹理坐标对于块的正面和背面是相同的。然后当你旋转方块时,你应该看到方块的宽度。我认为混合应该有效,但这不是我以前尝试过的。我不确定它在2D相机上的效果如何。是的,我想你需要在网格上添加额外的矩形来显示两条边。扩展Pixmap或在着色器中执行某些操作不会创建额外的几何体,当它垂直于摄影机视图时,您需要为其提供任何厚度。从理论上讲,你可以使用Pixmap计算边缘的适当图像,但要将其作为地图集的一部分,我只需手动绘制。你是否考虑过在旋转时简单地以3D绘制它?@user253751我考虑过,但除了建模之外,我以前从未在3D中工作过。我很犹豫是否要学习它,如果你不在3D中翻转区域,我可以想象一个着色器可以实现你所描述的效果。当精灵水平缩小时,它需要以增加的间距水平地对纹理进行多次采样。在采样点中,取非零不透明度点的最大不透明度和最近的RGB。
private Texture getTurningImage(TextureRegion input, int thickness)
{
if(Math.abs(dir) < 0.1)
dir = (right ? 1 : -1) * 0.1f;
Texture texture = input.getTexture();
if (!texture.getTextureData().isPrepared())
{
texture.getTextureData().prepare();
}
Pixmap pixmap = texture.getTextureData().consumePixmap();
Pixmap p = new Pixmap(64, 64, Pixmap.Format.RGBA8888);
p.setFilter(Pixmap.Filter.NearestNeighbour);
Pixmap texCopy = new Pixmap(input.getRegionWidth(), input.getRegionHeight(), Pixmap.Format.RGBA8888);
// getting a texture out of the input region. I can't use input.getTexture()
// because it's an animated sprite sheet
for (int x = 0; x < input.getRegionWidth(); x++)
{
for (int y = 0; y < input.getRegionHeight(); y++)
{
int colorInt = pixmap.getPixel(input.getRegionX() + x, input.getRegionY() + y);
Color c = new Color(colorInt);
colorInt = Color.rgba8888(c);
texCopy.drawPixel(x, y, colorInt);
}
}
pixmap.dispose();
float offsetVal = Math.round(thickness/2.0) * (float) -Math.cos((dir * Math.PI)/2);
if(offsetVal > -1.23/Math.pow(10, 16))
{
offsetVal = 0;
}
// generate the pixel colors we'll use for the side view
Pixmap sideProfile = new Pixmap(1, 64, Pixmap.Format.RGBA8888);
for (int y = 0; y < texCopy.getHeight(); y++)
{
for (int x = 0; x < texCopy.getWidth(); x++)
{
int colorInt = texCopy.getPixel(x, y);
if(new Color(colorInt).a != 0 && new Color(texCopy.getPixel(x + 1, y)).a == 0)
{
Color c = new Color(colorInt);
c.mul(.8f); // darken the color
c.a = 1;
colorInt = Color.rgba8888(c);
sideProfile.drawPixel(0, y, colorInt);
continue;
}
}
}
// drawing the bottom layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(-offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// drawing the middle (connecting) layer
// based on the edge pixels of the bottom layer, then translated to be in the middle
for (int y = 0; y < p.getHeight(); y++)
{
int colorInt = sideProfile.getPixel(0, y);
for (int x = 0; x < p.getWidth(); x++)
{
if(new Color(p.getPixel(x, y)).a != 0 && new Color(p.getPixel(x + 1, y)).a == 0)
{
for(int i = 0; i <= 2 * Math.round(Math.abs(offsetVal)); i++) // the for the length between the top and bottom
{
p.drawPixel(x + i - 2 * (int)Math.round(Math.abs(offsetVal)), y, colorInt);
}
}
}
}
// drawing the top layer
p.drawPixmap(texCopy, 0, 0, 64, 64, (int) (Math.round(offsetVal) + (64 - texCopy.getWidth()*Math.abs(dir))/2), 0, (int)(64*Math.abs(dir)), 64);
// flip if facing left
if(dir < 0)
{
p = flipPixmap(p);
}
return new Texture(p);
}
private Pixmap flipPixmap(Pixmap src)
{
final int width = src.getWidth();
final int height = src.getHeight();
Pixmap flipped = new Pixmap(width, height, src.getFormat());
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
flipped.drawPixel(x, y, src.getPixel(width - x - 1, y));
}
}
return flipped;
}