Problems with texturing an icosphere

Hello,



I’m trying to texture an icosphere with a tileable grass texture. I tried a couple of things I found on the internet, but none of those seemed to work. I tried to calculate the uv coordinates by converting the cartesian to barycentric with this alogrithm: http://adrianboeing.blogspot.de/2010/01/barycentric-coordinates.html. This is what happened:







The next thing I tried was a spherical mapping. I though of scaling the textures afterwards, but it didn’t work anyway. I tried those two algorithms:



[java]

//1

uv.setX((float) (0.5 - (FastMath.atan2(z, x) / (FastMath.PI * 2))));

uv.setY((float) (0.5 - (2 * (FastMath.asin(y) / (FastMath.PI * 2)))));

//2

uv.setX(x / FastMath.sqrt((x * x) + (y * y) + (z * z)));

uv.setY(y / FastMath.sqrt((x * x) + (y * y) + (z * z)));

[/java]



This is what happend this time (with the first algorithm, kinda smiliar outcome with the second one):







The last thing I tried was to just feed the uv coordinate buffer with the row (0|0), ( 1|0), (0|1). This is actually also what I tried first and I still wonder why it’s not working. What happened this time looks sort of similiar to the first attempt in this post.







Some triangles look perfectly mapped, some seem to be streched over one axis?!



Right now I’m pretty lost, I’ve been trying this for 2 days now, thought and read a lot about the concepts of the buffers and uv coordinates but I just can’t figure this out without any help. Every kind of help is appreciated :slight_smile:

There’s a “sphere mapped” plugin in the SDK that I wrote when you apply a texture to a sphere (obviously) the problem with that plugin is that it will create a seam.



I do intend to fix this eventually but since I’ve moved on to procedural texturing this is a very low priority for me. If you feel like it, and that’s what you want/need, you can always fix the seaming.

1 Like

To the OP, I could be totally off base since I don’t know how your actual mesh is built, but I think the problem is that the tiling exactly matches the distance of the points. (Which is logical) but that means that you end up sometimes with 1 → 1 style texcoord spans between vertexes.



Are you using only texture coordinates between 0 and 1? If so, that’s probably a mistake. You should either not share vertexes between adjacent faces or should use real texture coordinates that can go above 1.



As an illustration, if you imagine a regularly spaced grid where you want tiles that map directly to the grid, then you end up (potentially) with texture coordinates that look like:

0,0 0,0 0,0 0,0

or

0,0 1,0 1,0 1,0

depending on how you clamp the texture coordinates. …which won’t work right.



It really needs to be:

0,0 1,0 2,0 3,0 etc.



Again, just a total guess. But the spans that are just stretched lines are definitely spans with the same texture coordinates at each end of an edge… for whatever reason.

1 Like

Why not do it like this:

http://i.imgur.com/mCO1S.png

If you have tilable texture, you actually only need 3 texture coordinates. So lets say that:

A = {0, 0}

B = {0, 1}

C = {1, 0}

D = {1, 1}

I think that as long as you don’t have the same texture coordinate on neighbour vertex, you are ok.



PS: Sorry for my crappy art. :smiley:

2 Likes

If you don’t mind your textures getting mirrored ever other triangle then that is also a valid approach… and probably the easiest to implement overall.

That is exactly why I posted this, because it is the easiest one. Well you can maybe put also D coordinate now and then. :slight_smile:

Alright, thank you very much so far. I’d like to try what inShadow wrote. My vertex buffer isn’t ordered in any way though. Thus my first approach would be to begin with some arbitrary vertex and find the adjacent points. I made some algorithm to do that using the indexes:

[java]

private boolean isAdjacentPoint(int indexP1, int indexP2, int[] indexes)

{

boolean foundP1 = false;



for (int i = 0; i < indexes.length; i+:3)

{

if (indexP1 == indexes) foundP1 = true;

else if (indexP1 == indexes[i+1]) foundP1 = true;

else if (indexP1 == indexes[i+2]) foundP1 = true;



if (foundP1 == true)

{

if (indexP2 == indexes) return true;

if (indexP2 == indexes[i+1]) return true;

if (indexP2 == indexes[i+2]) return true;

foundP1 = false; //Reset the variable for next loop when the second index was not found.

}

}

return false;

}

[/java]



With this I could make a data structure where every object is a vertex position and holds a list with its neighbours. Then I could easily apply the texture coordinates. But the list with neighbours won’t be ordered. How would you do that? Or do you rather think this approach is crappy anyway?



greetings

How do you generate the vertices? Presumably they know what their neighbours are then?



If you generate them in the right sequence (top left to bottom right in the example above) - with a bit of logic to make sure you go to the right place when starting a new “line” then you just need to put the texture co-ords as abcabcabcabc etc.

I use an algorithm that approximates a sphere from an octahedron by splitting up every triangle in to four new triangles and normalising the 3 new vertex positions. Thus the positions are pretty messed up inside of the vertex buffer.

At the last few levels of splits it should be possible to mark the vertexes and then assign proper texture coordinates at the last split based on InShadow’s diagram. In theory.

1 Like

Thanks so much, I made it. Basically I did what pspeed wrote, but from the beginning of the sphere calculation. A new position is always added halfway between two points. Now I just check what uv coordinates the both points have and give the new position the remaining one. The algorithm seems to be a little odd, could probably get improved.



[java]

private Vector2f getRemainingTexCoord(int index1, int index2)

{

Vector2f a = new Vector2f(0, 0);

Vector2f b = new Vector2f(1, 0);

Vector2f c = new Vector2f(0, 1);



boolean foundA = false;

boolean foundB = false;

boolean foundC = false;



if (texCoords[index1].equals(a)) foundA = true;

else if (texCoords[index1].equals(b)) foundB = true;

else if (texCoords[index1].equals©) foundC = true;



if (texCoords[index2].equals(a)) foundA = true;

else if (texCoords[index2].equals(b)) foundB = true;

else if (texCoords[index2].equals©) foundC = true;



if (foundA && foundB) return c;

if (foundA && foundC) return b;

if (foundB && foundC) return a;



return null;

}

[/java]



Now it looks this way:





Still not perfect because of the mirroring but much better then the first tries!

Yes there will be some mirroring for sure. Maybe you can now and then also put D coordinate, so that you don’t use only half a texture. :slight_smile:

I am trying to approximate a sphere from icosahedron (haven’t implemented triangulation part yet) and it looks like this (I also include some D coordinates in). :wink:

http://i.imgur.com/h5pOj.png

@InShadow said: Yes there will be some mirroring for sure. Maybe you can now and then also put D coordinate, so that you don't use only half a texture. :)<br /> I am trying to approximate a sphere from icosahedron (haven't implemented triangulation part yet) and it looks like this (I also include some D coordinates in). ;)<br /> http://i.imgur.com/h5pOj.png</img>

just out of curiosity, how did you get that icosahedron to render as flat shaded?
i had to use separate vertices for each face to keep the normals from averaging to a smooth look.
consequently, it allows for texture mapping each triangle separately, so thats cool.

Yes, this is exactly what I have done. Each face its own vertices with their own normals, without special shader. :slight_smile:

Just so everyone knows, this approach does not work. An icosphere cannot be textured this way. The images posted by iShadow might work for the visible portion, but there is stretching on the non-visible sides.