3

Could some one explain for me how can I render multiple objects with different textures in OpenGL?

I think that I'm nearly to the final result but at the moment I got stuck here and I don't know what I need to do next. Really need some helps!

At the moment this is what I have:

  1. drawSphere(): draw an UV sphere based on number of longs and lats

    int numberOfVerices = 0;

    for(int i = 0; i <= lats; i++) { double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats); double z0 = sin(lat0); double zr0 = cos(lat0); double lat1 = M_PI * (-0.5 + (double) i / lats); double z1 = sin(lat1); double zr1 = cos(lat1); for(int j = 0; j <= longs; j++) { double lng = 2 * M_PI * (double) (j - 1) / longs; double x = cos(lng); double y = sin(lng); glNormal3f(x * zr0, y * zr0, z0); vertices.push_back(x * zr0); vertices.push_back(y * zr0); vertices.push_back(z0); indices.push_back(numberOfVerices); numberOfVerices++; vertices.push_back(x * zr1); vertices.push_back(y * zr1); vertices.push_back(z1); indices.push_back(numberOfVerices); numberOfVerices++; } indices.push_back(GL_PRIMITIVE_RESTART_FIXED_INDEX); } 
  2. SetupGeometry(): this method is used to bind vertices and texture coordinates.

drawSphere(300, 300);

glGenBuffers(1, &vboVertex); glBindBuffer(GL_ARRAY_BUFFER, vboVertex); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray(0); glGenBuffers(1, &vboTexture); glBindBuffer(GL_ARRAY_BUFFER, vboTexture); glBufferData(GL_ARRAY_BUFFER, texture.size() * sizeof(GLfloat), &texture[0], GL_STATIC_DRAW); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); glGenBuffers(1, &vboIndex); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndex); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW); numsToDraw = indices.size(); nums = indices.size(); 
  1. SetupShader(): create shader and compile shader

char text[1000]; int length;

vertexSource = filetobuf("space/sphere.vert"); fragmentSource = filetobuf("space/sphere.frag"); vertexShader = glCreateShader(GL_VERTEX_SHADER); fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vertexShader, 1, (const GLchar**) &vertexSource, 0); glShaderSource(fragmentShader, 1, (const GLchar**) &fragmentSource, 0); fprintf(stderr, "Compiling vertex shader....\n"); glCompileShader(vertexShader); fprintf(stderr, "Compiling fragment shader....\n"); glCompileShader(fragmentShader); fprintf(stderr, "Done....\n"); shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glBindAttribLocation(shaderProgram, 0, "in_Position"); glBindAttribLocation(shaderProgram, 1, "Texture_Coord"); printf("Linking program ... \n"); glLinkProgram(shaderProgram); glGetProgramInfoLog(shaderProgram, 1000, &length, text); if(length > 0){ fprintf(stderr, "Validate Shader Program\n%s\n", text ); } glUseProgram(shaderProgram); 
  1. SetupTexture(char * filename): loading image, generate 2 arrays of textures, one to GL_TEXTURE0 and other one to GL_TEXTURE1

GLuint texture[2]; glGenTextures(2, texture);

glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture[0]); data = stbi_load(fileName, &w, &h, &n, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glUniform1i(glGetUniformLocation(shaderProgram, "texture_Sun"), 0); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); stbi_image_free(data); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture[1]); data = stbi_load(fileName1, &w, &h, &n, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glUniform1i(glGetUniformLocation(shaderProgram, "texture_Earth"), 1); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); stbi_image_free(data); 
  1. Render(int i): rendering 2 objects, which is sphere.

