Search code examples
javac++openglglsljogl

How to edit vertex shader in JOGL


So im working on a Java/Jogl application that basically just translates the vertices of a triangle. So far I am able to get the triangle to move left to right, but I cant figure out how to edit the vertex shader so that when I click a button, the triangle begins to move up and down instead of left and right.

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.*;
import javax.swing.*;
import static com.jogamp.opengl.GL4.*;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.FPSAnimator;
import graphicslib3D.GLSLUtils;

import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.Vector;

public class a1 extends JFrame implements GLEventListener
{   
    private GLCanvas myCanvas;
    private int rendering_program;
    private int vao[] = new int[1];
    private GLSLUtils util = new GLSLUtils();
    private Button button1, button2;

    private float x = 0.0f;
    private float y = 0.0f;
    private float inc = 0.01f;
    private float incy = 0.01f;
    private int click = 1;

public a1()
{   setTitle("Chapter2 - program2");
    setSize(600, 400);
    myCanvas = new GLCanvas();
    myCanvas.addGLEventListener(this);
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(myCanvas, BorderLayout.CENTER);

    JPanel sidePanel = new JPanel();
    sidePanel.setLayout(new BoxLayout(sidePanel, BoxLayout.Y_AXIS));
    button1 = new Button("button");
    button2 = new Button("button2");
    sidePanel.add(button1);
    sidePanel.add(button2);
    getContentPane().add(sidePanel, BorderLayout.WEST);

    button2.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            click = 1;

        }
    });

    setVisible(true);
    FPSAnimator animator = new FPSAnimator(myCanvas, 30);
    animator.start();
}

public void display(GLAutoDrawable drawable)
{   GL4 gl = (GL4) GLContext.getCurrentGL();
    gl.glUseProgram(rendering_program);
    gl.glPointSize(50.0f);

    float bkg[] = {0.0f, 0.0f, 0.0f, 1.0f};
    FloatBuffer bkgBuffer = Buffers.newDirectFloatBuffer(bkg);
    gl.glClearBufferfv(GL_COLOR, 0, bkgBuffer);

    x+=inc;
    y+=incy;
    if(x > 1.0f) inc = -0.01f;
    if(x < -1.0f) inc = 0.01f;

    if(y > 1.0f) incy = -0.01f;
    if(y< -1.0f) incy = 0.01f;


    int offset_loc = gl.glGetUniformLocation(rendering_program, "inc");
    int offset_y = gl.glGetUniformLocation(rendering_program, "incy");
    int flag = gl.glGetUniformLocation(rendering_program, "flag");

    gl.glProgramUniform1f(rendering_program, offset_loc, x);
    gl.glProgramUniform1f(rendering_program, offset_y, y);
    gl.glProgramUniform1f(rendering_program, flag, click);
    gl.glDrawArrays(GL_TRIANGLES,0,3);
}


public void init(GLAutoDrawable drawable)
{   GL4 gl = (GL4) GLContext.getCurrentGL();
    rendering_program = createShaderProgram();
    gl.glGenVertexArrays(vao.length, vao, 0);
    gl.glBindVertexArray(vao[0]);
}

private int createShaderProgram()
{
    GL4 gl = (GL4) GLContext.getCurrentGL();
    int[] vertCompiled = new int[1];
    int[] fragCompiled = new int[1];
    int[] linked = new int[1];

    String vshaderSource[] = readShaderSource("src/vert.shader");
    String fshaderSource[] = readShaderSource("src/frag.shader");

    int vShader = gl.glCreateShader(GL_VERTEX_SHADER);
    gl.glShaderSource(vShader, vshaderSource.length, vshaderSource, null, 0);
    gl.glCompileShader(vShader);

    util.checkOpenGLError();
    gl.glGetShaderiv(vShader, GL_COMPILE_STATUS, vertCompiled, 0);
    if(vertCompiled[0] == 1)
    {
        System.out.println("vertex compilation success");
    }else{
        System.out.println("vertex compilation failed");
        util.printShaderLog(vShader);
    }
    int fShader = gl.glCreateShader(GL_FRAGMENT_SHADER);
    gl.glShaderSource(fShader, fshaderSource.length, fshaderSource, null, 0);
    gl.glCompileShader(fShader);

    util.checkOpenGLError();
    gl.glGetShaderiv(fShader, GL_COMPILE_STATUS, fragCompiled, 0);
    if(fragCompiled[0] == 1)
    {
        System.out.println("fragment compilation success");
    }else{
        System.out.println("fragment compilation failed");
        util.printShaderLog(fShader);
    }

    int vfprogram = gl.glCreateProgram();
    gl.glAttachShader(vfprogram, vShader);
    gl.glAttachShader(vfprogram, fShader);
    gl.glLinkProgram(vfprogram);

    util.checkOpenGLError();
    gl.glGetProgramiv(vfprogram, GL_LINK_STATUS, linked, 0);
    if(linked[0] == 1)
    {
        System.out.println("linking succeeded");
    }else{
        System.out.println("linking failed");
        util.printProgramLog(vfprogram);
    }
    //gl.glDeleteShader(vShader);
    //gl.glDeleteShader(fShader);
    return vfprogram;
}

