Related
The problem is that i am trying to create a 3D Cube via using the shaders, but the problem is that, it doesn't read the file correctly.
Here are the shaders that I have created, the problem is that it reads not correctly the sharders and give the error
I also get just a black screen as a result
My Shaders
Vertex shader
// vertex.glsl
#version 430
layout (location = 0) in vec3 position;
uniform mat4 proj_matrix;
uniform mat4 mv_matrix;
void main(void) {
gl_Position = proj_matrix * mv_matrix * vec4(position, 1.0);
}
Fragemtn shader
// fragment.glsl
#version 430
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void) {
color = vec4(1.0, 0.0, 0.0, 1.0);
}
main code
// my main code
import java.io.File;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLContext;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.math.Matrix4;
import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.common.nio.Buffers;
import com.jogamp.gluegen.*;
public class GOVNO extends JFrame implements GLEventListener {
private GLCanvas myCanvas;
private int rendering_program;
private int vbo[] = new int[2];
private int mTrans;
public GOVNO() {
setTitle("Chapter2 - program1");
setSize(600, 400);
setLocation(200, 200);
GLProfile profile = GLProfile.getDefault();
GLCapabilities capabilities = new GLCapabilities(profile);
myCanvas = new GLCanvas(capabilities);
myCanvas.addGLEventListener(this);
this.add(myCanvas);
setVisible(true);
}
public void display(GLAutoDrawable drawable) {
GL2 gl = (GL2) GLContext.getCurrentGL();
gl.glUseProgram(rendering_program);
float a = 0;
//Matrix4 mTransMatrix = new Matrix4();
float mTransMatrix[] = {
(float) Math.cos(a), (float) -Math.sin(a), 0, 0,
(float) Math.sin(a), (float) Math.cos(a), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
gl.glUniformMatrix4fv(mTrans, 1, false, mTransMatrix, 0);
gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo[0]);
gl.glVertexAttribPointer(0, 2, GL3.GL_FLOAT, false, 0, 0);
gl.glEnableVertexAttribArray(0);
gl.glDrawArrays(GL3.GL_TRIANGLES, 0, 6);
gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo[1]);
gl.glVertexAttribPointer(0, 2, GL3.GL_FLOAT, false, 0, 0);
gl.glEnableVertexAttribArray(0);
gl.glDrawArrays(GL3.GL_QUADS, 0, 8);
}
public void init(GLAutoDrawable drawable) {
GL2 gl = (GL2) GLContext.getCurrentGL();
rendering_program = createShaderProgram();
// generating location for transformation matrix
mTrans = gl.glGetUniformLocation(rendering_program, "trans");
float[] vertex_positions = { -0.5f, -1.0f, 0.0f, -0.5f, 0.5f, -1.0f, };
gl.glGenBuffers(vbo.length, vbo, 0);
gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo[0]);
FloatBuffer vertBuf Buffers.newDirectFloatBuffer(vertex_positions);
gl.glBufferData(GL3.GL_ARRAY_BUFFER, vertBuf.limit() * 4, vertBuf, GL3.GL_STATIC_DRAW);
float[] vertex_positions2 = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f };
gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo[1]);
FloatBuffer vertBuf2 = Buffers.newDirectFloatBuffer(vertex_positions2);
gl.glBufferData(GL3.GL_ARRAY_BUFFER, vertBuf2.limit() * 4, vertBuf2, GL3.GL_STATIC_DRAW);
}
private int createShaderProgram() {
GL2 gl = (GL2) GLContext.getCurrentGL();
String vshaderSource[] = readShaderSource("src/vertex.glsl");
String fshaderSource[] = readShaderSource("src/fragment.glsl");
int vShader = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
gl.glShaderSource(vShader, vshaderSource.length, vshaderSource, null, 0);
gl.glCompileShader(vShader);
printShaderLog(vShader);
int fShader = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
gl.glShaderSource(fShader, fshaderSource.length, fshaderSource, null, 0);
gl.glCompileShader(fShader);
printShaderLog(fShader);
int vfprogram = gl.glCreateProgram();
gl.glAttachShader(vfprogram, vShader);
gl.glAttachShader(vfprogram, fShader);
gl.glLinkProgram(vfprogram);
gl.glDeleteShader(vShader);
gl.glDeleteShader(fShader);
printProgramLog(vfprogram);
return vfprogram;
}
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";
System.out.print(program[i]);
}
return program;
}
private void printShaderLog(int shader) {
GL2 gl = (GL2) GLContext.getCurrentGL();
int[] len = new int[1];
int[] chWrittn = new int[1];
byte[] log = null;
// determine the length of the shader compilation log
gl.glGetShaderiv(shader, GL3.GL_INFO_LOG_LENGTH, len, 0);
if (len[0] > 0) {
log = new byte[len[0]];
gl.glGetShaderInfoLog(shader, len[0], chWrittn, 0, log, 0);
System.out.println("Shader Info Log: ");
for (int i = 0; i < log.length; i++) {
System.out.print((char) log[i]);
}
}
}
void printProgramLog(int prog) {
GL2 gl = (GL2) GLContext.getCurrentGL();
int[] len = new int[1];
int[] chWrittn = new int[1];
byte[] log = null;
// determine the length of the program linking log
gl.glGetProgramiv(prog, GL3.GL_INFO_LOG_LENGTH, len, 0);
if (len[0] > 0) {
log = new byte[len[0]];
gl.glGetProgramInfoLog(prog, len[0], chWrittn, 0, log, 0);
System.out.println("Program Info Log: ");
for (int i = 0; i < log.length; i++) {
System.out.print((char) log[i]);
}
}
}
public static void main(String[] args) {
System.out.println("Working Directory = " + System.getProperty("user.dir"));
new GOVNO();
}
}
I'm learning LWJGL and OpenGL by following this tutorial i found, i tried my best to change the code to be compatible with the never versions and hadnt a problem with it so far. But now my Tilerenderer wont render more than one type of tile/one texture for the VBO's and i tried to fix it now since 3 days (in the beginning it didn't render anything at all) but couldn't find anything that fixes this problem.
I'm using Java 9.0.4 and LWJGL 3.2.1 build 12 with JOML 1.9.13, GLFW, OpenGL and stb.
So far i tried changing the entire code involved in this problem and changing different variables for shaders but nothing seemed to work so far.
Here are all classes i figured might have something to do with the problem.
The Main class
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL;
public class Main {
public static void main(String[] args) {
int speed = 5;
Window.setCallbacks();
if (!glfwInit()) {
throw new IllegalStateException("Failed to init GLFW");
}
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
Window window = new Window();
window.setSize(640, 480);
window.setFullscreen(false);
window.createWindow("GAME");
GL.createCapabilities();
Camera camera = new Camera(window.getWidth(), window.getHeight());
glEnable(GL_TEXTURE_2D);
TileRenderer tiles = new TileRenderer();
Shader shader = new Shader("shader");
World world = new World();
world.setTile(Tile.test_tile, 0, 0);
double frameCap = 1.0 / 60.0;
double frameTime = 0;
double time = Timer.getTime();
double unprocessed = 0;
int frames = 0;
while(!window.shouldClose()) {
boolean canRender = false;
double time2 = Timer.getTime();
double passed = time2 - time;
unprocessed+=passed;
frameTime += passed;
time = time2;
while (unprocessed >= frameCap) {
canRender = true;
unprocessed-=frameCap;
if(window.getInput().isMouseButtonDown(0)) {
glfwSetWindowShouldClose(window.getWindow(), true);
}
if (window.getInput().isKeyPressed(GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(window.getWindow(), true);
}
if(window.getInput().isKeyDown(GLFW_KEY_W)) {
camera.addPosition(new Vector3f(0, -speed, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_A)) {
camera.addPosition(new Vector3f(speed, 0, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_S)) {
camera.addPosition(new Vector3f(0, speed, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_D)) {
camera.addPosition(new Vector3f(-speed, 0, 0));
}
if(window.getInput().isKeyDown(GLFW_KEY_O)) {
speed = 5;
}
if(window.getInput().isKeyDown(GLFW_KEY_P)) {
speed = 25;
}
window.update();
if (frameTime >= 1.0) {
frameTime = 0;
System.out.println("FPS:" + frames);
frames = 0;
}
}
if (canRender) {
glClear(GL_COLOR_BUFFER_BIT);
world.render(tiles, shader, camera);
window.swapBuffers();
frames++;
}
}
glfwTerminate();
}
}
The World class
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class World {
private byte[] tiles;
private int width;
private int height;
private Matrix4f world;
public World () {
width = 16;
height = 16;
tiles = new byte [width * height];
world = new Matrix4f().setTranslation(new Vector3f(0));
world.scale(32);
}
public void render(TileRenderer renderer, Shader shader, Camera camera) {
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
renderer.renderTile(tiles[x + y * width], y, -x, shader, world, camera);
}
}
}
public void setTile (Tile tile, int x, int y) {
System.err.println(tile.getId());
tiles[x + y * width] = tile.getId();
}
}
The Tilerenderer class
import java.util.HashMap;
import org.joml.Matrix4f;
import org.joml.Vector3f;
public class TileRenderer {
private HashMap<String, Texture> tileTextures;
private Model tileModel;
public TileRenderer() {
tileTextures = new HashMap<>();
float[] vertices = new float[]{
-1f, 1f, 0, // TOP LEFT 0
1f, 1f, 0, // TOP RIGHT 1
1f, -1f, 0, // BOTTOM RIGHT 2
-1f, -1f, 0,// BOTTOM LEFT 3
};
float[] texture = new float[]{0, 0, 1, 0, 1, 1, 0, 1,};
int[] indices = new int[]{0, 1, 2, 2, 3, 0};
tileModel = new Model(vertices, texture, indices);
for (int i = 0; i < Tile.tiles.length; i++) {
if (Tile.tiles[i] != null) {
if (!tileTextures.containsKey(Tile.tiles[i].getTexture())) {
String tex = Tile.tiles[i].getTexture();
tileTextures.put(tex, new Texture(tex + ".png"));
}
}
}
}
public void renderTile (byte id, int x, int y, Shader shader, Matrix4f world, Camera camera) {
shader.bind();
if (tileTextures.containsKey(Tile.tiles[id].getTexture())) {
tileTextures.get(Tile.tiles[id].getTexture()).bind(0);
}
Matrix4f tilePos = new Matrix4f().translate(new Vector3f(x*2, y*2, 0));
Matrix4f target = new Matrix4f();
camera.getProjection().mul(world, target);
target.mul(tilePos);
shader.setUniform("sampler", 0);
shader.setUniform("projection", target);
tileModel.render();
}
}
The Tile class
public class Tile {
public static Tile tiles[] = new Tile[16];
public static final Tile testTile = new Tile((byte)0, "Test");
public static final Tile testTile2 = new Tile((byte)1, "Test2");
private byte id;
private String texture;
public Tile(byte id, String texture) {
this.id = id;
this.texture = texture;
if (tiles[id] != null) {
throw new IllegalStateException("Tiles at: [" + id + "] is already being used!");
}
tiles[id] = this;
}
public byte getId () {return id;}
public String getTexture () {return texture;}
}
The Model class
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
public class Model {
private int draw_count;
private int v_id;
private int t_id;
private int i_id;
public Model (float[] vertices, float[] tex_coords, int[] indices) {
draw_count = indices.length;
IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
buffer.put(indices);
buffer.flip();
v_id = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, v_id);
glBufferData(GL_ARRAY_BUFFER, createBuffer(vertices), GL_STATIC_DRAW);
t_id = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, t_id);
glBufferData(GL_ARRAY_BUFFER, createBuffer(tex_coords), GL_STATIC_DRAW);
i_id = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
public void render() {
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, v_id);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, t_id);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);
glDrawElements(GL_TRIANGLES, draw_count, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
private FloatBuffer createBuffer(float[] data) {
FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}
The Texture class
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.stb.STBImage.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import org.lwjgl.BufferUtils;
public class Texture {
private int id;
private int width;
private int heigth;
public Texture (String filename) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer heigth = BufferUtils.createIntBuffer(1);
IntBuffer comp = BufferUtils.createIntBuffer(1);
ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);
this.width = width.get();
this.heigth = heigth.get();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
public void bind (int sampler) {
if (sampler >= 0 && sampler <= 31) {
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(GL_TEXTURE_2D, sampler);
}
}
}
The Shader class
import static org.lwjgl.opengl.GL20.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.FloatBuffer;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
public class Shader {
private int program;
private int vs;
private int fs;
public Shader (String filename) {
program = glCreateProgram();
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, readFile(filename + ".vs"));
glCompileShader(vs);
if (glGetShaderi(vs, GL_COMPILE_STATUS) != 1) {
System.err.println(glGetShaderInfoLog(vs));
System.exit(1);
}
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, readFile(filename + ".fs"));
glCompileShader(fs);
if (glGetShaderi(fs, GL_COMPILE_STATUS) != 1) {
System.err.println(glGetShaderInfoLog(fs));
System.exit(1);
}
glAttachShader(program, vs);
glAttachShader(program, fs);
glBindAttribLocation(program, 0, "vertices");
glBindAttribLocation(program, 1, "textures");
glLinkProgram(program);
if (glGetProgrami(program, GL_LINK_STATUS) != 1) {
System.err.println(glGetProgramInfoLog(program));
System.exit(1);
}
glValidateProgram(program);
if (glGetProgrami(program, GL_VALIDATE_STATUS) != 1) {
System.err.println(glGetProgramInfoLog(program));
System.exit(1);
}
}
public void bind () {
glUseProgram(program);
}
private String readFile (String filename) {
StringBuilder string = new StringBuilder();
BufferedReader br;
try {
br = new BufferedReader(new FileReader(new File("./shaders/" + filename)));
String line;
while((line = br.readLine()) != null) {
string.append(line);
string.append("\n");
}
} catch (IOException e ) {e.printStackTrace();}
return string.toString();
}
public void setUniform (String name, int value) {
int location = glGetUniformLocation(program, name);
if (location != -1) {
glUniform1i(location, value);
}
}
public void setUniform (String name, Matrix4f value) {
int location = glGetUniformLocation(program, name);
FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
value.get(buffer);
if (location != -1) {
glUniformMatrix4fv(location, false, buffer);
}
}
}
The Fragment Shader
#version 120
uniform sampler2D sampler;
varying vec2 tex_coords;
void main () {
gl_FragColor = texture2D(sampler, tex_coords);
}
The Vertex Shader
#version 120
attribute vec3 vertices;
attribute vec2 textures;
varying vec2 tex_coords;
uniform mat4 projection;
void main() {
tex_coords = textures;
gl_Position = projection*vec4(vertices, 1);
}
So far I'm creating 16x16 tiles all with the same texture but it is supposed to change the tile at 0, 0 (top left corner) to have a different texture
There is a basic misunderstanding, about how texturing works in OpenGL.
You have to create a separate texture object for each texture by glGenTextures. (See also Java Code Examples for org.lwjgl.opengl.GL11.glTexImage2D()).
int textureObject = glGenTextures();
This texture object has to be bound before loading the texture and before rendering the mesh. The texture is bound to the active texture unit, which is set by glActiveTexture.
int textureUnitIndex = 0; // e.g
glActiveTexture(GL_TEXTURE0 + textureUnitIndex);
glBindTexture(GL_TEXTURE_2D, textureObject);
The texture unit is a binding point for the shader program. The texture sampler in the shader program has to be associated to the same binding point. This can be done by glUniform1i:
GLSL:
uniform sampler2D sampler;
Java:
int location = glGetUniformLocation(program, "sampler");
glUniform1i(location, textureUnitIndex);
Sidenote: since GLSL version 4.2 this can be done in the fragment shader by specifying binding points - See OpenGL Shading Language 4.20 Specification - 4.4.4 Opaque-Uniform Layout Qualifiers; page 60:
#version 420
layout (binding = 0) uniform sampler2D sampler;
In your code never a texture object is generated. So the default texture object 0 is used for all textures. This causes that you code doesn't work.
Change the class Texture, somehow as follows, to solve the issue:
public class Texture {
private int textureObject;
private int width;
private int heigth;
public Texture (String filename) {
IntBuffer width = BufferUtils.createIntBuffer(1);
IntBuffer heigth = BufferUtils.createIntBuffer(1);
IntBuffer comp = BufferUtils.createIntBuffer(1);
ByteBuffer data = stbi_load("./res/" + filename, width, heigth, comp, 4);
this.width = width.get();
this.heigth = heigth.get();
textureObject = glGenTextures(); // generate texture name
glBindTexture(GL_TEXTURE_2D, textureObject);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this.width, this.heigth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
public void bind (int sampler) {
if (sampler >= 0 && sampler <= 31) {
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(GL_TEXTURE_2D, textureObject); // bind texture object
}
}
}
When i try to enable projectionMatrix the rendered image disappear, i see only black screen. The console don't return any error.
Where is the problem?
Renderer
package ms.renderer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import org.joml.Matrix4f;
import ms.Display;
import ms.renderer.VertexArrayObject.Vertex;
import ms.shaders.ShaderProgram;
import ms.utils.FileLoader;
import ms.utils.TextureLoader;
public class Renderer {
VertexArrayObject vertices;
ShaderProgram shaders;
Display display;
Matrix4f projectionMatrix;
private float FOV = (float) Math.toRadians(60.0f);
private float Z_NEAR = 0.01f;
private float Z_FAR = 1000.0f;
public Renderer() {
display = new Display();
vertices = new VertexArrayObject();
}
public void init() throws Exception {
shaders = new ShaderProgram();
shaders.createVertexShader(FileLoader.loadResources("/ms/resources/shaders/vertexShader.vs"));
shaders.createFragmentShader(FileLoader.loadResources("/ms/resources/shaders/fragmentShader.fs"));
shaders.link();
float aspectRation = (float) display.getWidth() / display.getHeight();
projectionMatrix = new Matrix4f().perspective(FOV, aspectRation, Z_NEAR, Z_FAR);
shaders.createUniforms("projectionMatrix");
shaders.createUniforms("textureSampler");
}
public void render(Vertex vertex, TextureLoader texture) {
clear();
shaders.bindPorgram();
shaders.setUniform("projectionMatrix", projectionMatrix);
shaders.setUniform("textureSampler", 0);
glBindVertexArray(vertex.getVaoID());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.getId());
glDrawElements(GL_TRIANGLES, vertex.getVertexCount(), GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
shaders.unbindProgram();
}
public void clear() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
public void clenaUp() {
vertices.cleanVAO();
shaders.cleanUp();
}
}
VertexShader
#version 400 core
in vec3 position;
in vec2 textureCoords;
out vec2 outTextureCoords;
uniform mat4 projectionMatrix;
void main()
{
gl_Position = projectionMatrix * vec4(position, 1.0);
outTextureCoords = textureCoords;
}
MainClass - gameLoop() method
public void gameLoop() throws Exception {
isRunning = true;
display.libVersion();
renderer.init();
float[] vertices = {
-0.5f, 0.5f, -5.0f,
-0.5f, -0.5f, -5.0f,
0.5f, -0.5f, -5.0f,
0.5f, 0.5f, -5.0f
};
int[] indices = {
0,1,3,
3,1,2
};
float[] textCoords = {
0, 0,
0, 1,
1, 1,
1, 0
};
Vertex model = loader.loadVAO(vertices, textCoords, indices);
TextureLoader texture = new TextureLoader("image");
while (isRunning && !display.windowShouldClose()) {
update();
renderer.render(model, texture);
if(display.windowShouldClose()) {
renderer.clenaUp();
isRunning = false;
}
}
}
If i remove projectionMatrix the image render normally. The projectionMatrix uniform loading by convert the value in Floatbuffer.
ShaderProgram - setUniform() method
public void setUniform(String uniformName, Matrix4f value) {
FloatBuffer buffers = BufferUtils.createFloatBuffer(16);
value.get(buffers);
glUniformMatrix4fv(uniforms.get(uniformName), false, buffers);
}
I found the error:
Renderer
public void createProjectionMatrix() {
Matrix4f projectionMatrix = transformation.getProjectionMatrix(
FOV,
display.getWidth(), //Solve by indicate an int value
display.getHeight(), //Solve by indicate an int value
Z_NEAR,
Z_FAR);
shaders.setUniform("projectionMatrix", projectionMatrix);
}
but if i resize the window, the image move to the right corner, obviusly.
How can I resolve the getWidth() and getHeight() method?
Display
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import ms.input.KeyboardInput;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
public class Display {
GLFWKeyCallback keyCallback;
GLFWWindowSizeCallback windowSizeCallback;
private int width;
private int height;
private String title;
public long window;
public Display() {}
public Display(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
}
public void init() {
GLFWErrorCallback.createPrint(System.err).set();
if ( !glfwInit() )
throw new IllegalStateException("Unable to initialize GLFW");
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(width, height, title, NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() {
#Override
public void invoke(long window, int width, int height) {
Display.this.width = width;
Display.this.height = height;
}
});
glfwSetKeyCallback(window, keyCallback = new KeyboardInput());
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(
window,
(vidmode.width() - width) / 2,
(vidmode.height() - height) / 2
);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwShowWindow(window);
GL.createCapabilities();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
public void libVersion() {
System.out.println("LWJGL Version: " + Version.getVersion() + "!");
System.out.println("GLFW Version: " + glfwGetVersionString() + "!");
System.out.println("OpenGL Version: " + glGetString(GL_VERSION));
}
public boolean windowShouldClose() {
return glfwWindowShouldClose(window);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
I've tried to implement an reaction-diffusion model on GPU with JOGL and GLSL.
I use a ping pong technique with 2 FramebufferObject ( I've tried too with one FBO and 2 Colors attachements without success).
Shader seems correct since I've tried it in unity (with some adaptations) and it works.
After one week of trying many things, i'm completely out of idea to make this code works. I'm really not specialist of JOGL, so maybe i miss something evident.
The result is an image which becomes white with time : no reaction-diffusion behaviors and I don't understand why !
Thanks in advance for helps. Here is my code :
package gpu2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.nio.IntBuffer;
import java.nio.FloatBuffer;
import java.io.File;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.GLFBODrawable;
import com.jogamp.opengl.FBObject;
import com.jogamp.opengl.FBObject.Colorbuffer;
import com.jogamp.opengl.FBObject.ColorAttachment;
import com.jogamp.opengl.FBObject.TextureAttachment;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.glsl.ShaderUtil;
import com.jogamp.opengl.util.GLBuffers;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLOffscreenAutoDrawable;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
import com.jogamp.opengl.GLDrawableFactory;
import static com.jogamp.opengl.GL.*; // GL constants
import static com.jogamp.opengl.GL2.*; // GL2 constants
import gpu2.ModelParam;
/**
* JOGL 2.0 Program Template (GLCanvas)
* This is a "Component" which can be added into a top-level "Container".
* It also handles the OpenGL events to render graphics.
*/
#SuppressWarnings("serial")
public class JOGL2Setup_GLCanvas extends GLCanvas implements GLEventListener {
// Define constants for the top-level container
private static String TITLE = "JOGL 2.0 Setup (GLCanvas)"; // window's title
private static final int CANVAS_WIDTH = 512; // width of the drawable
private static final int CANVAS_HEIGHT = 512; // height of the drawable
private static final int FPS = 30; // animator's target frames per second
private final float[] canvasVertices = {
-1f, -1f, 0.0f,
-1f, 1f, 0.0f,
1f, -1f, 0.0f,
1f, 1f, 0.0f,
};
private final float[] canvasTexCoords = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
/** The entry main() method to setup the top-level container and animator */
public static void main(String[] args) {
// Run the GUI codes in the event-dispatching thread for thread safety
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Create the OpenGL rendering canvas
GLCanvas canvas = new JOGL2Setup_GLCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Create a animator that drives canvas' display() at the specified FPS.
final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
// Create the top-level container
final JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame
frame.getContentPane().add(canvas);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
// Use a dedicate thread to run the stop() to ensure that the
// animator stops before program exits.
new Thread() {
#Override
public void run() {
if (animator.isStarted()) animator.stop();
System.exit(0);
}
}.start();
}
});
frame.setTitle(TITLE);
frame.pack();
frame.setVisible(true);
animator.start(); // start the animation loop
}
});
}
// Setup OpenGL Graphics Renderer
private GLU glu; // for the GL Utility
private GL2 gl;
//OpenGl data
private int vboVertices;
private int vboTextCoord;
private Texture textureFile;
private FBObject fbo[];
private ShaderProgram shaderCompute;
private ShaderProgram shaderVisu;
private ShaderProgram shaderComputeInit;
private int currentSourceBuffer = 0;
private int currentDestBuffer = 1;
private int currentFrame = 0;
private int maxFrameCount = 5000000;
private float clearUniform = 0;
ModelParam params = new ModelParam();
public JOGL2Setup_GLCanvas() {
this.addGLEventListener(this);
}
#Override
public void init(GLAutoDrawable drawable) {
gl = drawable.getGL().getGL2(); // get the OpenGL graphics context
glu = new GLU(); // get GL Utilities
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
gl.glEnable(GL_TEXTURE_2D);
gl.glEnable( GL_COLOR_MATERIAL );
gl.glEnable( GL_FRAMEBUFFER );
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NEAREST); // best perspective correction
viewOrtho(gl);
gl.glViewport(0,0,CANVAS_WIDTH,CANVAS_HEIGHT);
int[] buffers = new int[2];
gl.glGenBuffers(2, buffers, 0);
vboVertices = buffers[0];
vboTextCoord = buffers[1];
gl.glBindBuffer(GL_ARRAY_BUFFER, vboVertices);
gl.glBufferData(GL_ARRAY_BUFFER, canvasVertices.length*(Float.SIZE/Byte.SIZE)*3, FloatBuffer.wrap(canvasVertices), GL_STATIC_DRAW);
gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord);
gl.glBufferData(GL_ARRAY_BUFFER, canvasTexCoords.length*(Float.SIZE/Byte.SIZE)*2, FloatBuffer.wrap(canvasTexCoords), GL_STATIC_DRAW);
gl.glBindBuffer( GL_ARRAY_BUFFER, 0 );
// ------------ create Texture Source------------------------
textureFile = initializeTexture();
if (textureFile==null) {
System.out.println("cannot load texture from disk");
}
// ------------ load shaders ------------------------
shaderCompute = loadShader(gl, "compute.vsh", "compute.fsh");
shaderComputeInit = loadShader(gl, "compute.vsh", "computeInit.fsh");
shaderVisu = loadShader(gl, "visu.vsh", "visu.fsh");
// ------------ create FBO ------------------------
initFBO();
}
/**
* Called back by the animator to perform rendering.
*/
#Override
public void display(GLAutoDrawable drawable) {
if (currentFrame < maxFrameCount) {
prepareNextStep();
renderToFBO();
currentFrame++;
}
renderFBOToScreen();
}
private void prepareNextStep() {
currentSourceBuffer = 1 - currentSourceBuffer;
currentDestBuffer = 1 - currentDestBuffer;
}
private void renderToFBO()
{
fbo[currentDestBuffer].bind(gl);
//gl.glClear(GL_COLOR_BUFFER_BIT);
viewOrtho(gl);
shaderCompute.useProgram(gl, true);
setShaderUniformFloat(gl, shaderCompute.program(), "diffuseU", 0.211f);
setShaderUniformFloat(gl, shaderCompute.program(), "diffuseV", 0.088f);
setShaderUniformFloat(gl, shaderCompute.program(), "feed", 0.007f);
setShaderUniformFloat(gl, shaderCompute.program(), "kill", 0.08f);
setShaderUniformFloat(gl, shaderCompute.program(), "Tech", 1f);
setShaderUniformFloat(gl, shaderCompute.program(), "currentFrame", currentFrame);
setShaderUniformFloat2(gl, shaderCompute.program(), "resolution", CANVAS_WIDTH, CANVAS_HEIGHT);
drawDataBuffer(shaderCompute, true);
shaderCompute.useProgram(gl, false);
fbo[currentDestBuffer].unbind(gl);
}
void drawDataBuffer(ShaderProgram currentShader, boolean sencondImage) {
// --- draw vbo
gl.glEnableClientState(GL_VERTEX_ARRAY);
gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//textcoords
gl.glBindBuffer(GL_ARRAY_BUFFER,vboTextCoord);
gl.glTexCoordPointer(2, GL_FLOAT, 0, 0);
//vertices
gl.glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
gl.glVertexPointer(3, GL_FLOAT, 0, 0);
//activate texture data from last fbo
final FBObject.Colorbuffer texSource = (FBObject.Colorbuffer) fbo[currentSourceBuffer].getColorbuffer(0);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, texSource.getName());
setShaderUniform1i(gl, currentShader.program(), "textureData", 0);
if (sencondImage) {
//activate texture with image from file
gl.glActiveTexture(GL_TEXTURE1);
gl.glBindTexture(GL_TEXTURE_2D, textureFile.getTextureObject());
textureFile.bind(gl);
setShaderUniform1i(gl, currentShader.program(), "textureImage", 1);
}
//draw buffer on screens
gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length / 3);
//disable texture image
if (sencondImage) {
gl.glActiveTexture(GL_TEXTURE1);
textureFile.disable(gl);
}
//disable texture data
gl.glActiveTexture(GL_TEXTURE0);
gl.glDisable(texSource.getName());
gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL_VERTEX_ARRAY);
}
public void renderFBOToScreen()
{
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
gl.glLoadIdentity(); // reset the model-view matrix
viewOrtho(gl);
gl.glEnable(GL_TEXTURE_2D);
final FBObject.Colorbuffer tex0 = (FBObject.Colorbuffer) fbo[currentDestBuffer].getColorbuffer(0);
gl.glActiveTexture(GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, tex0.getName());
//activate shader
shaderVisu.useProgram(gl, true);
// --- draw vbo
gl.glEnableClientState(GL_VERTEX_ARRAY);
gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//textcoords
gl.glBindBuffer(GL_ARRAY_BUFFER, vboTextCoord);
gl.glTexCoordPointer(2, GL_FLOAT, 0, 0);
//vertices
gl.glBindBuffer( GL_ARRAY_BUFFER, vboVertices );
gl.glVertexPointer(3, GL_FLOAT, 0, 0);
//draw buffer on screens
gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, canvasVertices.length / 3);
gl.glDisableClientState(GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL_VERTEX_ARRAY);
gl.glBindBuffer( GL_ARRAY_BUFFER, 0 );
//desactivate shader
shaderVisu.useProgram(gl, false);
}
private void initFBO()
{
try {
gl.glEnable(GL_TEXTURE_2D);
fbo = new FBObject[2];
//first fbo
fbo[currentSourceBuffer] = new FBObject(); // Create FrameBuffer
fbo[currentSourceBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0);
fbo[currentSourceBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call
fbo[currentSourceBuffer].bind(gl);
int tex = genTexture(gl);
gl.glBindTexture(GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null);
fbo[currentSourceBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
//gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
int DrawBuffers[] = {GL_COLOR_ATTACHMENT0};
gl.glDrawBuffers(1, DrawBuffers, 0); // "1" is the size of DrawBuffers
fbo[currentSourceBuffer].unbind(gl);
//second fbo
fbo[currentDestBuffer] = new FBObject(); // Create FrameBuffer
fbo[currentDestBuffer].init(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0);
fbo[currentDestBuffer].reset(gl, CANVAS_WIDTH, CANVAS_HEIGHT, 0); // int width, height - size of FBO, can be resized with the same call
fbo[currentDestBuffer].bind(gl);
tex = genTexture(gl);
gl.glBindTexture(GL_TEXTURE_2D, tex);
gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_RGBA, GL_FLOAT, null);
fbo[currentDestBuffer].attachTexture2D(gl, 0, GL_RGBA32F, GL_RGBA, GL_FLOAT, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
//ogl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
gl.glDrawBuffers(1, DrawBuffers, 1); // "1" is the size of DrawBuffers
fbo[currentDestBuffer].unbind(gl);
} catch (Exception e) {
System.out.println("Problem with fbo init " + e);
e.printStackTrace();
}
}
private Texture initializeTexture() {
Texture t = null;
try {
t = TextureIO.newTexture(new File("e:/shaders/wiki.jpg"), false);
t.setTexParameteri(gl, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
t.setTexParameteri(gl, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
t.setTexParameteri(gl, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
t.setTexParameteri(gl, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} catch (Exception e) {
System.out.println("Unable to read texture file: " + e);
e.printStackTrace();
}
return t;
}
private ShaderProgram loadShader(GL2 gl, String vertexShader, String fragmentShader)
{
ShaderCode vertShader = ShaderCode.create(gl, GL2.GL_VERTEX_SHADER, 1, getClass(), new String[]{"e:/shaders/"+vertexShader},false);
vertShader.compile(gl);
ShaderCode fragShader = ShaderCode.create(gl, GL2.GL_FRAGMENT_SHADER, 1, getClass(), new String[]{"e:/shaders/"+fragmentShader},false);
fragShader.compile(gl);
ShaderProgram newShader = new ShaderProgram();
newShader.init(gl);
newShader.add(vertShader);
newShader.add(fragShader);
newShader.link(gl, System.out);
vertShader.destroy(gl);
fragShader.destroy(gl);
return newShader;
}
public static void setShaderUniform1i(GL2 inGL,int inProgramID,String inName,int inValue) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform1i(tUniformLocation, inValue);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
public static void setShaderUniformFloat(GL2 inGL,int inProgramID,String inName,float inValue) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform1f(tUniformLocation, inValue);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
public static void setShaderUniformFloat2(GL2 inGL,int inProgramID,String inName,float inValue1 ,float inValue2) {
int tUniformLocation = inGL.glGetUniformLocation(inProgramID,inName);
if (tUniformLocation != -1) {
inGL.glUniform2f(tUniformLocation, inValue1, inValue2);
} else {
System.out.println("UNIFORM COULD NOT BE FOUND! NAME="+inName);
}
}
private void viewOrtho(GL2 gl) // Set Up An Ortho View
{
gl.glMatrixMode(GL_PROJECTION); // Select Projection
gl.glPushMatrix(); // Push The Matrix
gl.glLoadIdentity(); // Reset The Matrix
gl.glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
gl.glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix
gl.glPushMatrix(); // Push The Matrix
gl.glLoadIdentity(); // Reset The Matrix
}
private int genTexture(GL2 gl) {
final int[] tmp = new int[1];
gl.glGenTextures(1, tmp, 0);
return tmp[0];
}
/**
* Called back before the OpenGL context is destroyed. Release resource such as buffers.
*/
#Override
public void dispose(GLAutoDrawable drawable) { }
}
And the corresponding GLSL Shader :
#version 120
uniform sampler2D textureData;
uniform sampler2D textureImage;
uniform vec2 resolution;
uniform float diffuseU;
uniform float diffuseV;
uniform float feed;
uniform float kill;
uniform float Tech = 1.0;
uniform float currentFrame = 0.0;
void main() {
//coords
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec2 pixel = 1./resolution;
//get data from texture
vec4 imgSource = texture2D(textureImage, gl_TexCoord[0].st);
vec2 oldUV = texture2D(textureData, gl_TexCoord[0].st).rg;
if(currentFrame<10){
if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.2f)
oldUV = vec2(0.0,0.2);
else if (distance(position,vec2(0.5,0.5 - currentFrame * 0.01f)) < 0.3f)
oldUV = vec2(0.5,0.1);
else
oldUV = vec2(0.1,0.0);
gl_FragColor = vec4(oldUV.rg, 0.0, 1.0);
return;
}
//get neightboors
vec2 dataUp = texture2D(textureData, position + pixel * vec2(0., 1.)).rg;
vec2 dataDown = texture2D(textureData, position + pixel * vec2(0., -1.)).rg;
vec2 dataLeft = texture2D(textureData, position + pixel * vec2(-1., 0.)).rg;
vec2 dataRight = texture2D(textureData, position + pixel * vec2(1., 0.)).rg;
//adapt parameters
vec2 imgParam = imgSource.rg;
float dU = diffuseU ;//+ 0.01 * (imgParam - 0.5);
float dV = diffuseV ;//+ 0.01 * (imgParam - 0.5);
float F = feed ;//+ 0.01 * (imgParam - 0.5);
float K = kill ;//+ 0.01 * (imgParam - 0.5);
//compute new values
vec2 laplace = (dataUp+dataDown+dataLeft+dataRight) - 4.0 * oldUV;
float uvv = oldUV.r * oldUV.g * oldUV.g;
// calculate delta quantities
float du = dU * laplace.r - uvv + F*(1.0 - oldUV.r);
float dv = dV * laplace.g + uvv - (F+K)*oldUV.g;
vec2 newUV = oldUV + vec2(du, dv)* Tech;
gl_FragColor = vec4(newUV.rg, 0.0, 1.0);
}
Few considerations:
avoid deprecated OpenGL (and GLU), use GL4 (or GL3)
unless you need awt/swt/swing, prefer newt, more here
prefer Animator instead of FPSAnimator, more here
prefer direct buffers instead of arrays, since otherwise jogl has to create them underneath and you can't keep trace (= deallocate when done) of those native allocations
GL4 will allow you also to avoid all those uniform overhead (and also potential bugs) you have to deal with (especially during runtime), thanks to explicit locations
prefer direct buffer management instead of FBObject for the moment unless you really know what FBObject is doing. Once you get it working, you can move on using that class. This may be (one of the) cause your code is not working, because something is not getting setup up as you need. Moreover, the lines of codes needed to replace FBObject are essentially the same
(if you can't use explicit location for any reason) prefer some literal way to define the texture uniform location, it is usually another tricky part causing bugs, something like this
prefer also a sampler for the textures, gives you more flexibility
don't wait one week next time, let us know earlier! :) Frustation can be a nasty thing that put you down easily. Together we can help you getting it working ;)
so I've been following a fair amount of tutorials on the internet and I tried to create my own graphics engine with OpenGL. The problem is that I can't make the texture work. I can render a square on the screen and change the color but I can't show a texture.
This is the Main Method:
public class Main implements Runnable{
public int HEIGHT = 400;
public int WIDTH = 400;
private boolean running;
private Thread thread;
private long window;
Level level;
public Main(){
}
public void start(){
running = true;
thread = new Thread(this, "Game");
thread.start();
}
public void stop(){
try {
thread.join();
running = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void init(){
if(glfwInit() != GL_TRUE){
System.err.println("Couldn't load the window");
return;
}
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Game!!", NULL, NULL);
if(window == NULL){
System.err.println("Couldn't create the window");
return;
}
ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowPos(window, (GLFWvidmode.width(vidmode) - WIDTH) / 2, (GLFWvidmode.height(vidmode) - HEIGHT) / 2);
glfwMakeContextCurrent(window);
glfwShowWindow(window);
GLContext.createFromCurrent();
Input input = new Input();
glfwSetKeyCallback(window, input);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
System.out.println("OpenGL: " + glGetString(GL_VERSION));
Shader.loadAll();
Matrix4f pr_matrix = Matrix4f.orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
Shader.BG.setUniformMat4f("pr_matrix", pr_matrix);
Shader.BG.setUniform1i("tex", 1);
level = new Level();
}
public void run() {
init();
long lastTime = System.nanoTime();
double delta = 0.0;
double ns = 1000000000.0 / 60.0;
long timer = System.currentTimeMillis();
int updates = 0;
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1.0) {
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " ups, " + frames + " fps");
updates = 0;
frames = 0;
}
if (glfwWindowShouldClose(window) == GL_TRUE)
running = false;
}
}
private void update(){
glfwPollEvents();
if(Input.isKeyDown(GLFW_KEY_ESCAPE)){
running = false;
}
}
private void render(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int error = glGetError();
if (error != GL_NO_ERROR)
System.out.println(error);
glfwSwapBuffers(window);
level.render();
}
public static void main(String arg[]){
new Main().start();
}
}
This is the Level Method:
public class Level {
private VertexArray background;
private Texture bgTexture;
public Level() {
float[] vertices = new float[] {
-0.5f, 0.5f, 0f,
-0.5f, -0.5f, 0f,
0.5f, -0.5f, 0f,
0.5f, 0.5f, 0f
};
byte[] indices = new byte[] { 0, 1, 3, 3, 1, 2 };
float[] tcs = new float[] {
0f, 0f,
0, 1.0f,
1.0f, 1.0f,
1.0f, 0
};
background = new VertexArray(vertices, indices, tcs);
bgTexture = new Texture("res/bird.png");
}
public void render() {
Shader.BG.enable();
bgTexture.bind();
background.bind();
background.draw();
bgTexture.unbind();
Shader.BG.disable();
}
Here the Texture Class:
public class Texture {
private int width, height;
private int texture;
public Texture(String path) {
texture = load(path);
}
private int load(String path) {
int[] pixels = null;
try {
BufferedImage image = ImageIO.read(new FileInputStream(path));
width = image.getWidth();
height = image.getHeight();
pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int[] data = new int[width * height];
for (int i = 0; i < width * height; i++) {
int a = (pixels[i] & 0xff000000) >> 24;
int r = (pixels[i] & 0xff0000) >> 16;
int g = (pixels[i] & 0xff00) >> 8;
int b = (pixels[i] & 0xff);
data[i] = a << 24 | b << 16 | g << 8 | r;
}
int result = glGenTextures();
glBindTexture(GL_TEXTURE_2D, result);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, BufferUtils.createIntBuffer(data));
glBindTexture(GL_TEXTURE_2D, 0);
return result;
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, texture);
}
public void unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
}
Here the Vertex Class:
public class VertexArray {
private int vao, vbo, ibo, tbo;
private int count;
public VertexArray(int count) {
this.count = count;
vao = glGenVertexArrays();
}
public VertexArray(float[] vertices, byte[] indices, float[] textureCoordinates) {
count = indices.length;
vao = glGenVertexArrays();
glBindVertexArray(vao);
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(vertices), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.VERTEX_ATTRIB, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.VERTEX_ATTRIB);
tbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(textureCoordinates), GL_STATIC_DRAW);
glVertexAttribPointer(Shader.TCOORD_ATTRIB, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(Shader.TCOORD_ATTRIB);
ibo = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createByteBuffer(indices), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void bind() {
glBindVertexArray(vao);
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
}
public void unbind() {
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
if (ibo > 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
public void draw() {
if (ibo > 0)
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_BYTE, 0);
else
glDrawArrays(GL_TRIANGLES, 0, count);
}
public void render() {
bind();
draw();
}
}
And here the Shaders:
Vertex:
#version 400 core
in vec4 position;
layout (location = 1) in vec2 tc;
uniform mat4 pr_matrix;
out vec2 tc_vr;
void main(void)
{
gl_Position = pr_matrix * position;
tc_vr = tc;
}
Fragment:
#version 400 core
out vec4 color;
in vec2 tc_vr;
uniform sampler2D tex;
void main(void)
{
color = texture(tex, tc_vr);
}
Thanks a lot for the help!