BlackBerry - трехмерное преобразование изображений

Я знаю, как повернуть изображение на любой угол с помощью drawTexturePath:

int displayWidth = Display.getWidth();
int displayHeight = Display.getHeight();
int[] x = new int[] { 0, displayWidth, displayWidth, 0 };
int[] x = new int[] { 0, 0, displayHeight, displayHeight };
int angle = Fixed32.toFP( 45 );
int dux = Fixed32.cosd(angle );
int dvx = -Fixed32.sind( angle );
int duy = Fixed32.sind( angle );         
int dvy = Fixed32.cosd( angle );       
graphics.drawTexturedPath( x, y, null, null, 0, 0, dvx, dux, dvy, duy, image);

но мне нужна трехмерная проекция простого изображения с трехмерным преобразованием (что-то вроде это)

Не могли бы вы посоветовать мне, как это сделать с помощью drawTexturedPath (я почти уверен, что это возможно)?
Есть ли альтернативы?


person Maksym Gontar    schedule 31.07.2009    source источник


Ответы (4)


Метод, используемый этой функцией (2 вектора ходьбы), такой же, как уловки кодирования oldskool, используемые для знаменитого эффекта «rotozoomer». пример видео ротозумера

Этот метод - очень быстрый способ поворота, масштабирования и наклона изображения. Вращение выполняется просто вращением векторов блуждания. Масштабирование выполняется простым масштабированием векторов ходьбы. Наклон осуществляется путем поворота движущихся элементов относительно друг друга (например, они больше не образуют угол в 90 градусов).

Nintendo сделала оборудование в своей SNES, чтобы использовать тот же эффект на любых спрайтах и ​​/ или фонах. Это дало возможность получить несколько очень крутых эффектов.

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

На snes они преодолели это, изменив каждую строку развертки в walkvectors (в те дни можно было установить прерывание, когда монитор рисовал любую строку развертки). Этот режим позже назывался MODE 7 (поскольку он вел себя как новый виртуальный вид графики Режим). Самыми известными играми, использующими этот режим, были Mario kart и F-zero.

Итак, чтобы это работало на Blackberry, вам нужно будет рисовать изображение "displayHeight" раз (например, каждый раз, когда одна строка сканирования изображения). Только так можно добиться желаемого эффекта. (Это, несомненно, будет стоить вам снижения производительности, поскольку теперь вы вызываете функцию drawTexturedPath много раз с новыми значениями, а не только один раз).

Я думаю, немного погуглив, вы можете найти некоторые формулы (или даже реализацию), как вычислять различные walkvectors. Имея немного бумаги (учитывая, что вы неплохо разбираетесь в математике), вы тоже можете сделать выводы сами. Я тоже делал это сам, когда делал игры для Gameboy Advance, поэтому знаю, что это возможно.

Обязательно просчитайте все заранее! Скорость - это все (особенно на медленных машинах, таких как телефоны)

РЕДАКТИРОВАТЬ: сделал для вас поиск в Google. Вот подробное объяснение того, как создать эффект mode7. Это поможет вам добиться того же с функцией Blackberry. Реализация режима 7

person Toad    schedule 07.08.2009
comment
Рейнир, спасибо за ответ! Честно говоря, я плохо разбираюсь в математике, поэтому я поднял этот вопрос до награды ... Ваш ответ действительно интересен, и хотя он может решить проблемы с производительностью, я приму его, если вы предоставите Blackberry код для режима 7. - person Maksym Gontar; 08.08.2009
comment
к сожалению, у меня нет ежевики. У меня есть доступ к нему, когда я нахожусь у клиента, выполняя некоторую работу по переносу (которая также включает в себя Blackberry). Но не думаю, что я буду там на следующей неделе. = ^ | - person Toad; 08.08.2009
comment
Я думал, что моя добавленная ссылка объясняет много математики, стоящей за ней ... Вы пытались ее прочитать? - person Toad; 08.08.2009
comment
Ну есть бесплатные тренажеры. Можете ли вы написать хотя бы алгоритм для получения этих значений xv yv xu yu? - person Maksym Gontar; 09.08.2009

С помощью следующего кода вы можете наклонить изображение и получить эффект, похожий на перспективу:

        int displayWidth = Display.getWidth();
        int displayHeight = Display.getHeight();
        int[] x = new int[] { 0, displayWidth, displayWidth, 0 };
        int[] y = new int[] { 0, 0, displayHeight, displayHeight };                

        int dux = Fixed32.toFP(-1);
        int dvx = Fixed32.toFP(1);
        int duy = Fixed32.toFP(1);
        int dvy = Fixed32.toFP(0);
        graphics.drawTexturedPath( x, y, null, null, 0, 0, dvx, dux, dvy, duy, image);

Это приведет к искажению изображения под углом 45 °. Если вы хотите получить определенный угол, вам просто нужно использовать некоторую тригонометрию для определения длины ваших векторов.

person Lucas S.    schedule 04.08.2009
comment
Привет, Лукас, спасибо за ответ. Вы предоставляете простой перекос. Откровенно говоря, мне нужно уметь выполнять любое комбинированное трехмерное преобразование (вращать, наклонять, изменять размер). Более подробно ознакомьтесь с stackoverflow.com/questions/660304/4-point -transform-images, его размер частично изменен, а не просто искажен. Как я сказал, должен быть какой-то способ сделать это, потому что: 1) - они предоставляют аргументы dvx, dux, dvy, duy, которые ведут себя как некая транс-матрица; 2) есть недокументированные методы setMatrix () и setIdentity () в классе net.rim.device.api.ui.Graphics (к сожалению, они не могут заставить их работать) - person Maksym Gontar; 04.08.2009