glClearColor(0.0, 0.0, 0.0, 1.0);/* Make our background black */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_PRIMITIVE_RESTART); glPrimitiveRestartIndex(GL_PRIMITIVE_RESTART_FIXED_INDEX); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndex); glPushMatrix(); glLoadIdentity(); glm::mat4 Projection = glm::perspective(50.0f, 5.0f / 3.0f, 1.0f, 100.0f); glm::mat4 View = glm::lookAt( glm::vec3(0, 5, 2), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0) ); /* Animations */ GLfloat angle = (GLfloat) (i); View = glm::translate(View, glm::vec3(2.0f, 0.0f, 0.0f)); View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f)); /* ******* */ glm::mat4 Model = glm::mat4(1.0f); glm::mat4 MVP = Projection * View * Model; glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP)); glDrawElements(GL_QUAD_STRIP, numsToDraw, GL_UNSIGNED_INT, NULL); glPopMatrix(); glPushMatrix(); glLoadIdentity(); glm::mat4 Projection1 = glm::perspective(50.0f, 5.0f / 3.0f, 1.0f, 100.0f); glm::mat4 View1 = glm::lookAt( glm::vec3(0, 5, 2), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0) ); /* Animations */ GLfloat angle1 = (GLfloat) (i); View1 = glm::translate(View1, glm::vec3(-2.0f, 0.0f, 0.0f)); View1 = glm::rotate(View1, angle1 * -0.5f, glm::vec3(0.0f, 0.0f, 1.0f)); /* ******* */ glm::mat4 Model1 = glm::mat4(1.0f); MVP = Projection1 * View1 * Model1; glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP)); glDrawElements(GL_QUAD_STRIP, nums, GL_UNSIGNED_INT, NULL); glPopMatrix(); 

VertexShader:

#version 330 core precision highp float; attribute vec3 in_Position; attribute vec3 in_Position1; varying vec4 Texture_Coord; uniform mat4 mvpMatrix; void main(void){ gl_Position = mvpMatrix * vec4(in_Position, 1.0); Texture_Coord = vec4(in_Position, 1.0); } 

FragmentShader:

#version 330 core precision highp float; varying vec4 Texture_Coord; uniform sampler2D texture_Sun; uniform sampler2D texture_Earth; out vec4 FragColor; void main(void){ vec2 longLat = vec2((atan(Texture_Coord.y, Texture_Coord.x)/3.1415926 + 1) * 0.5, (asin(Texture_Coord.z) / 3.1415926 + 0.5)); FragColor = texture2D(texture_Sun, longLat); FragColor = texture2D(texture_Earth, longLat); } 

Main codes in main:

SetupGeomtry(); SetupShader(); SetupTexture("images/Earth.jpg", "images/sun.jpg"); /* * Main loop */ int i = 0; while(!glfwWindowShouldClose(window)){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Render(i+=1); glfwSwapBuffers(window); glfwPollEvents(); Sleep(10); } 

1 Answer 1

4

Normally you would load your textures (i.e. buffer them to GPU):

GLuint texture[2]; glGenTextures(2, texture); glBindTexture(GL_TEXTURE_2D, texture[0]); data = stbi_load(fileName, &w, &h, &n, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); stbi_image_free(data); glBindTexture(GL_TEXTURE_2D, texture[1]); data = stbi_load(fileName1, &w, &h, &n, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); stbi_image_free(data); 

then before drawing each of your objects bind the relevant texture for said object:

// already selected the shader programme for both Sun and Earth GLint textureLocation = glGetUniformLocation(shaderProgram, "texture_CelestialBody"); // optionally remember more locations for multi texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture[0]); glUniform1i(textureLocation, 0); // optionally bind more textures for multi texture shader... // draw Sun now glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture[1]); glUniform1i(textureLocation, 0); // optionally bind more textures for multi texture shader... // draw Earth now 

then the texture_CelestialBody identifies the texture for both the Sun and the Earth - i.e. the fragment shader would not discriminate between the two.

Sign up to request clarification or add additional context in comments.

1 Comment

work perfectly! Thank you very much! Last time I tried to put my setuptexture method inside Render(). so everytime I render the sphere, i have to load all textures again. It works, it does work but too slow. This is a great solution!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.