Texturing a sphere

Started by msacco, June 18, 2018, 14:30:14

Previous topic - Next topic

msacco

I'd like to get some help with texturing a 3d sphere, Im using the following code to draw a sphere:

public static void testing() {
		final float PI = 3.141592f;
		float x, y, z, alpha, beta; // Storage for coordinates and angles
		float radius = 60f;
		int gradation = 20;
		for (alpha = 0.0f; alpha < PI; alpha += PI / gradation) {
			glBegin(GL_TRIANGLE_STRIP);
			for (beta = 0.0f; beta < 2.01 * PI; beta += PI / gradation) {
				x = (float) (radius * Math.cos(beta) * Math.sin(alpha));
				y = (float) (radius * Math.sin(beta) * Math.sin(alpha));
				z = (float) (radius * Math.cos(alpha));
				glVertex3f(x, y, z);
				x = (float) (radius * Math.cos(beta) * Math.sin(alpha + PI / gradation));
				y = (float) (radius * Math.sin(beta) * Math.sin(alpha + PI / gradation));
				z = (float) (radius * Math.cos(alpha + PI / gradation));
				glVertex3f(x, y, z);
			}
			glEnd();
		}
	}


The 3d sphere works just as it should, but I just don't really understand how to draw the texture on to it, I used slick utils to load the texture etc, and I manage to texture the sphere, but not really the way I need it to, how do I match/map the texture to the model? do I need to use glTexCoord2f go each glVertex3f? how does that work exactly? And how does the glVertex3f really works? Thanks.

msacco


mudlee

I would recommend you three resources:


When I learnt opengl, I used these resources mainly and the opengl red book: https://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0134495497/ref=sr_1_1?s=books&ie=UTF8&qid=1529415776&sr=1-1&keywords=opengl+programming+guide

msacco

Quote from: mudlee on June 19, 2018, 13:42:59
I would recommend you three resources:


When I learnt opengl, I used these resources mainly and the opengl red book: https://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0134495497/ref=sr_1_1?s=books&ie=UTF8&qid=1529415776&sr=1-1&keywords=opengl+programming+guide

I already tried those, but Im trying to texture a 3d sphere, which is like a lot of small triangles and Im trying to texture it with an earth or sun texture for example, but I don't know how to wrap it, because its not like a square where you just have to put the corner vertices..so I have no idea what to do :\

mudlee

I see, sorry. I would recommend to ask this on http://www.java-gaming.org/ as well.

msacco

Quote from: mudlee on June 19, 2018, 17:46:04
I see, sorry. I would recommend to ask this on http://www.java-gaming.org/ as well.

I will, thank you :)

KaiHH

First, you need a suitable projection of a spherical surface onto a 2D surface. Most people and also most textures you find use equirectangular projection. So there is that.

Next you need to know that texture coordinates in OpenGL are in the range ([0..1], [0..1]). So you need to map the texture coordinates in the range from zero to one in both dimensions u and v (also called 's' and 't') onto the sphere.

Equirectangular projection is suitable for you since it can simply use longitude/latitude angles, just like you are currently using to generate the 3D vertex positions in cartesian space.

So, try the following directly before the first glVertex3f call:
glTexCoord2f(beta / (2.0f * PI), alpha / PI);


And the following directly before the second glVertex3f call:
glTexCoord2f(beta / (2.0f * PI) + 0.5f / gradation, alpha / PI + 1.0f / gradation);

msacco

Quote from: KaiHH on June 19, 2018, 18:53:47
First, you need a suitable projection of a spherical surface onto a 2D surface. Most people and also most textures you find use equirectangular projection. So there is that.

Next you need to know that texture coordinates in OpenGL are in the range ([0..1], [0..1]). So you need to map the texture coordinates in the range from zero to one in both dimensions u and v (also called 's' and 't') onto the sphere.

Equirectangular projection is suitable for you since it can simply use longitude/latitude angles, just like you are currently using to generate the 3D vertex positions in cartesian space.

So, try the following directly before the first glVertex3f call:
glTexCoord2f(beta / (2.0f * PI), alpha / PI);


And the following directly before the second glVertex3f call:
glTexCoord2f(beta / (2.0f * PI) + 0.5f / gradation, alpha / PI + 1.0f / gradation);


