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