2016-01-02 5 views
0

Je suis nouveau sur OpenGL et j'essaie de dessiner deux carrés avec des textures différentes. J'utilise lwjgl 3 comme interface avec OpenGL, mais je crois que les appels OpenGL devraient sembler familiers aux personnes qui utilisent OpenGL dans d'autres langages. Ma boucle principale ressemble à ceci:Les textures OpenGL apparaissent au mauvais endroit lorsqu'elles sont réunies

while (glfwWindowShouldClose(windowId) == GLFW_FALSE) { 
     glClear(GL_COLOR_BUFFER_BIT); 

     glUseProgram(shaderProgramId); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 

     // DRAW TEXTURE 1 
     specifyVertexAttributes(shaderProgramId); 
     glBindTexture(GL_TEXTURE_2D, texture1.getId()); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo1); 
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

     // DRAW TEXTURE 2 
     specifyVertexAttributes(shaderProgramId); 
     glBindTexture(GL_TEXTURE_2D, texture2.getId()); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo2); 
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

     glfwSwapBuffers(windowId); 

     glfwPollEvents(); 
    } 

Quand je commente le code qui dessine la texture 2, la texture 1 dessine au bon endroit:

texture1

Quand je commente le code qui dessine texture 1, texture 2 tire au bon endroit:

texture2

Mais lorsque je tente de tirer deux du te xtures, ils changent de place:

combined

je réalise l'extrait de code ci-dessus est probablement pas suffisant pour diagnostiquer ce problème. J'ai créé une classe Java autonome qui contient tous les appels OpenGL que je fais pour dessiner ces textures: StandaloneMultiTextureExample. Le repo qui contient ce fichier se construit également avec gradle. Il devrait être très facile pour quiconque est prêt à aider à vérifier le dépôt et exécuter cette classe d'exemple.

Edit: Copie StandaloneMultiTextureExample.java (sans les importations)

public class StandaloneMultiTextureExample { 

    private final GLFWErrorCallback errorCallback = new LoggingErrorCallback(); 
    private final GLFWKeyCallback keyCallback = new ApplicationClosingKeyCallback(); 

    public void run() { 
     if (glfwInit() != GLFW_TRUE) { 
      throw new IllegalStateException("Unable to initialize GLFW"); 
     } 

     glfwSetErrorCallback(errorCallback); 
     int width = 225; 
     int height = 200; 
     long windowId = createWindow(width, height); 
     glfwSetKeyCallback(windowId, keyCallback); 

     glfwShowWindow(windowId); 
     GL.createCapabilities(); 

     Texture texture1 = createTexture("multiTextureExample/texture1.png"); 
     Texture texture2 = createTexture("multiTextureExample/texture2.png"); 

     int shaderProgramId = createShaderProgram(
       "multiTextureExample/textureShader.vert", 
       "multiTextureExample/textureShader.frag"); 

     IntBuffer elements = BufferUtils.createIntBuffer(2 * 3); 
     elements.put(0).put(1).put(2); 
     elements.put(2).put(3).put(0); 
     elements.flip(); 

     int ebo = glGenBuffers(); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements, GL_STATIC_DRAW); 

     float x1 = 0; 
     float y1 = 0; 
     float x2 = x1 + texture1.getWidth(); 
     float y2 = y1 + texture1.getHeight(); 
     float x3 = 25; 
     float x4 = x3 + texture2.getWidth(); 

     FloatBuffer texture1Vertices = BufferUtils.createFloatBuffer(4 * 7); 
     texture1Vertices.put(x1).put(y1).put(1).put(1).put(1).put(0).put(0); 
     texture1Vertices.put(x2).put(y1).put(1).put(1).put(1).put(1).put(0); 
     texture1Vertices.put(x2).put(y2).put(1).put(1).put(1).put(1).put(1); 
     texture1Vertices.put(x1).put(y2).put(1).put(1).put(1).put(0).put(1); 
     texture1Vertices.flip(); 

     FloatBuffer texture2Vertices = BufferUtils.createFloatBuffer(4 * 7); 
     texture2Vertices.put(x3).put(y1).put(1).put(1).put(1).put(0).put(0); 
     texture2Vertices.put(x4).put(y1).put(1).put(1).put(1).put(1).put(0); 
     texture2Vertices.put(x4).put(y2).put(1).put(1).put(1).put(1).put(1); 
     texture2Vertices.put(x3).put(y2).put(1).put(1).put(1).put(0).put(1); 
     texture2Vertices.flip(); 

