MeshTextureCoords

Started by
10 comments, last by haegarr 15 years, 6 months ago
Hi guys, this is not my usual forum but I think I need a little help from the hard core direct x guys for a simple problem. I resently made a .x file import to so convert models to another model format used by this game engine I'm playing with. I hit a snag with the texture coords. The model format of that engine needs the uvs to be from 0 to 1 and does not support tiling as I have resently learned that is an option in x files... I need to convert the x file uv coords to values ranging from 0 to 1 while "trying" to keep the model relatively intact. However, the best I was able to achieve was having some of the uvs mapped right while some mapped to the opposite side of the texture... So mapping the wrong spot on the texture... example x file MeshTextureCoords { 192; 1.122074;-0.880759;, 1.122074;-1.005673;, 0.992163;-1.005674;, 0.992164;-0.880759;, 2.990794;-1.135585;, 2.865879;-1.135585;, 2.865879;-1.005674;, 2.990794;-1.005674;, 0.992163;-0.124404;, 0.992163;-0.006360;, 1.122074;-0.006360;, 1.122074;-0.124403;, 1.122074;-0.124403;, 1.122074;-0.880759;, 0.992164;-0.880759;, 0.992163;-0.124404;, ... 0.122760;-1.005675;, 0.122760;-1.140582;, -0.007151;-1.140582;, -0.007151;-1.005675;, ... I tried various things like droping the integer if it's not 1 or -1 and move the coord to 1+v if v was negative... and a lot of different other things... I simply lack the right understanding to properly convert the various posibilities to a 0-1 range without breaking something or fix something while breaking something else. Does anyone here know the right formula for what I'm trying to do?
Advertisement
Welcome, icuurd12b42. I'm not a D3D expert. And I'm also not sure whether the following thoughts are correct, but I assume so... of course I do :)

Wrapping the (u,v) co-ordinates around isn't the only thing to do. A wrapping is done by a simple formula like
a' := a - floor( a ) for u,v

However, assume a triangle that uses an u=0.9 at one vertex and a u=1.1 at another one. With a wrapping interpolation, the texels read will be at positions 0.9 to 1.0, and from 0.0 to 0.1. Now, by wrapping the co-ordinates one-by-one (i.e. w/o looking at all 3 vertices at once), you get u'=0.9 and u'=0.1, so that an interpolation is going from 0.9 down to 0.1, what is obviously something very different.

Hence, for general textures, you need to do more than just to wrap co-ordinates. It must be possible to interpolate by exceeding the texture's border, since reversing the interpolation direction is normally not allowed (it may be allowed if the texture is symmetric, but that is not the general case, isn't it?). Assuming that no single triangle covers the entire texture, it should work to generate a new texture that is 2 times(*) as big as the original one in both dimensions. Then the original texture can be replicated 2x2 times into the new texture. By this way a triangle exceeding a border in the original texture can be mapped overlapping the middle axes of the new texture.

Then the vertices of each triangle are to be shifted so that their u,v's are all in [0,2). The resulting co-ordinates are to be scaled by 0.5, of course, to yield in the correct relative texture co-ordinates matching the new texture.

(*) if no texture resolution should be lost, else you can choose a smaller texture, of course.
Quote:Original post by haegarr
Welcome, icuurd12b42. I'm not a D3D expert. And I'm also not sure whether the following thoughts are correct, but I assume so... of course I do :)

Wrapping the (u,v) co-ordinates around isn't the only thing to do. A wrapping is done by a simple formula like
a' := a - floor( a ) for u,v

However, assume a triangle that uses an u=0.9 at one vertex and a u=1.1 at another one. With a wrapping interpolation, the texels read will be at positions 0.9 to 1.0, and from 0.0 to 0.1. Now, by wrapping the co-ordinates one-by-one (i.e. w/o looking at all 3 vertices at once), you get u'=0.9 and u'=0.1, so that an interpolation is going from 0.9 down to 0.1, what is obviously something very different.

This is where I'm at. so some uv coords are at the right position where others go down to .1 instead up to 1.0. So We are on the same page here. Good.

So how does the wraping work... Looking at the number you provided, I don't see the logic of the prodeure to apply in code. So I will need to look at the 3 facets data uv points and apply some sort of algorithm. to turn .9 and 1.1 to .9 and 1... (confused)

