尝试从setpixel / getpixel进行优化

时间:2016-05-07 20:20:55

标签: c# optimization unity3d textures texture2d

我正在尝试优化以下代码,因为多次循环以获得纹理的每个像素非常耗时!

我有3个纹理,在别处生成需要合并然后保存到磁盘。

我尝试过使用SetPixels和GetPixels,但这并不是特别有用,因为多次使用它只是替换整个纹理而不是仅替换非透明像素。以下是我到目前为止的功能:

public void savePNG()
{

    stationWidth = PlayerPrefs.GetInt("Station Width");
    stationHeight = PlayerPrefs.GetInt("Station Height");

    Debug.Log(stationWidth + ", " + stationHeight);

    Texture2D spaceStation = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    spaceStation = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);

    Color Test;

    floorTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    wallTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    roomTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);

    floorTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../floorTexture.png"), false);
    wallTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../wallTexture.png"), false);
    roomTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../roomTexture.png"), false);


    for(int row = 0; row < stationWidth*256; row ++)
    {
        for(int col = 0; col < stationHeight*256; col ++)
        {

            Test = floorTex.GetPixel(row,col);

            if(Test.a != 0.0f)
            {
                spaceStation.SetPixel(row, col, floorTex.GetPixel(row,col));
            }
            else
            {
                spaceStation.SetPixel(row, col, Color.white);
            }

            Test = wallTex.GetPixel(row,col);

            if(Test.a != 0.0f)
            {
                spaceStation.SetPixel(row, col, wallTex.GetPixel(row,col));
            }

            Test = roomTex.GetPixel(row,col);

            if(Test.a != 0.0f)
            {
                spaceStation.SetPixel(row, col, roomTex.GetPixel(row,col));
            }

        }
    }

    spaceStation.Apply();

    byte[] bytes = spaceStation.EncodeToPNG();
    File.WriteAllBytes(Application.dataPath + "/../SpaceStation.png", bytes);

}

我不确定从哪里开始,任何想法或建议都将不胜感激!

其他

我尝试的GetPixels和SetPixels代码看起来像这样:

    spaceStation.SetPixels(floorTex.GetPixels(0, 0, stationWidth*256, stationHeight*256));
    spaceStation.SetPixels(wallTex.GetPixels(0 ,0, stationWidth*256, stationHeight*256));
    spaceStation.SetPixels(roomTex.GetPixels(0, 0, stationWidth*256, stationHeight*256));

每个SetPixels完全覆盖了之前的那些,我希望透明像素根本不会覆盖任何像素,所以细节会通过

显示

2 个答案:

答案 0 :(得分:1)

我使用的是颜色数组,而不是单独设置每个像素,只需调用GetPixels 3次,SetPixels调用一次。功能现在快了大约80%,这是相当不错的全面。我被告知使用Graphics.Blit和着色器可以获得更好的结果,但我真的对着色器一无所知,所以我现在不打算采用这种方法。以下是代码现在的样子:

public void savePNG()
{
    stationWidth = PlayerPrefs.GetInt("Station Width");
    stationHeight = PlayerPrefs.GetInt("Station Height");

    Texture2D spaceStation = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    spaceStation = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);

    Color[] mainArray = new Color[(stationWidth*256)*(stationHeight*256)];
    Color[] wallArray = new Color[(stationWidth*256)*(stationHeight*256)];
    Color[] roomArray = new Color[(stationWidth*256)*(stationHeight*256)];

    floorTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    wallTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);
    roomTex = new Texture2D(stationWidth*256, stationHeight*256, TextureFormat.ARGB32, false);

    floorTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../floorTexture.png"), false);
    wallTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../wallTexture.png"), false);
    roomTex.LoadImage(File.ReadAllBytes(Application.dataPath + "/../roomTexture.png"), false);


    mainArray = floorTex.GetPixels(0,0,stationWidth*256, stationHeight*256);
    wallArray = wallTex.GetPixels(0,0,stationWidth*256, stationHeight*256);
    roomArray = roomTex.GetPixels(0,0,stationWidth*256, stationHeight*256);

    for(int i = 0; i < mainArray.Length; i++)
    {
        if(wallArray[i].a != 0.0f)
        {
            mainArray[i] = wallArray[i];
        }
        if(roomArray[i].a != 0.0f)
        {
            mainArray[i] = roomArray[i];
        }
    }

    spaceStation.SetPixels(mainArray);

    spaceStation.Apply();

    byte[] bytes = spaceStation.EncodeToPNG();
    File.WriteAllBytes(Application.dataPath + "/../SpaceStation.png", bytes);

}

答案 1 :(得分:-1)

我真的不知道Texture2D对象的(get / set)Pixel方法的性能。但在.NET世界中,我们更喜欢System.Drawing.Bitmap对象和System.Drawing.Imaging.BitmapData类以及BitmapData的Scan0属性来快速访问像素值。

在SO中已经有一个漂亮的answer来证明其用法。