黑莓 - 图像3D变换

时间:2009-07-31 13:49:03

标签: graphics blackberry java-me 3d

我知道如何使用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);

但我需要的是3d projection带有3d变换的简单图像(类似于this

你能告诉我如何使用drawTexturedPath(我几乎可以肯定这是可能的)吗? 还有其他选择吗?

4 个答案:

答案 0 :(得分:6)

此函数使用的方法(2个步行向量)与用于着名的“rotozoomer”效果的oldskool编码技巧相同。 rotozoomer example video

此方法是一种非常快速的旋转,缩放和倾斜图像的方法。只需旋转步行矢量即可完成旋转。简单地通过缩放步行向量来完成缩放。通过相对于彼此旋转助行器来完成偏斜(例如,它们不再成90度角)。

任天堂已经在他们的SNES中制造硬件,以对任何精灵和/或背景使用相同的效果。这为一些非常酷的效果让路。

这种技术的一个很大的缺点是人们不能透视地扭曲纹理。要做到这一点,每个新的水平线,步行矢量应该稍微改变。 (没有图纸很难解释)。

在snes上,他们通过改变walkvectors的每个扫描线来克服这个问题(在那些日子里,当监视器绘制任何扫描线时,可以设置中断)。此模式后来被称为MODE 7(因为它表现得像一种新的虚拟图形模式)。使用这种模式最着名的游戏是Mario kart和F-zero

因此,为了让这个工作在黑莓上,你必须绘制你的图像“displayHeight”次(例如,每次图像的一条扫描线)。这是达到预期效果的唯一方法。 (这无疑会让你受到性能损失,因为你现在用新值调用drawTexturedPath函数很多次,而不只是一次)。

我想通过一些谷歌搜索你可以找到一些公式(甚至实现)如何计算变化的walkvectors。有了一点纸(考虑到你的数学不太糟糕),你也可以自己推断它。当我为Gameboy Advance制作游戏时,我也是自己做的,所以我知道它可以完成。

务必预先确定一切!速度就是一切(尤其是在像手机这样的慢速机器上)

编辑:为你做了一些谷歌搜索。以下是如何创建mode7效果的详细说明。这将帮助您实现与Blackberry功能相同的功能。 Mode 7 implementation

答案 1 :(得分:2)

使用以下代码,您可以扭曲图像并获得类似效果的视角:

        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º的角度倾斜,如果你想要某个角度,你只需要使用一些三角法来确定矢量的长度。

答案 2 :(得分:2)

感谢您的回答和指导,给大家+1 MODE 7是我选择实现3D转换的方式,但不幸的是我无法使drawTexturedPath调整我的扫描线的大小......所以我选择了简单的drawImage。

假设您有一个位图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;
}

代码中的某处为outBmp创建一个Graphics outBmpGraphics 然后在从开始y到(纹理高度)* y变换因子的迭代中进行跟随:
1.为一行创建一个Bitmap lineBmp = new Bitmap(width,1) 2.从lineBmp中创建Graphics lineBmpGraphics 3.paint i从纹理到lineBmpGraphics的线 4.将lineBmp编码为EncodedImage img
5.根据MODE 7的尺度img 6.paint img to outBmpGraphics
注意: Richard Puckett's PNGEncoder BB port used in my code

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;
}

然后在paint()

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

为了扩展,我做了类似于Resizing a Bitmap using .scaleImage32 instead of .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游戏,那就太激动了!

答案 3 :(得分:1)

你想做纹理贴图,那个功能不会削减它。也许你可以克服它,但更好的选择是使用纹理映射算法。

对于每行像素,这涉及确定形状的边缘以及这些屏幕像素映射到的形状上的位置(纹理像素)。实际上并不是那么难,但可能需要一些工作。你只会画一次这张照片。

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

在你的位置,我会寻找一个简单的演示程序,它做了一些你想要的东西,并使用他们的资源作为基础来开发我自己的 - 或者甚至找到一个便携式源库,我确定必须有一个少。