Sign in to follow this  
Seiko

MDX - Precise quad sizes?

Recommended Posts

Seiko    122
A few days ago I had a texture mapping problem. In short I could not and can still not map a section of a 512x512 (32x32) texture to a quad using point sampling without texture alignment problems. After several days of painful debugging it seems that either my quad sizes are not accurate enough to allow explicit point sampling texture mapping or my transforms are inaccurate thus not showing the full 32x32 pixels of each quad. As I've tested by rendering the same texture (albeit with various textures taken from the 512x512 map) for each tile and as on many of the tiles the texture is perfect I'm thinking the actual texture mapping is fine and the problem must be with my geometry or view trasnforms. BTW, when I say corruption I mean I'm rendering a simple square texture that has a 1 pixel internal square border. I've left a 5 pixel boundary so it's not an edge problem and yet the 1 pixel border looses one of it's lines on certain tile positions. As it's the entire line, i.e. on one tile the top line might be missing it just seems that the pixels and texels are not aligned for certain quads? As such I'd like to know if it is possible to guarantee a perfect 32x32 pixel quad (2 tris) irrespective of position on screen. This is obviously in relation to a top down tiled map but with every 4th/5th row/column currently showing signs of texture corruption i.e. one pixel/texel isn't aligned I suspect that the precision of a (single vb.net) means that I'm not guaranteed a 32x32 quad for each of my tile positions. You can see the maths below and with both the x and y using decimals I wonder if this means that quad boundaries vary ever so slightly? update : pic here http://img8.picsplace.to/img8/1/problem_000.jpg Can someone please assist this newbie as I've lost countless hours on this and don't seem to be getting any closer to a solution. BTW, here are my constants, transforms and vertex construction code snippets.
  Private Const cInternalScreenWidth As Integer = 1024
  Private Const cInternalScreenHeight As Integer = 768
  Private Const cMapTileWidth As Integer = 32
  Private Const cMapTileHeight As Integer = 32
  Private Const cTilePerScreenWidth As Integer = CInt(cInternalScreenWidth / cMapTileWidth)
  Private Const cTilePerScreenHeight As Integer = CInt(cInternalScreenHeight / cMapTileHeight)
  Private Const cTextureWidthScale As Single = 10 / cTilePerScreenWidth
  Private Const cTextureHeightScale As Single = 10 / cTilePerScreenHeight
 
--------------------------------------------------------------------------------
 'Matrices
  .Transform.World = Matrix.Identity 

  .Transform.View = Matrix.LookAtLH(New Vector3(Xposition, Yposition, 9), New Vector3(Xposition, Yposition, 0), New Vector3(0.0F, 1.0F, 0.0F))

  .Transform.Projection = Matrix.PerspectiveFovLH(1, 1.0F, 0.0F, 5.0F)
 

--------------------------------------------------------------------------------
 'Tile Vertex calcualtions for the entire map
 'cTextureWidthScale = 0.3125       -- Noted here for convenience
 'cTextureHeightScale = 0.416666657 -- Noted here for convenience

 For RowLoop As Integer = 0 To TotalVerticalMapTiles - 1
      For ColumnLoop As Integer = 0 To TotalHorizontalMapTiles - 1
        With MapTiles(ColumnLoop, RowLoop)
        
          'Assign verts and textures Triangle 1
          .X(1) = 6 - ((ColumnLoop + 1) * cTextureWidthScale)
          .Y(1) = 6 - (RowLoop * cTextureHeightScale)
        
          .X(2) = .X(1)
          .Y(2) = 6 - ((RowLoop + 1) * cTextureHeightScale)
        
          .X(3) = 6 - (ColumnLoop * cTextureWidthScale)
          .Y(3) = .Y(1)
        
          'Triangle 2
          .X(4) = .X(3)
          .Y(4) = .Y(2)
        
          .X(5) = .X(3)
          .Y(5) = .Y(1)
        
          .X(6) = .X(1)
          .Y(6) = .Y(2)
        
        End With

        TileCount = TileCount + 1

      Next ColumnLoop
    Next RowLoop

