InexperiencedCoder
InexperiencedCoder

Reputation: 73

LWJGL - Vertex / Fragment Shader not working

I have managed to open a window and render a triangle on the screen in LWJGL. I have now created two external files for the vertex shader & fragment shader. However the triangle remains white.

This is the main file, where it calls the method to load the vertex shader and compile it, I have added a simple system.out line to see if this is being called, which it is.

import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.*;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Main {
    
     String TITLE = "f";
    
    

    // The window handle
    private long window;

    public void run() {
        System.out.println("Hello LWJGL " + Version.getVersion() + "!");

        init();
        loop();

        // Free the window callbacks and destroy the window
        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);

        // Terminate GLFW and free the error callback
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private void init() {
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        GLFWErrorCallback.createPrint(System.err).set();

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( !glfwInit() )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure GLFW
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

        // Create the window
        window = glfwCreateWindow(300, 300, TITLE, NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
        });

        // Get the thread stack and push a new frame
        try ( MemoryStack stack = stackPush() ) {
            IntBuffer pWidth = stack.mallocInt(1); // int*
            IntBuffer pHeight = stack.mallocInt(1); // int*

            // Get the window size passed to glfwCreateWindow
            glfwGetWindowSize(window, pWidth, pHeight);

            // Get the resolution of the primary monitor
            GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            // Center the window
            glfwSetWindowPos(
                window,
                (vidmode.width() - pWidth.get(0)) / 2,
                (vidmode.height() - pHeight.get(0)) / 2
            );
        } // the stack frame is popped automatically

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
    
        
        // Enable v-sync
        glfwSwapInterval(1);
    
        // Make the window visible
        glfwShowWindow(window);
        
    }

    private void loop() {
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the GLCapabilities instance and makes the OpenGL
        // bindings available for use.
        GL.createCapabilities();
        
        drawTriangle();
        loadShader("screenvertfilelocation", GL30.GL_VERTEX_SHADER);
        loadShader("screenvertfilelocation", GL30.GL_FRAGMENT_SHADER);
        
        
        
        // Set the clear color
        glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

        // Run the rendering loop until the user has attempted to close
        // the window or has pressed the ESCAPE key.
        while ( !glfwWindowShouldClose(window) ) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
            
            processTriangle();

            glfwSwapBuffers(window); // swap the color buffers

            // Poll for window events. The key callback above will only be
            // invoked during this call.
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        new Main().run();
    }
    
    int vertexCount = 0;
    int VAO = 0;
    int VBO = 0;

    public void drawTriangle() {
    
    float vertices[] = {
            -0.5f, -0.5f, 0.0f,
             0.5f, -0.5f, 0.0f,
             0.0f,  0.5f, 0.0f
        };  


    int VBO = GL30.glGenBuffers();
    int VAO = GL30.glGenBuffers();
 
    
    // Sending data to OpenGL requires the usage of (flipped) byte buffers
    FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(vertices.length);
    verticesBuffer.put(vertices);
    verticesBuffer.flip();
     
    vertexCount = 3;
    
    
    GL30.glBindVertexArray(VAO);

    GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, VBO);

    GL30.glBufferData(GL30.GL_ARRAY_BUFFER, verticesBuffer, GL30.GL_STATIC_DRAW);
    

    GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 0, 0);
    
    GL30.glEnableVertexAttribArray(0);
    
    GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, 0); 
    GL30.glBindVertexArray(0); 
    
    }
    
    public void processTriangle() {
        GL30.glBindVertexArray(VAO);
        GL30.glDrawArrays(GL_TRIANGLES, 0, 3);
    }
    
    
    //Deals with the Shaders
    private static int loadShader(String file, int type){
          StringBuilder shaderSource = new StringBuilder();
          try{
           BufferedReader reader = new BufferedReader(new FileReader(file));
           String line;
           while((line = reader.readLine())!=null){
            shaderSource.append(line).append("//\n");
           }
           reader.close();
          }catch(IOException e){
           e.printStackTrace();
           System.exit(-1);
          }
          int shaderID = GL20.glCreateShader(type);
          GL20.glShaderSource(shaderID, shaderSource);
          GL20.glCompileShader(shaderID);
          
          int vertexShader;
          vertexShader = GL30.glCreateShader(GL30.GL_VERTEX_SHADER);
          int fragmentShader;
          fragmentShader = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
          
          
          
          
          int shaderProgram;
          shaderProgram = GL30.glCreateProgram();
          
          
          GL30.glAttachShader(shaderProgram, vertexShader);
          GL30. glAttachShader(shaderProgram, fragmentShader);
          GL30.glLinkProgram(shaderProgram);
         
         
          GL30.glUseProgram(shaderProgram);
          
         GL30.glDeleteShader(vertexShader);
         GL30.glDeleteShader(fragmentShader); 
          
          System.out.println("Hello");
          
          if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS )== GL11.GL_FALSE){
           System.out.println(GL20.glGetShaderInfoLog(shaderID, 500));
           System.err.println("Could not compile shader!");
           System.exit(-1);
          }
          return shaderID;
         }

}

