Android Opengl-es загружает неэнергию 2 текстуры

У меня есть приложение, с которым я неоднократно играл в android, он использует opengl-es.

В настоящее время я загружаю текстуры из растрового изображения так:

//Load up and flip the texture - then dispose the temp
    Bitmap temp = BitmapFactory.decodeResource(Deflecticon.getContext().getResources(), resourceID);
    Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
    temp.recycle();

    //Bind the texture in memory
    gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

    //Set the parameters of the texture.
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    //On to the GPU
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

Очевидная проблема заключается в том, что текстура, которую я использую, должна быть мощью 2. На данный момент я предварительно редактирую текстуры в Photoshop, чтобы иметь силу 2 и просто иметь пустые границы. Однако это немного утомительно, и я хочу иметь возможность загружать их так, как они есть.. признать, что они не являются силой 2 и загружают их в текстуру.

Я знаю, что могу масштабировать растровое изображение, чтобы стать мощью 2-х размеров и просто растянуть текстуру, но я не хочу растягивать текстуру, а в некоторых случаях может захотеть поместить несколько текстур в один "атлас".

Я знаю, что могу использовать glTexSubImage2D() для вставки в текстуру данных, которые я хочу в начале координат, которые я хочу. Это здорово!

Однако я не знаю, как в Android инициализировать текстуру без данных?

В этом вопросе ранее спросил, было предложено вызвать glTexImage2D() без данных и затем заполнить его.

Однако в android, когда вы вызываете "GLUtils.texImage2D (GL10.GL_TEXTURE_2D, 0, bmp, 0);" вы не указываете ширину/высоту. Он читает это из растрового изображения, которое я предполагаю.

Каков наилучший способ сделать это? Могу ли я создать новое растровое изображение с правильной мощностью 2 размера, только пустым и не заполненным данными, и использовать его для инициализации текстуры, а затем вставить в нее с помощью subImage? Или я должен сделать новое растровое изображение, чтобы как-то скопировать пиксели, которые я хочу (не уверен, если вы можете сделать это легко) в это новое растровое изображение (оставляя границы), а затем просто используйте это?

Изменить: уточнил, что я использую opengl.

Ответ 1

Я думаю, если бы вы попытались создать растровое изображение с мощностью 2-х осевых размеров, а затем добавить растровое изображение, оно должно работать нормально. возможно что-то вроде

Bitmap.createBitmap(notPowerOf2Bitmap, offx, offy, xsize, ysize, bitmapFlag)

кроме этого, я бы сказал, страдают в процессе фотошопа. Сколько у вас фотографий?

Ответ 2

Растровые изображения Non-power-of-two (NPOT) поддерживаются на некоторых платформах GLES, но вы должны проверить, существует ли соответствующее расширение. Обратите внимание, однако, что, по крайней мере, на PowerVR SGX, хотя поддерживается NPOT, есть еще некоторые другие довольно произвольные ограничения; например, ваша ширина текстуры должна быть кратной 2 (если не равна 2). Кроме того, рендеринг NPOT имеет тенденцию быть немного медленнее на многих графических процессорах.

Одна вещь, которую вы можете сделать, это просто создать текстуру обертки, которая является размером в два раза, а затем использовать glTexSubimage2D для загрузки текстуры, чтобы покрыть только часть этого, а затем соответствующим образом скорректировать ваши координаты текстуры. Очевидным недостатком этого является то, что вы не можете использовать текстурную упаковку в этом случае. Если вы абсолютно должны поддерживать обертывание, вы можете просто масштабировать свою текстуру до ближайшего размера в два раза, прежде чем вы вызовете glTexImage2D, хотя это обычно вводит артефакты выборки и делает вещи размытыми, особенно если вы пытаетесь сделать пиксельные точные 2D работа.

Еще одна вещь, которую вы могли бы подумать, если вам не нужна поддержка обертывания, заключается в создании "атласа текстуры", в котором вы конденсируете все свои текстуры в несколько больших текстур и располагаете ваши полигоны только некоторыми части текстурного атласа (ов). Вы должны быть осторожны при создании MIPmaps, но помимо этого он обычно обеспечивает довольно хорошее преимущество в производительности, а также более эффективное использование текстурной памяти, так как вы не тратите столько на мягкие или масштабированные изображения.

Ответ 3

У меня есть 2 решения, которые я использовал для этой проблемы. Я могу быть более конкретным, если это необходимо, но концептуально вы можете: -

  • Сделайте изображение равным 2, а раздел, чтобы обрезать, вы заполняете 100% альфа-каналом и загружаете изображения с поддержкой альфы.

  • Измените свой вектор текстуры/буфер, чтобы он не загружал этот раздел. Поэтому вместо использования по умолчанию

    float texture[] = { 
        0.0f, 1.0f, //
        1.0f, 1.0f, //
        0.0f, 0.0f, //
        1.0f, 0.0f, //
    };
    

в качестве матрицы (очевидно, это для загрузки изображения в 2 треугольника), коэффициент обратно пропорционально площади для обрезки, например.

    float texture[] = { 
        0.0f, 0.75f, //
        0.9f, 0.75f, //
        0.0f, 0.0f, //
        0.9f, 0.0f, //
     };

конечно, будь то точным с вашей математикой или нежелательным битом, который может кровоточить, или вы вырезаете часть реального изображения. Очевидно, что этот массив вычисляется "на лету", а не жестко закодирован, как я показал здесь.

Ответ 4

Почему бы вам не создать два растровых изображения. Загрузите первый, как вы делаете, затем используйте createBitmapScaled, чтобы превратить это растровое изображение в два. По производительности я не знаю, возможно ли это самый быстрый способ, но он работает.

Ответ 5

Вы можете использовать GLES20.glTexImage2D() для создания пустой текстуры с заданной шириной и высотой. Пример кода   public static int genTexture (int texWidth, int texHeight) {       int [] textureIds = new int [1];       GLES20.glGenTextures(1, textureIds, 0);       assertNoError();       int textureId = textureIds [0];       texWidth = Utils.nextPowerOf2 (texWidth);       texHeight = Utils.nextPowerOf2 (texHeight);

    GLES20.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
    GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
            texWidth, texHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

    return textureId;
}