Quote:
Hence, for general textures, you need to do more than just to wrap co-ordinates. It must be possible to interpolate by exceeding the texture's border, since reversing the interpolation direction is normally not allowed (it may be allowed if the texture is symmetric, but that is not the general case, isn't it?). Assuming that no single triangle covers the entire texture, it should work to generate a new texture that is 2 times(*) as big as the original one in both dimensions. Then the original texture can be replicated 2x2 times into the new texture. By this way a triangle exceeding a border in the original texture can be mapped overlapping the middle axes of the new texture.

Then the vertices of each triangle are to be shifted so that their u,v's are all in [0,2). The resulting co-ordinates are to be scaled by 0.5, of course, to yield in the correct relative texture co-ordinates matching the new texture.

(*) if no texture resolution should be lost, else you can choose a smaller texture, of course.


Still trying to understand this part. I would accept a solution that would forgo the repeats and simply map the entire facet to the uv specified. It's the wraping that eludes me.
Well, the said formula
a' := a - floor( a )
actually _does_ the mapping of any fractional number into the range [0,1]. One can think of the original number being shifted along the real number axis by a distance of 1 so often until it reaches [0,1].

But if you do above shiting for each u or v individually, you may (and will sooner or later) alter the shape of a triangle, namely if one part is on this side and another part on the other side of a texture border. To avoid this, you have to ensure that the triangle can be covered by the texture without changing the inter-relationship of the u,v co-ordinates. So, instead of artificially repeating the texture by wrapping the texture co-ordinates around, you can really repeat the texture and hence being able to avoid co-ordinate wrapping even in cases where the the overlapping would otherwise enforce wrapping. Its a bit like "unrolling" the wrapped texture.
Quote:Original post by haegarr
Well, the said formula
a' := a - floor( a )
actually _does_ the mapping of any fractional number into the range [0,1]. One can think of the original number being shifted along the real number axis by a distance of 1 so often until it reaches [0,1].

Thats excactly what I was doing when I made the post.

Quote:
But if you do above shiting for each u or v individually, you may (and will sooner or later) alter the shape of a triangle, namely if one part is on this side and another part on the other side of a texture border.

That's exaclty the problem I have.

Quote:
To avoid this, you have to ensure that the triangle can be covered by the texture without changing the inter-relationship of the u,v co-ordinates. So, instead of artificially repeating the texture by wrapping the texture co-ordinates around, you can really repeat the texture and hence being able to avoid co-ordinate wrapping even in cases where the the overlapping would otherwise enforce wrapping. Its a bit like "unrolling" the wrapped texture.

That I cannot do because the engine only takes 0 to 1 values for its texture mapping references... I would need to create another texture, with n repeats, save it to file, then divide the uv's by n (num h tiles, num v tiles) so the uvs remmain in the 0 to 1 range. But the resulting texture would then become original size*n and I would quickly run out of video memory (unless I also resize the texture). The engine fails at loading textures larger than 1024x1024.

To top it off, I already have to merge multiple textures into one image as the model file for that engine only supports 1 texture per model. So for a multiple texture house model, I have to merge the door texture, the window texture, the roof... and so on into a single image smaller than 1024x1024 and adjust the uvs accordingly.

So I need to manually set the uvs. I'm afraid I have no choice in the matter.
Quote:Original post by icuurd12b42
That I cannot do because the engine only takes 0 to 1 values for its texture mapping references... I would need to create another texture, with n repeats, save it to file, then divide the uv's by n (num h tiles, num v tiles) so the uvs remmain in the 0 to 1 range. But the resulting texture would then become original size*n and I would quickly run out of video memory (unless I also resize the texture). The engine fails at loading textures larger than 1024x1024.

Please read my replies thoughtfully again:

First, you have to scale the (u,v) by 0.5 because the range [0,2] is a _virtual_ range of the artificial texture. The downscaling will reduce the (u,v) range to [0,1], of course, and will hence be valid for a relative texel addressing without wrapping.

Second, it is very unlikely that you need n>2 repeats in the artifical texture.

Third, the footnote in my first reply has already mentioned that you need bigger textures only if you want to preserve the texture resolution. Downsampling the texture by 2 when duplicating the original will yield in the same memory consumption as before, but on the cost of resolution, of course.