Спасибо за ответы и рекомендации, +1 всем вам.
РЕЖИМ 7 был способом реализации трехмерного преобразования, но, к сожалению, я не смог сделать drawTexturedPath для изменения размера моих строк сканирования ... поэтому я остановился на простом drawImage.

Предполагая, что у вас есть Bitmap inBmp (входная текстура), создайте новый Bitmap outBmp (выходная текстура).

Bitmap mInBmp = Bitmap.getBitmapResource("map.png");
int inHeight = mInBmp.getHeight();
int inWidth = mInBmp.getWidth();

int outHeight = 0;
int outWidth = 0;
int outDrawX = 0;
int outDrawY = 0;
Bitmap mOutBmp = null;

public Scr() {
    super();
    mOutBmp = getMode7YTransform();
    outWidth = mOutBmp.getWidth();
    outHeight = mOutBmp.getHeight();
    outDrawX = (Display.getWidth() - outWidth) / 2;
    outDrawY = Display.getHeight() - outHeight;
}

Где-то в коде создайте Graphics outBmpGraphics для outBmp.
Затем выполните следующие итерации от начала y до (высота текстуры) * коэффициент преобразования y:
1. создайте строку Bitmap Bmp = new Bitmap (width, 1) для одного line
2. создать графическую строкуBmpGraphics из lineBmp
3. нарисовать строку i от текстуры до lineBmpGraphics
4. закодировать lineBmp в EncodedImage img
5. масштабировать img согласно РЕЖИМУ 7
6. закрасить img в outBmpGraphics
Примечание: BB-порт Ричарда Пакетта PNGEncoder, используемый в моем коде

private Bitmap getMode7YTransform() {
    Bitmap outBmp = new Bitmap(inWidth, inHeight / 2);
    Graphics outBmpGraphics = new Graphics(outBmp);
    for (int i = 0; i < inHeight / 2; i++) {
        Bitmap lineBmp = new Bitmap(inWidth, 1);
        Graphics lineBmpGraphics = new Graphics(lineBmp);
        lineBmpGraphics.drawBitmap(0, 0, inWidth, 1, mInBmp, 0, 2 * i);
        PNGEncoder encoder = new PNGEncoder(lineBmp, true);
        byte[] data = null;
        try {
            data = encoder.encode(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        EncodedImage img = PNGEncodedImage.createEncodedImage(data, 
                0, -1);
        float xScaleFactor = ((float) (inHeight / 2 + i))
                / (float) inHeight;
        img = scaleImage(img, xScaleFactor, 1);
        int startX = (inWidth - img.getScaledWidth()) / 2;
        int imgHeight = img.getScaledHeight();
        int imgWidth = img.getScaledWidth();
        outBmpGraphics.drawImage(startX, i, imgWidth, imgHeight, img, 
                0, 0, 0);
    }
    return outBmp;
}

Тогда просто нарисуйте это краской ()

protected void paint(Graphics graphics) {
    graphics.drawBitmap(outDrawX, outDrawY, outWidth, outHeight, mOutBmp,
            0, 0);
}

Для масштабирования я сделал что-то похожее на метод, описанный в Изменение размера растрового изображения с использованием .scaleImage32 вместо .setScale

private EncodedImage scaleImage(EncodedImage image, float ratioX,
        float ratioY) {

    int currentWidthFixed32 = Fixed32.toFP(image.getWidth());
    int currentHeightFixed32 = Fixed32.toFP(image.getHeight());

    double w = (double) image.getWidth() * ratioX;
    double h = (double) image.getHeight() * ratioY;
    int width = (int) w;
    int height = (int) h;

    int requiredWidthFixed32 = Fixed32.toFP(width);
    int requiredHeightFixed32 = Fixed32.toFP(height);

    int scaleXFixed32 = Fixed32.div(currentWidthFixed32,
            requiredWidthFixed32);
    int scaleYFixed32 = Fixed32.div(currentHeightFixed32,
            requiredHeightFixed32);

    EncodedImage result = image.scaleImage32(scaleXFixed32, scaleYFixed32);
    return result;
}

См. Также
J2ME Mode 7 Floor Renderer - что-то более подробное и захватывающее, если вы пишете 3D-игру!

person Maksym Gontar    schedule 16.08.2009

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

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

У GameDev есть куча статей с исходным кодом здесь:

http://www.gamedev.net/reference/list.asp?categoryid=40#212

В Википедии тоже есть хорошая статья:

http://en.wikipedia.org/wiki/Texture_mapping

Еще один сайт с учебниками по 3D:

http://tfpsly.free.fr/Docs/TomHammersley/index.html

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

person Kristoffon    schedule 07.08.2009
comment
Привет, Кристоффон, спасибо за ответ! Как я понял, я могу рисовать цвет на пиксель, сохранять его один раз в растровом изображении и рисовать это растровое изображение при каждом обновлении. Это медленно, больше, чем нужно рисовать линии в год, но это тоже может быть решением. В качестве доказательства концепции можете ли вы предоставить код ежевики для преобразования перспективы, например, в wholetomato.com/ images / tour / mondoPerspectiveTrans.gif? - person Maksym Gontar; 08.08.2009
comment
Отображение текстур вручную (по 1 пикселю за раз) для j2me замедляет работу. J2me работает «быстро» только тогда, когда он может использовать функции API для выполнения тяжелой работы. - person Toad; 08.08.2009