PDA

View Full Version : Trouble texture mapping an image on sphere.



krunal
10-31-2017, 12:09 AM
Hey guys, I'm trying to texture map an image onto a sphere in OpenGL 3.3. But instead of showing the image it's showing something like this:
2534
I'm trying to map the face of buzz light year which is a 512x512 bmp image, and I don't know why it isn't texture mapping like it should on the sphere. It's coming out fine on a cube or any flat surface, but I'm having trouble mapping it to a sphere. Here's the code I'm using.


double Radius = 0.5;
int Lat = 10;
int Long = 10;

glm::vec2 t_coords[4] = {
glm::vec2( 0.0, 0.0),
glm::vec2( 0.0, 1.0),
glm::vec2( 1.0, 0.0),
glm::vec2( 1.0, 1.0)
};
void sphere(double radius, int Lats, int Longs)
{
float lats,longs;

float slices=(180/(float(Lats)*10))/2;
float sectors=(180/(float(Longs)*10))/2;

float l;int i=0;

for (lats = 0.0; lats <= PI; lats+=sectors)
{
for(longs = 0.0; longs <= 2.0*PI; longs+=slices)
{
float x = radius * sin(lats) * cos(longs);
float y = radius * sin(lats) * sin(longs);
float z = radius * cos(lats);
glm::vec4 pt(x, y, z, 1.0);
if(i>3) i=0;
v_colors[tri_idx] = white; v_positions[tri_idx] = pt; tex_coords[tri_idx] = t_coords[i];
v_normals[tri_idx] = pt; tri_idx++; i++;

w_colors[wire_idx] = black; w_positions[wire_idx] = pt;
w_normals[wire_idx] = pt; wire_idx++;


if(lats+sectors>PI)
l=PI;
else
l=lats+sectors;
x = radius * sin(l) * cos(longs);
y = radius * sin(l) * sin(longs);
z = radius * cos(l);
pt =glm::vec4(x, y, z, 1.0);
if(i>3) i=0;
v_colors[tri_idx] = white; v_positions[tri_idx] = pt; tex_coords[tri_idx] = t_coords[i];
v_normals[tri_idx] = pt; tri_idx++; i++;

w_colors[wire_idx] = black; w_positions[wire_idx] = pt;
w_normals[wire_idx] = pt; wire_idx++;

}
}
// To Complete the wireframe
for (lats = 0.0; lats <= PI; lats+=sectors)
{
for(longs = 0.0; longs <= 2.0*PI; longs+=slices)
{
float x = radius * sin(lats) * cos(longs);
float y = radius * sin(lats) * sin(longs);
float z = radius * cos(lats);
glm::vec4 pt(x, y, z, 1.0);

w_colors[wire_idx] = black; w_positions[wire_idx] = pt;
w_normals[wire_idx] = pt; wire_idx++;

}
}
}
void initBuffersGL(void)
{

// Load shaders and use the resulting shader program
std::string vertex_shader_file("vshader.glsl");
std::string fragment_shader_file("fshader.glsl");

std::vector<GLuint> shaderList;
shaderList.push_back(csX75::LoadShaderGL(GL_VERTEX _SHADER, vertex_shader_file));
shaderList.push_back(csX75::LoadShaderGL(GL_FRAGME NT_SHADER, fragment_shader_file));

shaderProgram = csX75::CreateProgramGL(shaderList);
glUseProgram( shaderProgram );

// getting the attributes from the shader program
GLuint vPosition = glGetAttribLocation( shaderProgram, "vPosition" );
GLuint vColor = glGetAttribLocation( shaderProgram, "vColor" );
GLuint vNormal = glGetAttribLocation( shaderProgram, "vNormal" );
GLuint texCoord = glGetAttribLocation( shaderProgram, "texCoord" );
uModelViewMatrix = glGetUniformLocation( shaderProgram, "uModelViewMatrix");
normalMatrix = glGetUniformLocation( shaderProgram, "normalMatrix");
viewMatrix = glGetUniformLocation( shaderProgram, "viewMatrix");

// Load Textures
GLuint tex=LoadTexture("images/buzz_face.bmp",512,512);
glBindTexture(GL_TEXTURE_2D, tex);

//Ask GL for two Vertex Attribute Objects (vao) , one for the colorcube and one for the plane.
glGenVertexArrays (2, vao);
//Ask GL for two Vertex Buffer Object (vbo)
glGenBuffers (2, vbo);

//Set 0 as the current array to be used by binding it
glBindVertexArray (vao[0]);
//Set 0 as the current buffer to be used by binding it
glBindBuffer (GL_ARRAY_BUFFER, vbo[0]);

// Call the sphere function
Lat = tesselation;
Long = tesselation;
sphere(Radius, Lat, Long);

//Copy the points into the current buffer
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions) + sizeof(v_colors) + sizeof(v_normals), NULL, GL_STATIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(v_positions), v_positions );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(v_positions), sizeof(v_colors), v_colors );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(v_colors)+sizeof(v_positions), sizeof(v_normals), v_normals );
// set up vertex array

glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );

//Textures
glEnableVertexAttribArray( texCoord );
glVertexAttribPointer( texCoord, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions)) );

// glEnableVertexAttribArray( vColor );
// glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions)) );

// glEnableVertexAttribArray( vNormal );
// glVertexAttribPointer( vNormal, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions) + sizeof(v_colors)) );

//Normal
glEnableVertexAttribArray( vNormal );
glVertexAttribPointer( vNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions)+sizeof(tex_coord s)) );

// For The Wireframe too ... --------

//Set 1 as the current array to be used by binding it
glBindVertexArray (vao[1]);
//Set 1 as the current buffer to be used by binding it
glBindBuffer (GL_ARRAY_BUFFER, vbo[1]);

//Copy the points into the current buffer
glBufferData (GL_ARRAY_BUFFER, sizeof (w_positions) + sizeof(w_colors) + sizeof(w_normals), NULL, GL_STATIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(w_positions), w_positions );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(w_positions), sizeof(w_colors), w_colors );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(w_colors)+sizeof(w_positions), sizeof(w_normals), w_normals );

// set up vertex array

glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );

glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(w_positions)) );

glEnableVertexAttribArray( vNormal );
glVertexAttribPointer( vNormal, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(w_positions) + sizeof(w_colors)) );


}

GLuint LoadTexture( const char * filename, int width, int height )
{
GLuint texture;
unsigned char header[54];// 54 Byte header of BMP
int pos;
unsigned int w,h;
unsigned int size; //w*h*3
unsigned char * data; // Data in RGB FORMAT
FILE * file;

file = fopen( filename, "rb" );
if ( file == NULL ) return 0; // if file is empty
if (fread(header,1,54,file)!=54)
{
printf("Incorrect BMP file\n");
return 0;
}

// Read MetaData
pos = *(int*)&(header[0x0A]);
size = *(int*)&(header[0x22]);
w = *(int*)&(header[0x12]);
h = *(int*)&(header[0x16]);

//Just in case metadata is missing
if(size == 0)
size = w*h*3;
if(pos == 0)
pos = 54;

data = new unsigned char [size];

fread( data, size, 1, file ); // read the file
fclose( file );
//////////////////////////

glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );


glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);

free( data );
return texture;// return the texture id
}

GClements
10-31-2017, 06:03 AM
Your texture coordinates are bogus. I don't know exactly how you intend to map the image to the sphere, but the texture coordinates should probably be based upon lat/lon.

Also: note that some amount of distortion is unavoidable with the fixed-function pipeline. You'll end up with a grid of trapezoids, each of which will be split into two triangles. One of those triangles will be larger than the other, but both will map to the same area of the texture, resulting in a crease along the diagonal. You can avoid this issue by using a bilinear mapping, but that requires shaders; fixed-function texturing is limited to affine or projective mapping.