x


SetPixels too slow

I am having trouble with making bullet holes in an airplane model I put together in Maya. The crux of the issue seems to be the speed at which either SetPixels() or mainTex.Apply() operate since that is what all my debugging points to. Right now a single bullet hole will slow the game to a very sad 0.9 seconds per frame. The textures being edited are both 2048 X 2048 which I know is quite large (I am thinking about cutting this up into smaller textures and mapping them separately on each part of the airplane).

Without too much talking, I present my commented code for your help and ask this one question: "How can I speed up the operations?"

var mainTex : Texture2D[]; // all editable textures of the object (some objects will have two or more) added before runtime

private var holesArray = new Array(); // x (x position), y (y position), z (radius)
private var holeTimers = new Array(); // cooling timer


function Update () {
    UpdateBulletHoles(); // cycle through the bullet holes that already exist and aply their texture changes
}

// this function is called by the bullet, explosive, or other such object which comes in contact with this object
function AddHole (xPos : float, yPos : float, rad : float) {
    holesArray.Push(Vector3(xPos * mainTex[0].width, yPos * mainTex[0].height, rad)); // x and y are set up for positioning the hole on the texture; z takes the radius of the projectile
    holeTimers.Push(0.0); // all bullet holes start at zero cooling time
}

function UpdateBulletHoles () {
    if (holesArray.length == 0) // if there are no active bullet holes then don't do anything
        return;

    // this block of code is used to remove holes that have fully cooled and to ensure that the hole is drawn as being fully cooled
    var holesToRemove = new Array();
    for (i = 0; i < holesArray.length; i++)
    {
        holeTimers[i] += Time.deltaTime * 10;
        if (holeTimers[i] >= 20)
        {
            holesToRemove.Push(i);
            holeTimers[i] = 20;
        }
    }

    // cycle through textures
    for (l = 0; l < mainTex.length; l++)
    {

        // cycle through holes
        for (k = 0; k < holesArray.length; k++)
        {

            // don't draw holes on parts of the geometry that have not had their UV coordinates layed out perfectly (nor ever will)
            if (holesArray[k].x >= 5 || holesArray[k].y <= 2040)
            {

                var pix : Color;
                // get a square of pixels from the texture that is as wide and as tall as the drawn hole and centered on that hole
                var pixels = mainTex[l].GetPixels(holesArray[k].x - holesArray[k].z - 3, holesArray[k].y + holesArray[k].z + 3, (holesArray[k].z * 2) + 6, (holesArray[k].z * 2) + 6, 0);
                var pixPos : Vector2;

                // set up ring color to show its cooling progress
                if (holeTimers[k] <= 10)
                    pix = Color.Lerp(Color(1, 1, 0, 1), Color(1, 0.5, 0, 1), holeTimers[k] / 10);
                else
                    pix = Color.Lerp(Color(1, 0.5, 0, 1), Color(0.5, 0.5, 0.5, 1), (holeTimers[k] - 10) / 10);

                // cycle through the square of pixels just extracted from the texture
                for (i = 0; i < pixels.length; i++)
                {

                    // this block of code finds the distance of each pixel from the center of the hole
                    var dist : float;
                    pixPos.x = ((i / (holesArray[k].z + 3)) - Mathf.Floor(i / (holesArray[k].z + 3))) * (holesArray[k].z + 3);
                    pixPos.y = Mathf.Floor(i / (holesArray[k].z + 3));
                    dist = Mathf.Sqrt(Mathf.Pow(pixPos.x - (holesArray[k].z + 3), 2) + Mathf.Pow(pixPos.y - (holesArray[k].z + 3), 2));

                    // draw the ring on the outside of the hole 3 pixels thick and punch a hole with the previously given radius
                    if (dist <= holesArray[k].z + 3 && dist > holesArray[k].z)
                        if (pixels[i].a > 0.5)
                            pixels[i] = pix;
                    if (dist <= holesArray[k].z)
                    {
                        pixels[i] = pix;
                        pixels[i].a = 0;
                    }
                }

                // set the square of pixels with the altered pixels
                mainTex[l].SetPixels(holesArray[k].x - holesArray[k].z - 3, holesArray[k].y + holesArray[k].z + 3, (holesArray[k].z * 2) + 6, (holesArray[k].z * 2) + 6, pixels, 0);

            }
        }

        mainTex[l].Apply(); // send the pixel changes to the graphics card
    }

    // remove fully cooled holes from the arrays
    for (i = 0; i < holesToRemove.length; i++)
    {
        holesToRemove.RemoveAt(i);
        holesArray.RemoveAt(i);
        holeTimers.RemoveAt(i);
    }
}

Thanks, -Conan Horus

more ▼

asked Feb 20, 2012 at 12:48 AM

ConanHorus gravatar image

ConanHorus
61 12 8 11

Nothing to do with SetPixels; when you use Apply() it has to upload the entire texture no matter how few or how many pixels have changed.

Feb 20, 2012 at 02:03 AM Eric5h5
(comments are locked)
10|3000 characters needed characters left

0 answers: sort voted first
Be the first one to answer this question
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x52
x44
x17

asked: Feb 20, 2012 at 12:48 AM

Seen: 2128 times

Last Updated: Feb 20, 2012 at 02:03 AM