2009-07-31 7 views
3

Je sais comment faire pivoter l'image sur un angle avec drawTexturePath:BlackBerry - image 3D transformer

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

mais ce que je besoin est un 3d projection d'image simple avec la transformation 3D (quelque chose comme this)

Can S'il vous plaît, conseillez-moi comment faire cela avec drawTexturedPath (je suis presque sûr que c'est possible)?
Y a-t-il des alternatives?

Répondre

6

La méthode utilisée par cette fonction (2 vecteurs de marche) est la même que les astuces de codage oldskool utilisées pour le célèbre effet «rotozoomer». rotozoomer example video

Cette méthode est un moyen très rapide de faire pivoter, zoomer et incliner une image. La rotation est faite simplement en faisant tourner les vecteurs de marche. Le zoom est fait simplement en mettant à l'échelle les vecteurs de marche. L'inclinaison est réalisée en faisant tourner les baladeurs les uns par rapport aux autres (par exemple, ils ne font plus un angle de 90 degrés).

Nintendo avait fabriqué du matériel dans sa SNES pour utiliser le même effet sur les sprites et/ou arrière-plans. Cela a fait place à des effets très cool. Un gros inconvénient de cette technique est que l'on ne peut pas déformer une texture de façon perspective. Pour ce faire, à chaque nouvelle ligne horizontale, les vecteurs de marche doivent être légèrement modifiés. (difficile à expliquer sans un dessin). Sur le marché, ils ont surmonté cela en changeant chaque ligne de balayage des walkvectors (à cette époque, on pouvait définir une interruption lorsque le moniteur dessinait une ligne de balayage). Ce mode a ensuite été appelé MODE 7 (car il se comportait comme un nouveau type de mode graphique virtuel). Les jeux les plus célèbres utilisant ce mode étaient Mario kart et F-zero

Donc, pour que cela fonctionne sur la mûre, vous devrez dessiner votre image "displayHeight" fois (par exemple, chaque fois une ligne de balayage de l'image). C'est le seul moyen d'obtenir l'effet désiré. (Cela vous coûtera sans aucun doute un coup de performance puisque vous appelez maintenant la fonction drawTexturedPath beaucoup de fois avec de nouvelles valeurs, au lieu d'une seule fois). Je suppose avec un peu de googling que vous pouvez trouver quelques formules (ou même une implémentation) comment calculer les différents walkvectors. Avec un peu de papier (étant donné que vous n'êtes pas trop mauvais en maths), vous pourriez en déduire vous-même. Je l'ai fait moi-même quand je faisais des jeux pour le Gameboy Advance, donc je sais que ça peut être fait.

Assurez-vous de tout précalculer! La vitesse est tout (en particulier sur les machines lentes comme les téléphones)

EDIT: a fait un peu de googling pour vous. Voici une explication détaillée sur la façon de créer l'effet mode7. Cela vous aidera à atteindre la même chose avec la fonction Blackberry. Mode 7 implementation

+0

Reinier, merci pour la réponse! Pour être sérieux, je suis mauvais en maths, c'est pourquoi j'ai pris cette question à la prime ... Votre réponse est vraiment intéressante, et bien qu'elle puisse résoudre des problèmes de performance, je l'accepterai si vous fournissez un Blackberry code pour un mode 7. –

+0

malheureusement, je ne possède pas une mûre. J'y ai accès quand je suis chez un client qui fait du portage (ce qui implique aussi le blackberry). Ne pense pas que je serai là la semaine prochaine cependant. =^| – Toad

+0

Je pensais que mon lien ajouté expliquait beaucoup de maths impliqués ... Avez-vous essayé de le lire? – Toad

2

Avec le code suivant, vous pouvez incliner votre image et obtenir un point de vue comme effet:

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

Cela biaiser votre image dans un angle de 45 °, si vous voulez un certain angle, vous avez juste besoin d'utiliser un peu de trigonométrie pour déterminer les longueurs de vos vecteurs.

+0

Salut Lucas, merci pour votre réponse. Ce que vous fournissez est un simple biais. Franchement, je dois être capable de faire n'importe quelle transformation 3D combinée (rotation, inclinaison, redimensionnement). Jetez un coup d'oeil à http://stackoverflow.com/questions/660304/4-point-transform-images, son redimensionné en partie, pas seulement asymétrique.Comme je l'ai dit, il devrait y avoir un moyen de le faire, car: 1) - ils fournissent des arguments dvx, dux, dvy, duy qui se comportent comme des matrices trans; 2) il existe des méthodes setMatrix() et setIdentity() non documentées dans la classe net.rim.device.api.ui.Graphics (malheureusement, elles ne peuvent pas fonctionner) –

1

Vous souhaitez effectuer un mappage de texture et cette fonction ne le coupe pas. Peut-être que vous pouvez le contourner mais la meilleure option est d'utiliser un algorithme de mappage de texture.

Cela implique, pour chaque ligne de pixels, de déterminer les bords de la forme et où sur la forme ces pixels d'écran mappent (les pixels de texture). Ce n'est pas si dur en fait, mais cela peut prendre un peu de travail. Et vous ne dessinerez l'image qu'une seule fois.

GameDev a un tas d'articles avec code source ici:

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

Wikipedia a aussi un bel article:

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

Un autre site avec des tutoriels 3D:

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

À votre place, je chercherais un programme de démonstration simple qui ferait quelque chose de proche de ce que vous voulez et utiliserais ses sources comme base pour développer le mien - ou même trouver une bibliothèque source portable, je suis sûr qu'il doit y avoir un peu.

+0

Salut Kristoffon, merci pour la réponse! Comme je l'ai compris, je peux peindre la couleur par pixel, l'enregistrer une fois en mode point, et dessiner ce bitmap sur chaque actualisation. C'est lent, plus que dessiner ligne par an, mais peut aussi être une solution. Pour preuve de concept, pouvez-vous fournir le code Blackberry pour la transformation de perspective, comme dans http://www.wholetomato.com/images/tour/mondoPerspectiveTrans.gif? –

+0

Le mappage de texture à la main (donc 1 pixel à la fois) est un moyen de ralentir pour j2me. J2me est seulement 'rapide' quand il peut utiliser les fonctions de l'API pour faire le gros du travail. – Toad

2

Merci pour les réponses et les conseils, +1 à vous tous.
Le MODE 7 était la façon dont j'ai choisi d'implémenter la transformation 3D, mais malheureusement je ne pouvais pas faire drawTexturedPath pour redimensionner mes lignes de balayage ... donc je suis descendu à drawImage simple.

En supposant que vous avez un bitmap inBmp (texture d'entrée), créez un nouveau bitmap outBmp (texture de sortie).

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

Quelque part dans le code, créez un Graphics outBMPGraphics pour outBmp.
Alors ne suit dans l'itération du début à y (hauteur de texture) * y transform facteur:
1.Créez un Bitmap lineBmp = new Bitmap (largeur, 1) pour une ligne
2.Créez un lineBmpGraphics graphique de lineBmp
3.paint i la ligne de texture à lineBmpGraphics
4.encode lineBmp à EncodedImage img img
5.scale selon le mode 7
6.paint img à outBmpGraphics
note: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; 
} 

Ensuite, il suffit dessiner dans la peinture()

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

à l'échelle, j'ai faire quelque chose similaire à la méthode décrite dans 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; 
} 

Voir aussi
J2ME Mode 7 Floor Renderer - quelque chose de beaucoup plus détaillé & excitant si vous écrivez un jeu en 3D!