Android Opengl-es загружает несиловые 2 текстуры - PullRequest
10 голосов
/ 18 апреля 2011

У меня есть приложение, с которым я неоднократно играл в 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. В настоящее время я предварительно редактирую текстуры в фотошопе, чтобы они имели степень 2 и просто имели пустые границы. Однако это немного утомительно, и я хочу иметь возможность загружать их такими, какие они есть ... распознавать, что они не имеют степени 2, и загружать их в текстуру, которая есть.

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

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

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

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

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

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

Редактировать: пояснил, что я использую opengl.

Ответы [ 5 ]

4 голосов
/ 19 апреля 2011

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

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

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

2 голосов
/ 09 сентября 2011

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

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

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

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

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

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

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

2 голосов
/ 28 апреля 2011

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

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

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

0 голосов
/ 22 декабря 2014

Вы можете использовать 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;
}
0 голосов
/ 03 июня 2011

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

...