gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Manual sorting of polygons in 3d

#140083 - Jesse - Thu Sep 13, 2007 1:03 pm

I've been trying to use the 3d-hardware to replace my sprites, since I want access to the nice alpha-formats. The problem is that I can't seem to control in what order my polygons are rendered in. I've been trying to find topics about this and found some that discuss turning off the automatic y-sorting, but it doesn't seem to make a difference for me.

The code below is a good example where the order that the two polygons is rendered on the screen only depends on the y-position, even though I use GL_TRANS_MANUALSORT. On a side-note, it's the other way around when running in DeSmuME where it always render in the call-order.

Does anyone have any idea of how to solve this?


Code:
#include <nds.h>
#include <stdlib.h>

void DrawQuad(int _PosX, int _PosY, int _Color, int _TextureID)
{
   int Size = 64;
   int x0 = (1 << 11) / 256 + (_PosX - 128) * (1 << 12) / 128;
   int x1 = (1 << 11) / 256 + (_PosX + Size - 128) * (1 << 12) / 128;
   int y0 = (1 << 11) / 192 + (96 - _PosY) * (1 << 12) / 96;
   int y1 = (1 << 11) / 192 + (96 - _PosY - Size) * (1 << 12) / 96;

   glBindTexture(0, _TextureID);
   glBegin(GL_QUAD);
   glNormal(NORMAL_PACK(0,inttov10(-1),0));
   glColor3b(_Color >> 16, _Color >> 8, _Color);

   glTexCoord2t16(inttot16(64), 0);
   glVertex3v16(x1, y0, 0);
   glTexCoord2t16(0, 0);
   glVertex3v16(x0, y0, 0);
   glTexCoord2t16(0, inttot16(64));
   glVertex3v16(x0, y1, 0);
   glTexCoord2t16(inttot16(64), inttot16(64));
   glVertex3v16(x1, y1, 0);

   glEnd();
}

int main()
{
   powerON(POWER_ALL);
   irqInit();
   irqEnable(IRQ_VBLANK);
   lcdMainOnBottom();
   videoSetMode(MODE_0_3D);
   vramSetMainBanks(VRAM_A_TEXTURE_SLOT0, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);

   glInit();
   glEnable(GL_TEXTURE_2D);
   glViewPort(0,0,255,191);

   short *pBuf = new short[64 * 64];
   for(int i = 0; i < 64 * 64; i++)
   {
      int x = (i & 63);
      int y = (i >> 6);
      if(x == 0 || x == 63 || y == 0 || y == 63)
         pBuf[i] = 0x801f;
      else if((x & 1) || (y & 1))
         pBuf[i] = 0xffff;
      else
         pBuf[i] = 0x8000;
   }

   int textureID;
   glGenTextures(1, &textureID);
   glBindTexture(0, textureID);
   glTexImage2D(0, 0, GL_RGBA, TEXTURE_SIZE_64, TEXTURE_SIZE_64, 0, TEXGEN_TEXCOORD, (u8*)pBuf);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   
   glMaterialf(GL_AMBIENT, RGB15(16,16,16));
   glMaterialf(GL_DIFFUSE, RGB15(16,16,16));
   glMaterialf(GL_SPECULAR, BIT(15) | RGB15(8,8,8));
   glMaterialf(GL_EMISSION, RGB15(16,16,16));
   glMaterialShinyness();

   glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK);

   int nFrame = 0;
   while(1)
   {
      nFrame = (nFrame + 1) & 127;
      DrawQuad(nFrame, nFrame, 0xffffffff, textureID);
      DrawQuad(128 - nFrame, 128 - nFrame, 0xffff00ff, textureID);

      glFlush(GL_TRANS_MANUALSORT);

      swiWaitForVBlank();
   }

   return 0;
}

#140084 - Jesse - Thu Sep 13, 2007 1:09 pm

By the way, this may be a good example of how to render textured quads pixel-perfect with the 3d-hardware. It took me far too much time to get everything right. :)

#140088 - a128 - Thu Sep 13, 2007 1:56 pm

Jesse wrote:


Code:


      glFlush(GL_TRANS_MANUALSORT);

      swiWaitForVBlank();
   }

}


swiWaitForVBlank(); is not need after glFlush()

#140091 - kusma - Thu Sep 13, 2007 2:10 pm

a128 wrote:
swiWaitForVBlank(); is not need after glFlush()

In normal OpenGL glFlush() is just supposed to guarantee that rendering will finish within finite time, not to do any updates or change any state. Conceptually, it shouldn't wait for the next vblank or swap any buffers. After browsing the source code for videoGL, it seems that the glFlush() implementation is somewhat confused with the windowing-systems buffer swapping routines. I'd personally much more prefer calling it something else than glFlush() since that easily leads to confusions for those of us who are pretty much fluent at OpenGL.

#140093 - Jesse - Thu Sep 13, 2007 2:27 pm

kusma wrote:
After browsing the source code for videoGL, it seems that the glFlush() implementation is somewhat confused with the windowing-systems buffer swapping routines.

