I’m attempting to set up a fragment and vertex shader where the vertex shader outputs a quad that covers the entire screen and the fragment shader draws a signed distance function on it.
I know that you can attach fragment shade through loadShader("myshader.glsl");
but I want to have more flexibility and be able to use compute shaders.
Currently, I’m running into this error message “OpenGL error 1282 at top endDraw(): invalid operation”
The shaders have worked on a previous project so hopefully, they are correct. My guess is that I’ve missed something when I’m setting up the state for the shaders in the Java code.
Here is the code:
Vertex Shader:
#version 400 core
/* A very basic vertex shader to allow us to take a picel point, transform them with
* a matrix and then output the clipspace coordinates
*/
layout(location = 0) in vec2 a_position;
uniform vec2 u_resolution;
uniform mat3 u_matrix;
void main() {
// Multiply the position by the matrix.
vec2 position = (u_matrix * vec3(a_position, 1)).xy;
// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clip_space = zeroToTwo - 1.0;
gl_Position = vec4(clip_space * vec2(1, -1), 0, 1);
}
SDG Circle Fragment Shader:
#version 400 core
// fragment shaders don't have a default precision so we need
// to pick one. highp is a good default. It means "high precision"
precision highp float;
uniform vec2 u_resolution;
// .x = f(p)
// .y = ∂f(p)/∂x
// .z = ∂f(p)/∂y
// .yz = ∇f(p) with ‖∇f(p)‖ = 1
vec3 sdgCircle( in vec2 p, in float r )
{
float l = length(p);
return vec3( l-r, p/l );
}
// we need to declare an output for the fragment shader
layout(location = 0) out vec4 outColor;
void main()
{
vec2 p = (2.0*gl_FragCoord.xy-u_resolution.xy)/u_resolution.y;
// sdf(p) and gradient(sdf(p))
vec3 dg = sdgCircle(p,0.5);
float d = dg.x;
vec2 g = dg.yz;
// central differenes based gradient, for comparison
// g = vec2(dFdx(d),dFdy(d))/(2.0/iResolution.y);
// coloring
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.4,0.7,0.85);
col *= 1.0 + vec3(0.5*g,0.0);
//col = vec3(0.5+0.5*g,1.0);
col *= 1.0 - 0.5*exp(-16.0*abs(d));
col *= 0.9 + 0.1*cos(150.0*d);
col = mix( col, vec3(1.0), 1.0-smoothstep(0.0,0.01,abs(d)) );
outColor = vec4(col,1.0);
}
Main Program
import com.jogamp.opengl.*;
import com.jogamp.common.nio.Buffers;
import java.nio.FloatBuffer;
LightingSystem ls;
GL4 gl;
ShaderProgram shaderProgram;
void setup() {
size(1000, 1000, P2D);
PGL pgl = ((PGraphicsOpenGL)g).pgl;
gl = ((PJOGL)pgl).gl.getGL4();
shaderProgram = new ShaderProgram(gl, "simple.vert", "sdgCircle2.frag", width, height);
//ls = new LightingSystem(gl, 5000, (float) width, (float) height);
}
void draw() {
background(0);
shaderProgram.draw();
//ls.update();
//ls.render();
}
void dispose() {
shaderProgram.release();
//ls.release();
}
ShaderProgram
import com.jogamp.opengl.GL4;
class ShaderProgram {
private GL4 gl;
private ShaderHelper shaderHelper = new ShaderHelper();
private int shaderProgram;
private int vertShader;
private int fragShader;
// Vertex Buffer Object
private int[] vbo = new int[1];
private int numberOfIndicesToRender;
ShaderProgram(GL4 gl, String vertexFileName, String fragmentFileName, float width, float height) {
this.gl = gl;
vertShader = shaderHelper.createAndCompileShader(gl, GL4.GL_VERTEX_SHADER, vertexFileName);
fragShader = shaderHelper.createAndCompileShader(gl, GL4.GL_FRAGMENT_SHADER, fragmentFileName);
shaderProgram = gl.glCreateProgram();
gl.glAttachShader(shaderProgram, vertShader);
gl.glAttachShader(shaderProgram, fragShader);
gl.glLinkProgram(shaderProgram);
// Fill screen with a rectangle we can draw on
gl.glGenBuffers(1, vbo, 0);
gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vbo[0]);
float[] vertices = createRectangle(gl, 0.0, 0.0, width, height);
this.numberOfIndicesToRender = vertices.length;
FloatBuffer rectangleFB = Buffers.newDirectFloatBuffer(vertices);
int numberOfBytes = rectangleFB.limit()*4;
gl.glBufferData(GL4.GL_ARRAY_BUFFER, numberOfBytes, rectangleFB, GL4.GL_STATIC_DRAW);
gl.glEnableVertexAttribArray(0);
// Since the vertex has 1 vec2 variable, then the stride is 8
// position attribute (no offset)
gl.glVertexAttribPointer(0, 2, GL4.GL_FLOAT, false, 2 * 4, 0);
// Pass the transformation matrix
int matrixLocation = gl.glGetUniformLocation(shaderProgram, "u_matrix");
float[] matrix =
{ 1.0, 0.0, 0.0
, 0.0, 1.0, 0.0
, 0.0, 0.0, 1.0
};
gl.glUniformMatrix3fv(matrixLocation, 1, false, Buffers.newDirectFloatBuffer(matrix));
// Pass the resolution
int resolutionLocation = gl.glGetUniformLocation(shaderProgram, "u_resolution");
gl.glUniform2f(resolutionLocation, width, height);
}
/**
* Adds two triangles (creating a rectangle) to the currently bound buffer.
*/
float[] createRectangle(GL4 gl, float x, float y, float width, float height){
float x1 = x;
float x2 = x + width;
float y1 = y;
float y2 = y + height;
float[] res = {x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2};
return res;
}
void draw() {
gl.glUseProgram(shaderProgram);
gl.glDrawArrays(GL4.GL_TRIANGLES, 0, numberOfIndicesToRender);
}
void release() {
gl.glDeleteShader(vertShader);
gl.glDeleteShader(fragShader);
}
}
ShaderHelper
/**
* Helper class that contains static methods
*/
class ShaderHelper {
public int createAndCompileShader(GL4 gl, int type, String shaderPath) {
int shader = gl.glCreateShader(type);
// String[] vlines = new String[]{PApplet.join(loadStrings(shaderPath), "\n")};
// int[] vlengths = new int[]{vlines[0].length()};
String[] vlines = new String[]{PApplet.join(loadStrings(shaderPath), "\n")};
int[] vlengths = new int[vlines.length];
for (int i = 0; i < vlines.length; i++){
vlengths[i] = vlines[i].length();
}
gl.glShaderSource(shader, vlines.length, vlines, vlengths, 0);
gl.glCompileShader(shader);
int[] compiled = new int[1];
gl.glGetShaderiv(shader, GL4.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
int[] logLength = new int[1];
gl.glGetShaderiv(shader, GL4.GL_INFO_LOG_LENGTH, logLength, 0);
byte[] log = new byte[logLength[0]];
gl.glGetShaderInfoLog(shader, logLength[0], (int[]) null, 0, log, 0);
throw new IllegalStateException("Error compiling the shader '" + shaderPath + "': " + new String(log));
}
return shader;
}
public boolean updateUniform1i(GL4 gl, int compute_program, String uniformName, int uniformValue) {
int loc = gl.glGetUniformLocation(compute_program, uniformName);
if (loc != -1)
{
gl.glUniform1i(loc, uniformValue);
return true;
}
return false;
}
public boolean updateUniform1f(GL4 gl, int compute_program, String uniformName, float uniformValue) {
Integer loc = gl.glGetUniformLocation(compute_program, uniformName);
if (loc != -1)
{
gl.glUniform1f(loc, uniformValue);
return true;
}
return false;
}
public boolean updateUniform2f(GL4 gl, int compute_program, String uniformName, float uniformValue1, float uniformValue2) {
int loc = gl.glGetUniformLocation(compute_program, uniformName);
gl.glUniform2f(loc, uniformValue1, uniformValue2);
if (loc != -1)
{
gl.glUniform2f(loc, uniformValue1, uniformValue2);
return true;
}
return false;
}
public boolean updateUniform3f(GL4 gl, int compute_program, String uniformName, float uniformValue1, float uniformValue2, float uniformValue3) {
int loc = gl.glGetUniformLocation(compute_program, uniformName);
if (loc != -1)
{
gl.glUniform3f(loc, uniformValue1, uniformValue2, uniformValue3);
return true;
}
return false;
}
}