public static void main(String[] args) { new a1(); }
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
public void dispose(GLAutoDrawable drawable) {}

private String[] readShaderSource(String filename)
{
    Vector<String> lines = new Vector<String>();
    Scanner sc;
    try
    {
        sc = new Scanner(new File(filename));
    }catch (IOException e)
    {
        System.err.println("IOException reading file: " + e);
        return null;
    }
    while(sc.hasNext())
    {
        lines.addElement(sc.nextLine());
    }
    String[] program = new String[lines.size()];
    for(int i=0; i<lines.size(); i++)
    {
        program[i] = (String) lines.elementAt(i)+ "\n";
    }
    return program;
}
}

#version 430
uniform float inc;
void main(void)
{

  if(gl_VertexID == 0) gl_Position = vec4(0.25, -0.25+inc, 0.0, 1.0);
  else if(gl_VertexID == 1) gl_Position = vec4(-0.25, -0.25+inc, 0.0, 1.0);
  else gl_Position = vec4(0.25, 0.25+inc, 0.0, 1.0);

}

How do I edit my vertex shader so that when I click on a button the location of the vertices changes and the triangle begins to move up and down instead of left to right?


Solution

  • 1) Don't do the update like that

    2) Don't use an int array for the OpenGL resources (vao), prefer a direct integer buffer, you can use GLBuffers.newDirectIntBuffer(1); for the vao for example..

    3) Don't use an FPSAnimator, use Animator instead

    4) Don't inialize a new direct buffer everytime in the display() method (bkgBuffer), do it just once in the variable declaration or in the init(). You should also dispose any direct buffer, since it is not guaranteed that they are gonna be removed by the garbage collector. I have a small class for that here. A better one however is the implementation of Gouessej here.

    4) Use a vertex buffer object to declare your vertices attributes (like position)

    5) Declare a boolean flag variable update to trigger the update.

    button2.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            update = 1;
        }
    });
    
    public void display(GLAutoDrawable drawable) {   
    
        GL4 gl = (GL4) GLContext.getCurrentGL();
    
        if(update) {
            update = false;
            ...
        }
    }
    

    now you have 2 possibilities:

    • you update the vertices directly

          gl3.glBindBuffer(GL_ARRAY_BUFFER, bufferName.get(Buffer.VERTEX));
          gl3.glBufferSubData(GL_ARRAY_BUFFER, 0, vertexBuffer.capacity(), vertexBuffer);
          gl3.glBindBuffer(GL_ARRAY_BUFFER, 0);
      

    and your vertex shader may be something like

    #version 430    
    layout (location = POSITION) in vec2 position;
    void main(void)
    {    
        gl_Position = vec4(position, 0, 1);
    }
    
    • you update only the matrix that is going to multiply the vertices

      gl3.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.TRANSFORM));
      gl3.glBufferSubData(GL_UNIFORM_BUFFER, 0, Mat4.SIZE, matBuffer);
      gl3.glBindBuffer(GL_UNIFORM_BUFFER, 0);
      

    and in this case the vertex may be

    #version 430    
    layout (location = POSITION) in vec2 position;
    
    layout (binding = TRANSFORM) uniform Transform
    {
        mat4 mat;
    };
    
    void main(void)
    {    
        gl_Position = mat * vec4(position, 0, 1);
    }
    

    In case you need further assistance, don't hesitate to ask for help. For inspiration, you can refer to this hello triangle of mine