Hmm. What do you mean? The only implementation of glFlush I can find is:
Code:
GL_STATIC_INL void glFlush(uint32 mode) { GFX_FLUSH = mode; }

So this code waits for VBlank? Strange... (but of course has nothing to do with my problem. :)

#140094 - M3d10n - Thu Sep 13, 2007 2:28 pm

a128 wrote:
Jesse wrote:


Code:


      glFlush(GL_TRANS_MANUALSORT);

      swiWaitForVBlank();
   }

}


swiWaitForVBlank(); is not need after glFlush()


For rendering, no it isn't (the screen will religiously update at 60fps). But for keeping the game logic running at constant speed, yes it is required.

Back on topic: Jesse, did you try assigning a different poly ID for each quad? I think alpha-blended polygons with the same ID can't blend against each other, but I'm not sure.

#140096 - kusma - Thu Sep 13, 2007 2:57 pm

Jesse wrote:

Hmm. What do you mean? The only implementation of glFlush I can find is:
Code:
GL_STATIC_INL void glFlush(uint32 mode) { GFX_FLUSH = mode; }


Yeah, and GFX_FLUSH is what is documented in gbatek as
Quote:
4000540h - Cmd 50h - SWAP_BUFFERS - Swap Rendering Engine Buffer (W)
SwapBuffers exchanges the two sets of Polygon/Vertex RAM buffers, that is, the newly defined polygons/vertices are passed to the rendering engine (and will be displayed in following frame(s)). The other buffer is emptied, and passed to the Geometry Engine (to be filled with new polygons/vertices by Geometry Commands).

0 Translucent polygon Y-sorting (0=Auto-sort, 1=Manual-sort)
1 Depth Buffering (0=With Z-value, 1=With W-value)
(mode 1 does not function properly with orthogonal projections)
2-31 Not used

SwapBuffers isn't executed until next VBlank (Scanline 192) (the Geometry Engine is halted for that duration). SwapBuffers should not be issued within Begin/End.

This differs quite a lot from the operation of glFlush().

Quote:

So this code waits for VBlank? Strange... (but of course has nothing to do with my problem. :)

No, it does not. But it doesn't reach the rendering engine until the next vblank.

#140102 - Jesse - Thu Sep 13, 2007 4:21 pm

M3d10n wrote:
Back on topic: Jesse, did you try assigning a different poly ID for each quad? I think alpha-blended polygons with the same ID can't blend against each other, but I'm not sure.

I tried this now:
Code:
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK | POLY_ID(0));
DrawQuad(nFrame, nFrame, 0xffffffff, textureID);
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_BACK | POLY_ID(1));
DrawQuad(128 - nFrame, 128 - nFrame, 0xffff00ff, textureID);


With no change. The polygons are still switching order depending on y-position.

#140106 - Peter - Thu Sep 13, 2007 5:25 pm

Jesse wrote:
On a side-note, it's the other way around when running in DeSmuME where it always render in the call-order.

So far DeSmuME (v1.0.18a) wasn't able to emulate any of my 3D programs correctly. I have much better results with no$gba, though it lacks of some 3D features but it's much closer to what the hardware displays. My little experience with NDS 3D programming is to only trust the real hardware though!
_________________
Kind Regards,
Peter

#140111 - Sunray - Thu Sep 13, 2007 5:51 pm

Edit: Forget what I said. I misread.

#153999 - SiW - Wed Apr 09, 2008 4:41 am

Did you ever solve this, Jesse? Because I'm having exactly the same issue.

#154003 - a128 - Wed Apr 09, 2008 8:53 am

The "Y-Problem" is one of those unsolved!!!? problems.

I hope there is a solution...or somethink like "No it can't be solved"

#154007 - Sunray - Wed Apr 09, 2008 9:57 am

I don't know. I've never had any problems with this myself. :O

What's important is that you specify a z value for each layer of sprites and not 0 for every vertex.

#154021 - SiW - Wed Apr 09, 2008 3:31 pm

Yeah, my workaround is to auto-increment the z value every time I draw a quad (resetting it each frame, of course). Which, now that I think about, is the same method I use in PSPGL game of mine to ensure reliable sort order, heh.

Although I still had trouble on the DS, so I looked around at other 2D-as-3D implementations and changed my glOrtho setup to match uLib's glOrthof32(0, 256, 192, 0, -2045, 1). This isn't exactly intuitive, but it does work.

#154023 - M3d10n - Wed Apr 09, 2008 5:08 pm

It makes sense because you cannot turn off depth-testing on the DS, so even if you draw sprite A first and sprite B later, the one with the smaller Z will be on front. But this is a good thing, since this mean you can sort the sprites by assigned sorted Z values, instead of having to sort them in a list.

#154024 - Noda - Wed Apr 09, 2008 5:26 pm

Take a look at the PAlib or uLibrary sources, they're doing exactly what you want perfectly ;)

#154026 - SiW - Wed Apr 09, 2008 5:46 pm

Well I did just say I looked at uLib ;)