     int vbo1 = glGenBuffers(); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo1); 
     glBufferData(GL_ARRAY_BUFFER, texture1Vertices, GL_STATIC_DRAW); 

     int vbo2 = glGenBuffers(); 
     glBindBuffer(GL_ARRAY_BUFFER, vbo2); 
     glBufferData(GL_ARRAY_BUFFER, texture2Vertices, GL_STATIC_DRAW); 

     specifyUniformVariables(windowId, shaderProgramId); 

     glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 

     while (glfwWindowShouldClose(windowId) == GLFW_FALSE) { 
      glClear(GL_COLOR_BUFFER_BIT); 

      glUseProgram(shaderProgramId); 
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 

      specifyVertexAttributes(shaderProgramId); 
      glBindTexture(GL_TEXTURE_2D, texture1.getId()); 
      glBindBuffer(GL_ARRAY_BUFFER, vbo1); 
      glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

      specifyVertexAttributes(shaderProgramId); 
      glBindTexture(GL_TEXTURE_2D, texture2.getId()); 
      glBindBuffer(GL_ARRAY_BUFFER, vbo2); 
      glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 

      glfwSwapBuffers(windowId); 

      glfwPollEvents(); 
     } 
    } 

    private void specifyUniformVariables(long windowId, int shaderProgramId) { 
     int uniModel = getUniform(shaderProgramId, "model"); 
     FloatBuffer model = BufferUtils.createFloatBuffer(16); 
     new Matrix4f().get(model); 
     glUniformMatrix4fv(uniModel, false, model); 

     FloatBuffer view = BufferUtils.createFloatBuffer(16); 
     new Matrix4f().get(view); 
     int uniView = getUniform(shaderProgramId, "view"); 
     glUniformMatrix4fv(uniView, false, view); 

     WindowSize windowSize = getWindowSize(windowId); 
     int uniProjection = getUniform(shaderProgramId, "projection"); 
     FloatBuffer projection = BufferUtils.createFloatBuffer(16); 
     new Matrix4f().ortho2D(0, windowSize.getWidth(), 0, windowSize.getHeight()).get(projection); 
     glUniformMatrix4fv(uniProjection, false, projection); 
    } 

    private void specifyVertexAttributes(int shaderProgramId) { 
     int stride = 7 * Float.BYTES; 

     int posAttrib = getAttribute(shaderProgramId, "position"); 
     glEnableVertexAttribArray(posAttrib); 
     glVertexAttribPointer(posAttrib, 2, GL_FLOAT, false, stride, 0); 

     int colAttrib = getAttribute(shaderProgramId, "color"); 
     glEnableVertexAttribArray(colAttrib); 
     glVertexAttribPointer(colAttrib, 3, GL_FLOAT, false, stride, 2 * Float.BYTES); 

     int texAttrib = getAttribute(shaderProgramId, "texcoord"); 
     glEnableVertexAttribArray(texAttrib); 
     glVertexAttribPointer(texAttrib, 2, GL_FLOAT, false, stride, 5 * Float.BYTES); 
    } 

    public long createWindow(int width, int height) { 
     glfwDefaultWindowHints(); 
     glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); 
     glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); 

     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 

     long windowId = glfwCreateWindow(width, height, "Hello World!", NULL, NULL); 
     if (windowId == NULL) { 
      throw new RuntimeException("Failed to create the GLFW window"); 
     } 

     // Get the resolution of the primary monitor 
     GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); 
     // Center our window 
     glfwSetWindowPos(
      windowId, 
      (vidmode.width() - width)/2, 
      (vidmode.height() - height)/2 
     ); 

     // Make the OpenGL context current 
     glfwMakeContextCurrent(windowId); 
     // Enable v-sync 
     glfwSwapInterval(1); 

     return windowId; 
    } 

    public WindowSize getWindowSize(long windowId) { 
     IntBuffer width = BufferUtils.createIntBuffer(1); 
     IntBuffer height = BufferUtils.createIntBuffer(1); 
     GLFW.glfwGetFramebufferSize(windowId, width, height); 
     return new WindowSize(width.get(), height.get()); 
    } 

    public Texture createTexture(String textureResource) { 
     int textureId = glGenTextures(); 
     glBindTexture(GL_TEXTURE_2D, textureId); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

     ARGBImage image = new ImageService().loadClasspathImage(textureResource); 
     glTexImage2D(
       GL_TEXTURE_2D, 
       0, 
       GL_RGBA8, 
       image.getWidth(), 
       image.getHeight(), 
       0, 
       GL_RGBA, 
       GL_UNSIGNED_BYTE, 
       image.getContents()); 

     return new Texture(textureId, image.getWidth(), image.getHeight()); 
    } 

    public int createShaderProgram(String vertexResource, String fragmentResource) { 
     int vertexShader = glCreateShader(GL_VERTEX_SHADER); 
     String vertexSource = getClasspathResource(vertexResource); 
     glShaderSource(vertexShader, vertexSource); 
     glCompileShader(vertexShader); 
     validateShaderCompilation(vertexShader); 

     int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
     String fragmentSource = getClasspathResource(fragmentResource); 
     glShaderSource(fragmentShader, fragmentSource); 
     glCompileShader(fragmentShader); 
     validateShaderCompilation(fragmentShader); 

     int shaderProgramId = glCreateProgram(); 
     glAttachShader(shaderProgramId, vertexShader); 
     glAttachShader(shaderProgramId, fragmentShader); 
     glLinkProgram(shaderProgramId); 
     validateShaderProgram(shaderProgramId); 
     glUseProgram(shaderProgramId); 

     return shaderProgramId; 
    } 

    private static String getClasspathResource(String resourceName) { 
     URL url = Resources.getResource(resourceName); 
     try { 
      return Resources.toString(url, Charsets.UTF_8); 
     } catch (IOException e) { 
      throw Throwables.propagate(e); 
     } 
    } 

    private static void validateShaderCompilation(int shader) { 
     int status = glGetShaderi(shader, GL_COMPILE_STATUS); 
     if (status != GL_TRUE) { 
      throw new RuntimeException(glGetShaderInfoLog(shader)); 
     } 
    } 

    private static void validateShaderProgram(int shaderProgram) { 
     int status = glGetProgrami(shaderProgram, GL_LINK_STATUS); 
     if (status != GL_TRUE) { 
      throw new RuntimeException(glGetProgramInfoLog(shaderProgram)); 
     } 
    } 

    public int getUniform(int shaderProgramId, String uniformName) { 
     int location = glGetUniformLocation(shaderProgramId, uniformName); 
     if (location == -1) { 
      throw new IllegalArgumentException("Could not find uniform: " 
        + uniformName + " for shaderProgramId: " + shaderProgramId); 
     } else { 
      return location; 
     } 
    } 

    public int getAttribute(int shaderProgramId, String attribute) { 
     int location = glGetAttribLocation(shaderProgramId, attribute); 
     if (location == -1) { 
      throw new IllegalArgumentException("Could not find attribute: " 
        + attribute + " for shaderProgramId: " + shaderProgramId); 
     } else { 
      return location; 
     } 
    } 

    public static void main(String[] args) { 
     new StandaloneMultiTextureExample().run(); 
    } 

} 
+1