Quote:Original post by icuurd12b42
So I need to manually set the uvs. I'm afraid I have no choice in the matter.

If the problem is as analysed above (and you've affirmed it is) then there is absolutely no chance to simply re-calculate the (u,v)s, neither automatically nor manually. As long as the texture isn't mirrored/repeated by itself there is IMHO no other way than to enfore the repetition in the texture artificially. If you say that a manual correction will work, then there is a texture property not mentioned here. Perhaps you can provide us with a link to a picture of the texture?
This is the image of the facets that map <almost> right
screenshot100bmp.png

This is the one with some uv point on the wrong side

screenshot101bmp.png

Sorry the board does not take the code. Just copy and paste in your address bar.

[Edited by - icuurd12b42 on October 12, 2008 11:37:00 PM]
Interestingly, the mappings shown in the both screenshots above should not need any wrapping at all. I mean, the shown example is expected to have only (u,v)'s in the range [0,1], but the results suggest that they are slightly out of the valid range. Can you provide us the vertex positions with their belonging texture co-ordinates in a human readable form, especially of the shown side of the crate?

Quote:Original post by icuurd12b42
Sorry the board does not take the code. Just copy and paste in your address bar.

Using standard HTML tags <a href="...">bla</a> and <img src="..."/> should work (at least the anchor tag did it for me several times already; I still haven't used the image tag).
Quote:Original post by haegarr
Interestingly, the mappings shown in the both screenshots above should not need any wrapping at all. I mean, the shown example is expected to have only (u,v)'s in the range [0,1], but the results suggest that they are slightly out of the valid range. Can you provide us the vertex positions with their belonging texture co-ordinates in a human readable form, especially of the shown side of the crate?

That's the result of
u = 1-(u-(int)fabs(u)); or is it
u = (u-(int)fabs(u)); I'm playing with both until I figure the right method

I'll see if I can modify the code to display the points as well (later)... It's hard to manually extract them visually from the file wich is this one.

Download Crate_1.zip
Quote:Original post by icuurd12b42
That's the result of
u = 1-(u-(int)fabs(u)); or is it
u = (u-(int)fabs(u)); I'm playing with both until I figure the right method

Both formulas fail immediately if a negative argument is used. E.g.
u1'(-0.8) = 1-(-0.8-0) = 1.8
u2'(-0.8) = -0.8-0 = -0.8
and things gets more worse if the argument has a greater absolute value.

I still suggest to use
u = u - floor(u)
That formula also suffers from all integer numbers being mapped to 0 (as your formulas do, too), but that is a principal problem: [0,1]->[0,1] and [1,2]->[0,1] cannot be solved simultaneously. Instead the formula solves [0,1)->[0,1) and [1,2)->[0,1). But see below.

Now coming to the "real world" example of the crate, we have the following texture coordinates for the first quad:
1.122074;-0.880759;,
1.122074;-1.005673;,
0.992163;-1.005674;,
0.992164;-0.880759;,
What can be seen here is that the values are far from being perfect. In a perfect situation a side of the crate is textured without any wrapping: The 0.992163 would be 1, and the -1.005673 would be -1. But they are not, causing both the horizontal border (due to 0.992163 < 1 < 1.122074) as well as the vertical border (due to -1.005674 < -1 < -0.880759) being crossed.

2 possible solutions come ATM to my mind:

(1) You write the correction algorithm with the previous knowledge that the mappings should not cross borders. You can say this because of the same given texture is mapped w/o repetition onto each side of the crate. Of course, using this previous knowledge restricts this solution to belonging use cases.

You can use the same previous knowledge an do the correction manually, but that is a question of patience and, more importantly, how many mapping has to be corrected in process of time.

(2) Well :) You go the way of building an artificial texture as mentioned. That frees the algorithm from working for the above special use case only, and furthur eliminates the problem of the right-sided open range limit.

If you want to get most bang for the bucks, you can investigate the (u,v)s and determine how much of the texture is to be repeated. So one full repetition in both dimensions is the expected maximum you get. For some models you may already be lucky with n=1.1...1.2 or so.

This topic is closed to new replies.

Advertisement