-------------------------------------------------------------------------------
 'Texture Coordiantes mappings
 Dim TexturesPerRow As Single = CSng(TemplateTextureWidth / cMapTileWidth)
 Dim TexturesPerColumn As Single = CSng(TemplateTextureHeight / cMapTileHeight)
 Dim Alignment As Single = CSng(1 / (TemplateTextureWidth * 2))

 ReDim MapTextures(CInt(TexturesPerRow * TexturesPerColumn))
 Dim OffsetX,OffsetY As Single

 For TextureNumber As Integer = 1 To (CInt(TexturesPerRow * TexturesPerColumn))

      OffsetX = CSng(((TextureNumber - ((Int(TextureNumber / TexturesPerRow) * TexturesPerRow))) * (cMapTileWidth)) - (cMapTileWidth - 2)) - 1
      OffsetY = CSng((Int(TextureNumber / TexturesPerColumn)) * (cMapTileHeight)) + 1

      With MapTextures(TextureNumber)
        ReDim .tu(6)
        ReDim .tv(6)

        .tu(1) = ((OffsetX + (cMapTileWidth - 2)) / TemplateTextureWidth) - Alignment
        .tv(1) = (OffsetY / TemplateTextureHeight) - Alignment

        .tu(2) = .tu(1)
        .tv(2) = ((OffsetY + (cMapTileHeight - 2)) / TemplateTextureHeight) - Alignment

        .tu(3) = (OffsetX / TemplateTextureWidth) - Alignment
        .tv(3) = .tv(1)

        .tu(4) = .tu(3)
        .tv(4) = .tv(2)

        .tu(5) = .tu(3)
        .tv(5) = .tv(1)

        .tu(6) = .tu(1)
        .tv(6) = .tv(2)

      End With
    Next TextureNumber





[Edited by - Seiko on November 24, 2005 8:38:27 AM]

Share this post


Link to post
Share on other sites
Demirug    884
Have you already check this out: http://msdn.microsoft.com/library/en-us/directx9_c/Directly_Mapping_Texels_to_Pixels.asp?frame=true

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Demirug
Have you already check this out: http://msdn.microsoft.com/library/en-us/directx9_c/Directly_Mapping_Texels_to_Pixels.asp?frame=true


Yep, that's why I think it's my geometry or projection. The fact that the same texture is ok on certain tiles suggests to me at least that the texture mapping is fine. Note too that the texture mapping are precalculated once only and then reused for the tiles. So my logic says if it is ok for one tile why not for another?

Share this post


Link to post
Share on other sites
Demirug    884
I would assume a rounding problem with your vertex cords.

Have you tried working with pre transformed vertices? In the case of 2D with perfect texel to pixel mapping this is normally the better way.

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Demirug
I would assume a rounding problem with your vertex cords.

Have you tried working with pre transformed vertices? In the case of 2D with perfect texel to pixel mapping this is normally the better way.


I did contemplate switching to pre transformed vertices but I really wanted to create a baseline using none transformed vertices as I use alot of matrices for the sprites movement and rotation. Although I could still no doubt use the matrices I was hoping to then bolster the engine with simplified lighting and shadowing techniques as my understanding progresses. Alas, I'm failing on the first task as I can't even control the precise quad size. (lol). I thought I could try and clamp values or something but I'm not really sure which values to clamp, round up or down!

Share this post


Link to post
Share on other sites
Demirug    884
First off all you should make sure that your vertex cords are the problem. Can you render the tiles as wireframe and make a screenshot? This will make it possible to check the size of each tile. If they are not all 32*32 you can limit your search to the vertex cords.

As I don’t know the rest of your code it is possible that I am wrong but your matrix setup looks a little bit unusual for a 2D game.

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Demirug
First off all you should make sure that your vertex cords are the problem. Can you render the tiles as wireframe and make a screenshot? This will make it possible to check the size of each tile. If they are not all 32*32 you can limit your search to the vertex cords.

As I don’t know the rest of your code it is possible that I am wrong but your matrix setup looks a little bit unusual for a 2D game.


My quads, including the wireframe lines are actually 36x35 pixels which you'd think would cause the problem but as I'm clamping the textures I thought I would see an area not covered or taken from an adajecent texel? If a single texel is applied to two pixels then I would have simply concluded that the texture mapping is incorrect due to the size but as I actually looose a texel it suggests to me that my transforms are the problem?