Une chose que j'ai remarquée; vous devez lier un buffer de tableau _before_ appelant 'glVertexAttribPointer', car' glVertexAttribPointer' est où OpenGL lit l'objet buffer de tableau actuellement lié et l'affecte au VAO (de sorte que les modifications ultérieures de la liaison du buffer de tableau soient inutiles) –

+0

Merci @ ColonelThirtyTwo. J'ai essayé un certain nombre d'ordres différents des déclarations opengl, mais j'ai dû manquer celui-là. Si vous vous souciez des points de débordement de la pile, postez-le comme réponse et je l'accepterai. – Kevin

Répondre

1

Vous configurez vos tableaux de sommets de manière incorrecte, en liant le tampon de sommet au mauvais moment. Lorsque vous utilisez des objets Vertex Array Objects (VAO) pour rendre [1], la seule lecture de la liaison GL_ARRAY_BUFFER est l'appel glVertexAttribPointer. L'appel glVertexAttribPointer prend le nom de l'objet GL_ARRAY_BUFFER actuellement lié et l'associe à l'attribut et à l'objet VAO; après cela, la liaison GL_ARRAY_BUFFER n'a aucune importance et la liaison d'un autre tampon de tableau ne modifiera en aucune façon le VAO.

Dans votre code, vous appelez specifyVertexAttributes pour configurer votre VAO avant que vous appelez glBindBuffer. Cela signifie que le tampon de tableau que glVertexAttribPointer enregistre est le précédent utilisé. Dans vos deux premiers exemples, où vous ne liez qu'un seul tampon de tableau à un moment donné, cela "fonctionne" car le tampon lié de l'image précédente persiste et est lu dans l'image suivante; Si vous avez mis votre programme en pause dès la première image, il sera probablement noir.

La solution dans votre cas est simple; déplacez l'appel glBindBuffer au-dessus de l'appel specifyVertexAttributes, afin que vos appels glVertexAttribPointer lisent le tampon approprié. Notez que cela ne pas s'applique avec la liaison GL_ELEMENT_ARRAY_BUFFER; la liaison est enregistrée dans le VAO chaque fois que vous en liez un nouveau.

[1] Techniquement, vous utilisez le VAO par défaut, qui n'est pris en charge que dans un contexte de compatibilité, mais il est facile de créer et de lier un VAO global utilisé en permanence.