8
votes

I have OpenGL program that I want to texture sphere with bitmap of earth. I prepared mesh in Blender and exported it to OBJ file. Program loads appropriate mesh data (vertices, uv and normals) and bitmap properly- I have checked it texturing cube with bone bitmap.

My program is texturing sphere, but incorrectly (or in the way I don't expect). Each triangle of this sphere includes deformed copy of this bitmap. I've checked bitmap and uv seems to be ok. I've tried many sizes of bitmap (powers of 2, multiples of 2 etc).

Here's the texture:

Earth texture

Screenshot of my program (like It would ignore my UV coords):

enter image description here

Mappings of UVs in Blender I've done in this way:

enter image description here

Code setting texture after loading it (apart from code adding texture to VBO- I think it's ok):

  GLuint texID;
  glGenTextures(1,&texID);
  glBindTexture(GL_TEXTURE_2D,texID);
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_BGR,GL_UNSIGNED_BYTE,(GLvoid*)&data[0]);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

Is there needed any extra code to map this texture properly?

[Edit] Initializing textures (earlier presented code is in LoadTextureBMP_custom() function)

bool Program::InitTextures(string texturePath)
{
  textureID = LoadTextureBMP_custom(texturePath);
  GLuint TBO_ID;
  glGenBuffers(1,&TBO_ID);
  glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
  glBufferData(GL_ARRAY_BUFFER,uv.size()*sizeof(vec2),&uv[0],GL_STATIC_DRAW);
  return true;
}

My main loop:

bool Program::MainLoop()
{
  bool done = false;
  mat4 projectionMatrix;
  mat4 viewMatrix;
  mat4 modelMatrix;
  mat4 MVP;

  Camera camera;
  shader.SetShader(true);

  while(!done)
  {
    if( (glfwGetKey(GLFW_KEY_ESC)))
      done = true;
    if(!glfwGetWindowParam(GLFW_OPENED))
      done = true;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Tutaj przeksztalcenia macierzy
    camera.UpdateCamera();
    modelMatrix = mat4(1.0f);
    viewMatrix = camera.GetViewMatrix();
    projectionMatrix = camera.GetProjectionMatrix();
    MVP = projectionMatrix*viewMatrix*modelMatrix;
    // Koniec przeksztalcen

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,textureID);

    shader.SetShaderParameters(MVP);

    SetOpenGLScene(width,height);

    glEnableVertexAttribArray(0); // Udostepnienie zmiennej Vertex Shadera => vertexPosition_modelspace
    glBindBuffer(GL_ARRAY_BUFFER,VBO_ID);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
    glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,(void*)0);

    glDrawArrays(GL_TRIANGLES,0,vert.size());

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    glfwSwapBuffers();
  }
  shader.SetShader(false);

  return true;
}

VS:

#version 330

layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexUV;
out vec2 UV;

uniform mat4 MVP;

void main()
{
  vec4 v = vec4(vertexPosition,1.0f);
  gl_Position = MVP*v;
  UV = vertexUV;
}

FS:

#version 330

in vec2 UV;
out vec4 color;

uniform sampler2D texSampler; // Uchwyt tekstury

void main()
{
  color = texture(texSampler, UV);
}
2
That seems like a UV mapping problem. Are you sure the UV coordinates are correct in your model? That is to say, does it look OK in Blender?manabreak
what is the range of your UV values?Alnitak
p.s. that texture is not suitable for mapping on a sphere. You need one that has been stretched into a cylindrical map, like this one - paulbourke.net/geometry/transformationprojection/earth.jpgAlnitak
@Alnitak: Actually the topology of OP's texture is better suited for a sphere than a mercator map. This has to do with the topological properties of a sphere, which can be mapped into 2 dimensional bounded manifolds only if at least two separate manifolds are used. Trying to strech a single bounded 2-manifold into a sphere will leave singularities, also knowns as poles.datenwolf
@datenwolf true if you have infinite resolution; the OP's texture loses resolution at the edges of the earth rather rapidly though. The best way I've seen to texture a sphere is to construct the sphere from a regular polyhedron that is textured per-side then the sides are deformed to form the sphere.Ron Warholic

2 Answers

1
votes

I haven't done any professional GL programming, but I've been working with 3D software quite a lot.

  • your UVs are most likely bad
  • your texture is a bad fit to project on a sphere
  • considering UVs are bad, you might want to check your normals as well
  • consider an ISOSPHERE instead of a regular one to make more efficient use of polygons

You are currently using a flat texture with flat mapping, which may give you very ugly results, since you will have very low resolution in the "outer" perimeter and most likely a nasty seam artifact where the two projections meet if you like... rotate the planet or something.

Note that you don't have to have any particular UV map, it just needs to be correct with the geometry, which it doesn't look like it is right now. The spherical mapping will take care for the rest. You could probably get away with a cylindrical map as well, since most Earth textures are in a suitable projection.

1
votes

Finally, I've got the answer. Error was there:

bool Program::InitTextures(string texturePath)
{
  textureID = LoadTextureBMP_custom(texturePath);
  // GLuint TBO_ID; _ERROR_
  glGenBuffers(1,&TBO_ID);
  glBindBuffer(GL_ARRAY_BUFFER,TBO_ID);
  glBufferData(GL_ARRAY_BUFFER,uv.size()*sizeof(vec2),&uv[0],GL_STATIC_DRAW);
}

There is the part of Program class declaration:

class Program
{
 private:
  Shader shader;
  GLuint textureID;

  GLuint VAO_ID;
  GLuint VBO_ID;
  GLuint TBO_ID; // Member covered with local variable declaration in InitTextures()
  ...
}

I've erroneously declared local TBO_ID that covered TBO_ID in class scope. UVs were generated with crummy precision and seams are horrible, but they weren't problem.

enter image description here

I have to admit that information I've supplied is too small to enable help. I should have put all the code of Program class. Thanks everybody who tried to.