Amazing! Thank you so much! I've been trying to work it out for a few days now with no success. It works perfectly with my sun texture, but there's a small problem with my earth texture, tho Im not sure if its something with the code or the actual earth texture, but I downloaded it from a very reliable source(aka: http://planetpixelemporium.com/earth.html).
Thats how it looks like with the earth texture:
https://imgur.com/s0pn0Oy

I think I managed to fix it by changing both of the lines to 2.07f * PI instead of 2.0f, and it seems to be working now, but I don't think thats how it should work, do you have any ideas why it happens?
One more thing, when looking close at the texture it looks like this:
https://imgur.com/lUpLg9K

Is that the way it supposed to be? or is there a way to make it smoother? It seems that when lowering the graduation the gaps appears to be bigger and bigger, thats with graduation of 20 for example:
https://imgur.com/yZIjYc8

I assume Im doing something wrong in the code, thanks a lot for the help anyway!!


KaiHH

Oh, sorry, by bad. The second call has to be:
glTexCoord2f(beta / (2.0f * PI), alpha / PI + 1.0f / gradation);

msacco

Quote from: KaiHH on June 19, 2018, 20:06:03
Oh, sorry, by bad. The second call has to be:
glTexCoord2f(beta / (2.0f * PI), alpha / PI + 1.0f / gradation);


Yep, it works like a charm! The code still needs to be (2.07f * PI) in both of them for the earth texture to work properly, but I assume its something to do with the texture itself. If you know why it might happen, that would be really nice to know, as making 2 different codes for 2 different textures is ok, but code duplication is never a good thing.

KaiHH

The problem is the inaccuracy of the floating point arithmetic of your loops. Normally, you would not loop over the actual float angles and increment them; but you would loop over your "gradation" as integer and compute the angle from the current step, like so:
float PI = (float) Math.PI;
float x, y, z;
float radius = 60f;
int gradation = 10;
for (int j = 0; j < gradation; j++) {
  float alpha1 = (float) j / gradation * PI;
  float alpha2 = (float) (j + 1) / gradation * PI;
  for (int i = 0; i <= gradation; i++) {
    float beta = (float) i / gradation * 2.0f * PI;
    x = (float) (radius * Math.cos(beta) * Math.sin(alpha1));
    y = (float) (radius * Math.sin(beta) * Math.sin(alpha1));
    z = (float) (radius * Math.cos(alpha1));
    glTexCoord2f(beta / (2.0f * PI), alpha1 / PI);
    glVertex3f(x, y, z);
    x = (float) (radius * Math.cos(beta) * Math.sin(alpha2));
    y = (float) (radius * Math.sin(beta) * Math.sin(alpha2));
    z = (float) (radius * Math.cos(alpha2));
    glTexCoord2f(beta / (2.0f * PI), alpha2 / PI);
    glVertex3f(x, y, z);
  }
}

msacco

Quote from: KaiHH on June 20, 2018, 15:13:58
The problem is the inaccuracy of the floating point arithmetic of your loops. Normally, you would not loop over the actual float angles and increment them; but you would loop over your "gradation" as integer and compute the angle from the current step, like so:
float PI = (float) Math.PI;
float x, y, z;
float radius = 60f;
int gradation = 10;
for (int j = 0; j < gradation; j++) {
  float alpha1 = (float) j / gradation * PI;
  float alpha2 = (float) (j + 1) / gradation * PI;
  for (int i = 0; i <= gradation; i++) {
    float beta = (float) i / gradation * 2.0f * PI;
    x = (float) (radius * Math.cos(beta) * Math.sin(alpha1));
    y = (float) (radius * Math.sin(beta) * Math.sin(alpha1));
    z = (float) (radius * Math.cos(alpha1));
    glTexCoord2f(beta / (2.0f * PI), alpha1 / PI);
    glVertex3f(x, y, z);
    x = (float) (radius * Math.cos(beta) * Math.sin(alpha2));
    y = (float) (radius * Math.sin(beta) * Math.sin(alpha2));
    z = (float) (radius * Math.cos(alpha2));
    glTexCoord2f(beta / (2.0f * PI), alpha2 / PI);
    glVertex3f(x, y, z);
  }
}


Well the code works as well, but when Im using the earth texture I still need to change it(to 2.05f now tho). So I think its pretty clear that its a problem with my texture, as the texture dimensions are 1000x500 and are not a power of 2(I assume, I can't see any other reason for that to happen besides that).

One more unrelated question, are there any good tutorials for opengl 4 for java? Many people told me that using old opengl versions is bad because of the gpu management. Do you know anything about it? I just can't find any tutorial..Thanks.

Edit - I have changed the earth texture to 1024x512, and it works just as it should now, so yeah, it was because of the texture and power of 2.

KaiHH

Quote from: msacco on June 20, 2018, 15:43:27
are there any good tutorials for opengl 4 for java?
You can have a look at https://www.amazon.com/Computer-Graphics-Programming-OpenGL-Java/dp/1683920279
It uses the most modern OpenGL version at the time it was written, is specifically for Java and uses JOGL as the Java/OpenGL binding. But you can very easily adapt to LWJGL it you like it better.
The second edition of this book is due to August this year, also featuring the "quasi de-facto" Java vector/matrix standard library JOML, so that you do not have to use the legacy OpenGL matrix stack anymore.

msacco

Quote from: KaiHH on June 20, 2018, 17:12:40
Quote from: msacco on June 20, 2018, 15:43:27
are there any good tutorials for opengl 4 for java?
You can have a look at https://www.amazon.com/Computer-Graphics-Programming-OpenGL-Java/dp/1683920279
It uses the most modern OpenGL version at the time it was written, is specifically for Java and uses JOGL as the Java/OpenGL binding. But you can very easily adapt to LWJGL it you like it better.
The second edition of this book is due to August this year, also featuring the "quasi de-facto" Java vector/matrix library JOML, so that you do not have to use the legacy OpenGL matrix stack anymore.

Im already using the jogl vectors etc, its really nice and good. The book looks really good, I'll surely check it out. Just out of curiosity, and only if you really want to, because you really don't have to at all, can you show me a version of the draw sphere code using opengl 4? Cause I don't quite understand the basics, as far as people told me, you shouldn't use any opengl 1-2 methods in opengl 4. Again, only if you feel like it, its kinda something big to ask for. Thanks.

KaiHH

No problem. Here is a demo using the somewhat latest reasonable version of OpenGL to render a rotating, textured sphere:
  https://github.com/LWJGL/lwjgl3-demos/commit/4304297afc6275f791d8b3e2850b740b6cfcdb4f
See the Java and shader files in that commit. It uses OpenGL 3.2 Core Profile functions. There hasn't been much improvement in later OpenGL versions for such simple things as rendering a textured sphere. It's still always:
- create a vertex and (optionally) index/element buffer
- create a shader program
- setup vertex specification with these buffers and the vertex attributes imported by the shader program
- enable/bind shader
- call draw functions