This really is a pain to get to the bottom of. BTW, thanks for the support!
:(

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Demirug
Do you lost the texel inside the tile or on they edge?

Can post a screenshot that shows the problem?


Alas, I have no where to post a screen shot although I have now found out that my quad sizes are definately wrong in the areas with the texture problem. For the correctly textured tiles the quads are 36x35 however on the incorrect columns the quads are 37x35 thus the mapping gets a little skewed. This must be either my vertex construction or my projections? As for the textel loss or gain dependant on how I tweak my code it is well within the 32x32 texture area.

So how can I create a map of tiles that do not suffer from this imprecision?

Share this post


Link to post
Share on other sites
Usually I'm working in an ortho view when dealing with this problem but it may still work here. Generally, all of my 2D grapgics-objects have a few extra floating point memebers used for baising either the texture coordiantes, the vertex space coordiantes or even both. Generally these numbers are tiny say, 0.0005f Sometimes this does the trick, but the real problem is when I go to test on different hardrware. Nearly every card samples and rounds a different way and I'm still figuring a way around this. One way, belive it or not, is to use the baising along with bi-linear texture filtering. If the textures are designed well and the bais is just right, it seems to look pretty good on nearly every card.

Since you are working in perspective though, I really don't think there is any way that you can expect to properly map texles to pixels. Most hardware is concerned with speed, not accuracy.

Share this post


Link to post
Share on other sites
Demirug    884
You can upload images there: http://picsplace.to/

Maybe it is both. I am still not understand the reason for your view and projection matrix you are use. Do you have copy this from some 3D sample?

For 2D you can use Identity or set the view matrix to a scale matrix that allows you to use real pixel coordinates for your vertices. Maybe I have an example an my system but I am normally don’t use vb for my DX stuff.

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Demirug
You can upload images there: http://picsplace.to/

Maybe it is both. I am still not understand the reason for your view and projection matrix you are use. Do you have copy this from some 3D sample?

For 2D you can use Identity or set the view matrix to a scale matrix that allows you to use real pixel coordinates for your vertices. Maybe I have an example an my system but I am normally don’t use vb for my DX stuff.


Ah thanks, I've uploaded the pic. This is a simple map of tiles. There are two 32x32 textures being used from within one 512x512 texture. As you can see some tiles are not shown correctly. They are effected in columns and rows.

http://img8.picsplace.to/img8/1/problem_000.jpg

As for the matrix. It's just one I set up having browsed a number of examples. This allows me to scroll and keep an overhead view. i.e top down scroller.

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by lack o comments
Usually I'm working in an ortho view when dealing with this problem but it may still work here. Generally, all of my 2D grapgics-objects have a few extra floating point memebers used for baising either the texture coordiantes, the vertex space coordiantes or even both. Generally these numbers are tiny say, 0.0005f Sometimes this does the trick, but the real problem is when I go to test on different hardrware. Nearly every card samples and rounds a different way and I'm still figuring a way around this. One way, belive it or not, is to use the baising along with bi-linear texture filtering. If the textures are designed well and the bais is just right, it seems to look pretty good on nearly every card.

Since you are working in perspective though, I really don't think there is any way that you can expect to properly map texles to pixels. Most hardware is concerned with speed, not accuracy.


Thanks, yes I had thought of that but as my maps are going to quite large I didn't want to have to try and apply offsets per column/row to my geometry. As for the cards, I've tested this on three albeit ATI cards, 9600, x700 and x800.
All show the same problem.

Share this post


Link to post
Share on other sites
mohamed adel    174
Quote:
Original post by Demirug
I would assume a rounding problem with your vertex cords.

Have you tried working with pre transformed vertices? In the case of 2D with perfect texel to pixel mapping this is normally the better way.


Excerpt from Tom Miller's blogs:

"When a Direct3D device is created, the runtime will change the Floating point unit to suit its needs (by default switch to single precision, the default for the CLR is double precision). This is done because it has better performance than double precision (naturally). When creating the device you should use the CreateFlags.FpuPreserve flag to keep the CLR's double precision."

Are you working with a single or double precission?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Quote:
Original post by mohamed adel
Quote:
Original post by Demirug
I would assume a rounding problem with your vertex cords.

Have you tried working with pre transformed vertices? In the case of 2D with perfect texel to pixel mapping this is normally the better way.


Excerpt from Tom Miller's blogs:

"When a Direct3D device is created, the runtime will change the Floating point unit to suit its needs (by default switch to single precision, the default for the CLR is double precision). This is done because it has better performance than double precision (naturally). When creating the device you should use the CreateFlags.FpuPreserve flag to keep the CLR's double precision."

Are you working with a single or double precission?


Hmmm, thats interesting I'll see what happens. Many thanks.

Share this post


Link to post
Share on other sites
Seiko    122
Quote:
Original post by Anonymous Poster
Quote:
Original post by mohamed adel
Quote:
Original post by Demirug
I would assume a rounding problem with your vertex cords.

Have you tried working with pre transformed vertices? In the case of 2D with perfect texel to pixel mapping this is normally the better way.


Excerpt from Tom Miller's blogs:

"When a Direct3D device is created, the runtime will change the Floating point unit to suit its needs (by default switch to single precision, the default for the CLR is double precision). This is done because it has better performance than double precision (naturally). When creating the device you should use the CreateFlags.FpuPreserve flag to keep the CLR's double precision."

Are you working with a single or double precission?


Hmmm, thats interesting I'll see what happens. Many thanks.


Alas, it has no effect
:(

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this