Here is the vertex shader file:

    #version 330 core
layout (location = 0) in vec3 aPos; 
  
out vec4 vertexColor; 

void main()
{
    gl_Position = vec4(aPos, 1.0); 
    vertexColor = vec4(0.5, 4.0, 0.0, 1.0); 
}

and here is the fragment shader file:

    #version 330 core
out vec4 FragColor;
  
in vec4 vertexColor; 

void main()
{
    FragColor = vertexColor;
} 

Upvotes: 0

Views: 812

Answers (1)

Sync it
Sync it

Reputation: 1198

There are both improvements and corrections to be made here

1. Improvements

This is in your shader. After linking your shader you also need to verify it. Although your shader works fine without it for more complex programs it can reveal hidden error's

Here is the modified code[Just an suggestion take it if you wish]

private void loadProgram()
{
      int vertex,fragment;
     
      int programID=GL20.glCreateProgram();  //Step 1 create program and attach source code to it
      GL20.glAttachShader(programID,vertex=loadShader("screenvertfilelocation",GL20.GL_VERTEX_SHADER));
      GL20.glAttachShader(programID,fragment=loadShader("screenvertfilelocation",GL20.GL_FRAGMENT_SHADER));
      
      
      
      GL20.glLinkProgram(programID);   //Step 2 link the program
      if(GL20.glGetProgrami(programID,GL20.GL_LINK_STATUS)==GL11.GL_FALSE)
      {  
        int infoLogSize=GL20.glGetProgrami(programID,GL20.GL_INFO_LOG_LENGTH); //Get's exact error size rather than using 500
        System.err.println(GL20.glGetProgramInfoLog(programID,infoLogSize));
        System.err.println("COULD NOT LINK SHADER");
        System.exit(-1);
      } 
      
      
      
      GL20.glValidateProgram(programID);  //Step 3 Validate shader
      if(GL20.glGetProgrami(programID,GL20.GL_VALIDATE_STATUS)==GL11.GL_FALSE)
      {
        int infoLogSize=GL20.glGetProgrami(programID,GL20.GL_INFO_LOG_LENGTH);  //Get exact error size
        System.err.println(GL20.glGetProgramInfoLog(programID,infoLogSize));
        System.err.println("COULD NOT VALIDATE SHADER");
        System.exit(-1);
      } 
      
      GL20.glDeleteShader(vertex);    //Step 4 clean up
      GL20.glDeleteShader(fragment);
      
      GL20.glUseProgram(programID);
    }
    
    private int loadShader(String fileName,int shaderType)
    {
     try(BufferedReader reader = new BufferedReader(new FileReader(fileName)))
     {
      StringBuilder source=new StringBuilder();
      
      String line;
      while((line=reader.readLine())!=null)
      {
       source.append(line)
             .append(System.lineSeparator());
      }
      
      int shaderID=GL20.glCreateShader(shaderType);
      GL20.glShaderSource(shaderID,source);
      GL20.glCompileShader(shaderID);

      if(GL20.glGetShaderi(shaderID,GL20.GL_COMPILE_STATUS)==GL11.GL_FALSE)
      {
        int infoLogSize=GL20.glGetShaderi(shaderID,GL20.GL_INFO_LOG_LENGTH); 
        throw new IOException("COULD NOT COMPILE SHADER "+GL20.glGetShaderInfoLog(shaderID,infoLogSize));
      }    
      return shaderID;
     }
     catch(IOException ex)
     {
      ex.printStackTrace(System.err);
      System.exit(-1);
      return -1;
     }  
    }  

Call loadProgram() after drawTriangle()

2. Your Solution

This is just a follow up from @Rabbid76 post

As soon as i copy pasted your code in my IDE i get the warning

local variable hides a field

In this code

int vertexCount = 0;
    int VAO = 0;
    int VBO = 0;

    public void drawTriangle() {
    
    float vertices[] = 
     {
            -0.5f, -0.5f, 0.0f,
             0.5f, -0.5f, 0.0f,
             0.0f,  0.5f, 0.0f
   };  

    //The warning here. You are redeclaring VBO & VAO
    int VBO = GL15.glGenBuffers();
    int VAO = GL30.glGenVertexArrays(); // @Rabbid76 original fix

Just remove the declarations

    VBO = GL15.glGenBuffers();
    VAO = GL30.glGenVertexArrays();

I am using LWJGL 3.1.3 and most of the gl functions and constants i use belong to an diffrent gl version for example there is no

GL30.GL_FLOAT

but

GL11.GL_FLOAT

Just to name a few

Output:

enter image description here

Upvotes: -1

Related Questions