Hot questions for Using Lightweight Java Game Library in render

Question:

I am currently following ThinMatrix's OpenGL tutorial on rendering with VAOs and VBOS. I copy the code almost exactly (the only difference being I make a factory class static instead of just having it normally). The only technical difference I can see between my version of the program and his is that I am using lwjgl 3 instead of lwjgl 2.

Here is my source code:

/*************
    MAIN
*************/
import Render.ModelLoader;
import Render.Render;
import Render.RawModel;
import org.lwjgl.Version;
import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;

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

public class Main {

    private static long window;
    private static ModelLoader modelLoader;
    private static Render renderer;


    private static final int WIDTH = 1280;
    private static final int HEIGHT = 720;

    public static void main(String[] args) {

        float[] vertices = {
                //Bottom left triangle
                -.5f,.5f,0f,
                -.5f,-.5f,0f,
                .5f,-.5f,0f,
                //Top right triangle
                .5f,-.5f,0f,
                .5f,.5f,0f,
                -.5f,.5f,0f
        };

        RawModel model = modelLoader.loadToVAO(vertices);

        initApp();

        //Main Loop
        while (!glfwWindowShouldClose(window)){
            glfwPollEvents();
            renderer.prepare();
            renderer.render(model);
            glfwSwapBuffers(window);
        }

        cleanUp();
    }

    public static void initApp(){
        System.out.println("LWJGL " + Version.getVersion());
        //Set the error callback routine to use System.err
        GLFWErrorCallback.createPrint(System.err).set();

        //Init GLFW
        if (!glfwInit()){
            throw new IllegalStateException("Could not initialise GLFW.");
        }

        //Create the window
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_RESIZABLE,GLFW_FALSE);
        window = glfwCreateWindow(WIDTH, HEIGHT, "My Display", NULL, NULL);
        if (window == NULL){
            throw new IllegalStateException("Could not create window");
        }

        //Center the window
        GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidMode.width()-WIDTH)/2, (vidMode.height()-HEIGHT)/2);

        //Link window's context to current thread
        glfwMakeContextCurrent(window);
        //VSync
        glfwSwapInterval(1);
        glfwShowWindow(window);

        GL.createCapabilities();
        System.out.println("OpenGL " + glGetString(GL_VERSION));
    }

    public static void cleanUp(){
        modelLoader.cleanUp();
        Callbacks.glfwFreeCallbacks(window); //Release callbacks
        glfwDestroyWindow(window); //Destroy the window
        glfwTerminate(); //Terminate GLFW
        glfwSetErrorCallback(null).set();
    }

}
/*************
   RAWMODEL
*************/
package Render;

public class RawModel {
    private int vaoID;
    private int vertexCount;

    public RawModel(int vaoID,int vertexCount){
        this.vaoID = vaoID;
        this.vertexCount = vertexCount;
    }

    public int getVaoID() {
        return vaoID;
    }

    public int getVertexCount() {
        return vertexCount;
    }
}
/*************
  MODELLOADER
*************/
package Render;

import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;

public class ModelLoader {

    private static List<Integer> vaos = new ArrayList<>();
    private static List<Integer> vbos = new ArrayList<>();

    public static RawModel loadToVAO(float[] positions){
        int vaoID = createVAO();
        vaos.add(vaoID);
        storeDataInAttribList(0,positions);
        unbindVAO();
        return new RawModel(vaoID, positions.length/3);
    }

    private static int createVAO(){
        int vaoID = glGenVertexArrays();
        glBindVertexArray(vaoID);
        return vaoID;
    }

    private static void storeDataInAttribList(int attribNum, float[] data){
        int vboID = glGenBuffers();
        vbos.add(vboID);
        glBindBuffer(GL_ARRAY_BUFFER,vboID);
        FloatBuffer buffer = storeDataInFB(data);
        glBufferData(GL_ARRAY_BUFFER,buffer,GL_STATIC_DRAW);
        glVertexAttribPointer(attribNum,3,GL_FLOAT,false,0,0);
        glBindBuffer(GL_ARRAY_BUFFER,0);
    }

    private static FloatBuffer storeDataInFB(float[] data){
        FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
        buffer.put(data);
        buffer.flip();
        return buffer;
    }

    private static void unbindVAO(){
        glBindVertexArray(0);
    }

    public static void cleanUp(){
        for (int vao:vaos) {
            glDeleteVertexArrays(vao);
        }
        for (int vbo:vbos) {
            glDeleteBuffers(vbo);
        }
    }
}
/*************
    RENDER
*************/
package Render;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;

public class Render {

    public static void prepare(){
        glClearColor(0.0f,0.4f,0.6f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    }

    public static void render(RawModel model){
        glEnableClientState(GL_VERTEX_ARRAY);
        glBindVertexArray(model.getVaoID());
        glEnableVertexAttribArray(0);
        glDrawArrays(GL_TRIANGLES,0,model.getVertexCount());
        glDisableVertexAttribArray(0);
        glBindVertexArray(0);
        glDisableClientState(GL_VERTEX_ARRAY);
    }
}

The problem I'm having is that whenever I try to run the project it just crashes with this error message:

Connected to the target VM, address: '127.0.0.1:49390', transport: 'socket'

 A fatal error has been detected by the Java Runtime Environment:

  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffffa09862d, pid=12556, tid=0x00000000000020ac

 JRE version: Java(TM) SE Runtime Environment (8.0_121-b13) (build 1.8.0_121-b13)
 Java VM: Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode windows-amd64 compressed oops)
 Problematic frame:
 C  [lwjgl_opengl.dll+0x862d]

 Failed to write core dump. Minidumps are not enabled by default on client versions of Windows

 An error report file with more information is saved as:
 C:\Users\TokenGuard\IdeaProjects\ModernOpenGLTutorial\hs_err_pid12556.log

 If you would like to submit a bug report, please visit:
   http://bugreport.java.com/bugreport/crash.jsp
 The crash happened outside the Java Virtual Machine in native code.
 See problematic frame for where to report the bug.

Disconnected from the target VM, address: '127.0.0.1:49390', transport: 'socket'

Process finished with exit code 1

Upon looking around I've found this stackoverflow post: Java OpenGL EXCEPTION_ACCESS_VIOLATION on glDrawArrays only on NVIDIA, which seems to have the same problem and the OP of that question actually posted a solution.

I am using an AMD graphics card, but I still gave it a try to see if it fixed my problem, however it does nothing, as it still comes up with the same error message.

Putting some breakpoints in I have found that the problem lies in the createVAO() method, more specifically the call to glGenVertexArrays() fails for some reason. I have tried explicitly telling glfw to use OpenGL 3.0 but it still doesn't help.

At this point I am completely out of ideas. Any guidance on what I should do?


Answer:

The problem is this:

RawModel model = modelLoader.loadToVAO(vertices);
initApp();

You need to flip it around:

initApp();
RawModel model = modelLoader.loadToVAO(vertices)

The problem with that is that when you call modelLoader.loadToVAO(vertices) it calls glGenVertexArrays() (as you've observed). At this point you however don't have a current context set. Which you do in initApp() with glfwMakeContextCurrent().

You must have a current context set before calling any OpenGL functions.

Question:


Answer:

LWJGL3 has a built in binding to STB which can load TTF font files, there are examples in the LWJGL3 repo which show you how to render text using it.

Further details and examples for the same can be found here.

Question:

I'm having some trouble with rendering Master Cheif in Java using LWJGL and GLSL shaders where the is some flickering, dissapearing of polygons and strange colouring. And for the life of me I can't figure out why.

What it should look like:

What it does look like when I move the camera a little:

Shaders: https://github.com/marko5049/LucidEngine/tree/master/src/res/shaders

MainShaders: LightingMain ShdaowMapping Smapler Filters

All the code: https://github.com/marko5049/LucidEngine

StaticMesh:

public void addVertices(Vertex[] vertices, int[] indices, boolean calcNorm) {
    if(calcNorm) {
        vertices = calcNormals(vertices, indices);
    }

    handler.setSize(indices.length);
    EngineCore.polycount += indices.length/3;

    glBindBuffer(GL_ARRAY_BUFFER, handler.getVbo());
    glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handler.getIbo());
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);
}

private void finalDraw(int typeIndex) {
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);

    glBindBuffer(GL_ARRAY_BUFFER, handler.getVbo());
    glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
    glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
    glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);
    glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 32);
    glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 44);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handler.getIbo());
    glDrawElements(typeIndex, handler.getSize(), GL_UNSIGNED_INT, 0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
}

Answer:

What you describe and is shown in your sample images are typical symptoms of a problem that is often called "depth fighting" or "z-fighting". This is caused by precision limitations of the depth buffer.

The most common scenario where this becomes an issue is if the range covered by the depth buffer is large, and the scene contains polygons with very similar depth values.

For example, picture a polygon A that is slightly in front of polygon B in world space. Pixels from polygon A and polygon B can end up with the same depth value after all transformations are applied, and the resulting depth is rounded to the available depth buffer precision. Depending on the order of drawing, the pixel from polygon A or polygon B will be visible in this case. The typical result is that a mix of pixels from polygon A and polygon B will show up where polygon A should cover polygon B.

There are a number of ways to address this:

  • Reduce the depth range. In a standard perspective projection, this is controlled by the near and far plane distances, where the relative far/near value is the critical quantity. Which values cause depth fighting depends heavily on the scene and depth buffer precision. The safest bet is to keep the relative value as small as possible. In most cases, values up to about 100 tend to rarely cause problems, and values of 1000 and higher can start causing issues.
  • Increase the depth buffer precision. The most common depth buffer sizes are 16-bit and 24-bit, and many GPUs support both. If things get problematic, choose at least 24-bit. Depending on hardware and OpenGL version, higher resolution depth buffers might be available.
  • Avoid rendering polygons with almost identical depth. Either remove hidden polygons that are very close in depth to visible polygons, or at least move them farther apart.

If the above is not enough, the solutions get more complex. There are scenarios where there is really geometry with a large range of depth that must be visible at the same time. Methods for dealing with these (relatively rare) cases include logarithmic depth buffers, and multi-pass rendering approaches.

Note that my answer is purely about the case where the original polygons in world space have different depth. If polygons with exactly the same depth (i.e. coplanar polygons) are drawn, depth fighting will almost always be the result, and this situation needs to be avoided with other methods. Since this doesn't look like the scenario here, I intentionally did not cover it.

Question:

Is there any way I can render sprites, text, etc., but have part of it not rendered so that it is all contained in a rectangle? This would be applied to scroll views and textfields for example.


Answer:

If it's a screen aligned rectangle, then using a scissor rect is the best solution. See: https://www.khronos.org/opengles/sdk/docs/man/xhtml/glScissor.xml

Question:

I am writing an OpenGL application using LWJGL 3. I am able to render solid colours just fine, but as soon as I try to introduce a texture sampler all I see is black.

Specifically, the value returned by texture(texUnit, DataIn.texCoord) in the fragment shader is always vec4(0, 0, 0, 1).

I have even tried manually populating the buffer passed to glTexImage2D with all 255s, but I get the same result. I'm totally stumped at this point!

Initialisation:

private void initGL() {

    // Enable depth buffer
    GL11.glEnable(GL11.GL_DEPTH_TEST);

    // Set background colour
    GL11.glClearColor(0.2f, 0.2f, 0.4f, 0.0f);

    // Set viewport to the whole window
    GL11.glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    // Enable alpha blending (transparency)
    GL11.glEnable(GL11.GL_BLEND);
    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

    // Enable back-face culling
    GL11.glEnable(GL11.GL_CULL_FACE);
    GL11.glCullFace(GL11.GL_BACK);

    // Use linear filtering for texture scaling
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);

    // Clamp texture co-ordinates between 0 and 1
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,
            GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

    int errorCode = GL11.glGetError();
    if (errorCode != GL11.GL_NO_ERROR) {
        throw new RuntimeException(
                "OpenGL error " + String.valueOf(errorCode)
                + " during initialisation");
    }
}

Texture loading:

    String filename = "terrain.png";

    // Read image into a ByteBuffer
    IntBuffer w = BufferUtils.createIntBuffer(1);
    IntBuffer h = BufferUtils.createIntBuffer(1);
    IntBuffer comp = BufferUtils.createIntBuffer(1);
    ByteBuffer texelData = 
            STBImage.stbi_load(GFX_DIR + filename, w, h, comp, 4);
    if (texelData == null) {
        throw new RuntimeException("Error loading " + filename + ": " +
                STBImage.stbi_failure_reason());
    }
    int width = w.get();
    int height = h.get();

    // Generate texture ID
    terrainTexId = GL11.glGenTextures();
    // Pass our texture to the shader
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, terrainTexId);
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height,
            0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, texelData);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); // Deselect

    int errorCode = GL11.glGetError();
    if (errorCode != GL11.GL_NO_ERROR) {
        throw new RuntimeException(
                "OpenGL error " + String.valueOf(errorCode)
                + " loading texture: " + filename);
    }

Rendering:

    // Clear the screen and depth buffer
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

    // Use our shader program
    GL20.glUseProgram(Shaders.programId);

    // Set the projection matrix
    FloatBuffer fb = BufferUtils.createFloatBuffer(16);
    projection.setPerspective(
            camera.getFovY(),
            window.getAspectRatio(), 
            Camera.Z_NEAR,
            Camera.Z_FAR);
    GL20.glUniformMatrix4fv(
            Shaders.projectionLoc, false, projection.get(fb));

    // Set the model-view matrix.
    modelView.setLookAt(
            camera.getPos(),
            camera.getTarget(),
            camera.getUpVector());
    GL20.glUniformMatrix4fv(Shaders.modelViewLoc, false, modelView.get(fb));

    // Bind our texture to texture unit 0
    GL13.glActiveTexture(GL13.GL_TEXTURE0 + 0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, terrainTexId);
    // Tell the shader to sample from texture unit 0.
    // This is the default anyway.
    GL20.glUniform1i(Shaders.texUnitLoc, 0);

    // Pass the lighting information to the shader
    fb = BufferUtils.createFloatBuffer(3);
    GL20.glUniform3fv(Shaders.lightAmbientColourLoc,
            lighting.getAmbientColour().get(fb));
    GL20.glUniform1f(Shaders.lightAmbientIntensityLoc,
            lighting.getAmbientIntensity());
    GL20.glUniform3fv(Shaders.lightDiffuseColourLoc,
            lighting.getDiffuseColour().get(fb));
    GL20.glUniform3fv(Shaders.lightDiffuseAngleLoc,
            lighting.getDiffuseVector().get(fb));
    GL20.glUniform1f(Shaders.lightDiffuseIntensityLoc,
            lighting.getDiffuseIntensity());

    // Bind to the VAO that has all the information about the vertices
    GL30.glBindVertexArray(terrainSection.getVaoId());
    GL20.glEnableVertexAttribArray(Shaders.PARAM_VERTEX);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_VERTEX_NORMAL);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_MATERIAL_AMBIENT_COLOUR);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_MATERIAL_DIFFUSE_COLOUR);
    GL20.glEnableVertexAttribArray(Shaders.PARAM_TEXTURE_COORDS);

    // Draw the vertices
    GL11.glDrawArrays(
            GL11.GL_TRIANGLES, 0, TerrainSection.NUM_VERTICES_FOR_BUFFERS);

    // Put everything back to default (deselect)
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_VERTEX);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_VERTEX_NORMAL);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_MATERIAL_AMBIENT_COLOUR);
    GL20.glDisableVertexAttribArray(Shaders.PARAM_MATERIAL_DIFFUSE_COLOUR);
    GL30.glBindVertexArray(0);
    GL20.glUseProgram(0);

Vertex Shader:

#version 330

uniform mat4 projection;
uniform mat4 modelView;
uniform vec3 lightAmbientColour;
uniform float lightAmbientIntensity;
uniform vec3 lightDiffuseAngle;
uniform vec3 lightDiffuseColour;
uniform float lightDiffuseIntensity;

layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec3 materialAmbientColour;
layout(location = 3) in vec3 materialDiffuseColour;
layout(location = 4) in vec2 texCoord;

out Data {
    vec4 colour;
    vec2 texCoord;
} DataOut;

void main(void) {
    gl_Position = projection * modelView * vec4(vertex, 1.0);

    vec3 ambientComponent = lightAmbientIntensity * 
            (lightAmbientColour * materialAmbientColour);
    ambientComponent = clamp(ambientComponent, 0.0, 1.0);

    // The dot product gives us a measure of how "aligned" 2 vectors are,
    // between 0 and 1. If the light direction and the vertex normal are
    // well-aligned, the vertex should appear more brightly-lit.
    float dotProduct = dot(lightDiffuseAngle, vertexNormal);
    if (dotProduct < 0){
        dotProduct = 0;
    }
    vec3 diffuseComponent = lightDiffuseIntensity * dotProduct * 
            (lightDiffuseColour * materialDiffuseColour);
    diffuseComponent = clamp(diffuseComponent, 0.0, 1.0);

    vec3 colourResult = max(diffuseComponent, ambientComponent);
    DataOut.colour = vec4(colourResult, 1.0);
    DataOut.texCoord = texCoord;
}

Fragment Shader:

#version 330

uniform sampler2D texUnit;

in Data {
    vec4 colour;
    vec2 texCoord;
} DataIn;

out vec4 fragColour;

void main() {

    if (DataIn.colour.w == 0.0){
        // Discard transparent fragments, so they don't affect the depth buffer
        discard;
    }

    vec4 texColour = texture(texUnit, DataIn.texCoord);
    fragColour = DataIn.colour * texColour;
}

Answer:

You should:

  • avoid blending for the moment
  • move glTexParameteri into the texture loading/initialization, since it is part of the texture. Or use a sampler
  • call glActiveTexture before glBindTexture in the texture loading
  • check Shaders.texUnitLoc != -1
  • in the rendering avoid either:
    • binding/unbinding the vao and add glVertexAttribPointer
    • calling glEnableVertexAttribArray and glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); since those are part of the vao
  • GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); when the vao is bound, will result into an ebo/ibo unbind in the bound vao
  • if you don't use any indices (glDrawArrays), you don't have to unbind any ebo/ibo
  • since you call all those enableVertexAttribArray you should also call glDisableVertexAttribArray(Shaders.PARAM_TEXTURE_COORDS);
  • define in your shader the same semantic, such as:

    • #define VERTEX 0
    • #define VERTEX_NORMAL 1
    • #define MATERIAL_AMBIENT_COLOUR 2
    • #define MATERIAL_DIFFUSE_COLOUR 3
    • #define TEXTURE_COORDS 4

    and assign them accordingly to the various locations

  • check texture coordinates
  • avoid the discard for the moment
  • write the pure color fragColour = texColour for the moment

Question:

I am in the process of migrating a 2D game from legacy -> modern OpenGL. For me, this means using shaders and vertex arrays instead of glProjection, glOrtho and glBegin / glEnd.

I've stripped the relevant code down to a very basic example. The camera is at (0, 0, -1) looking at (0, 0, 0), and I am trying to draw a triangle with points:

(0, 0, 0)
      X
      | '
      |   '
      |     '
      X-------X
(0, 1, 0)   (1, 1, 0)

Even with a very simple shader that renders all fragments white, I do not see this triangle, just the flashing background colour.

Code

package client.render.opengl;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

import client.res.gfx.ScreenShader;

public class RenderingTest {

    private static final int NUM_VERTICES = 3;

    private static long window;
    private static int shaderProgram;
    private static int vao;
    private static int uniformLoc;
    private static Matrix4f viewProjMatrix = new Matrix4f();
    private static FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);

    public static void main(String[] args) throws IOException {

        init();

        while (!GLFW.glfwWindowShouldClose(window)) {
            GLFW.glfwPollEvents();
            render();
            GLFW.glfwSwapBuffers(window);
        }
    }

    private static void init() throws IOException {

        // Setup an error callback
        GLFW.glfwSetErrorCallback(
                GLFWErrorCallback.createPrint(System.err)
        );

        // Initialise GLFW
        if (!GLFW.glfwInit()) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        // Create window
        window = GLFW.glfwCreateWindow(800, 600, "test", 0, 0);
        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        GLFW.glfwShowWindow(window);

        // Load shader
        // Assume this code is good for now, it's too long to post here
        ScreenShader.initialise();
        shaderProgram = ScreenShader.shader.getProgram();
        uniformLoc = ScreenShader.shader.getUniformLoc(ScreenShader.UNIFORM_VIEW_PROJ_MATRIX);

        // Define our vertices
        ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(NUM_VERTICES * 2 * Float.BYTES);
        vertexBuffer.putFloat(0).putFloat(0); // Vertex 1
        vertexBuffer.putFloat(0).putFloat(1); // Vertex 2
        vertexBuffer.putFloat(1).putFloat(1); // Vertex 3
        vertexBuffer.flip();

        // Create VAO
        vao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vao);

        // Create VBO and fill it with vertex positions
        int vboIdPositions = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboIdPositions);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBuffer, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 0, 0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Deselect

        // Unbind the VAO
        GL30.glBindVertexArray(0);
    }

    public static void render() {

        // Render a random background to prove the loop is working
        GL11.glClearColor(
                (float) (Math.random() * 0.2f),
                (float) (Math.random() * 0.2f),
                (float) (Math.random() * 0.2f),
                1.0f);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

        // Use shader
        GL20.glUseProgram(shaderProgram);

        // Get camera position
        float cameraX = 0;
        float cameraY = 0;

        // Set view and projection
        viewProjMatrix
                .setOrtho(
                        0,
                        800,
                        600,
                        0,
                        0.01f,
                        10
                ).lookAt(
                        cameraX, cameraY, -1,    // Camera position
                        cameraX, cameraY, 0,     // Camera "look" vector
                        0, 1, 0                  // Camera "up" vector
                );

        // Pass this matrix to our shader
        GL20.glUniformMatrix4fv(uniformLoc, false, viewProjMatrix.get(fb16));

        // Bind our vertex array
        GL30.glBindVertexArray(vao);

        // Enable vertex attributes
        GL20.glEnableVertexAttribArray(0);

        // Draw the vertices
        GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, NUM_VERTICES);

        // Disable vertex attributes
        GL20.glDisableVertexAttribArray(0);

        // Unbind vertex array
        GL30.glBindVertexArray(0);

        // Release shader
        GL20.glUseProgram(0);
    }

}

Vertex Shader

#version 330

uniform mat4 view_proj_matrix;

layout(location = 0) in vec2 in_vertex;

void main(void) {
    gl_Position = view_proj_matrix * vec4(in_vertex, 0, 1);
}

Fragment Shader

#version 330

out vec4 frag_colour;

void main(void) {
    frag_colour = vec4(1, 1, 1, 1);
}

I don't know how to progress since I can't even get this toy example to work. Can anyone see what I'm doing wrong, or point me to a working example that uses JOML with LWJGL2 and shaders?


Answer:

With your view and projection matrix, the triangle has a size of 1 pixel and is out of the screen at the left.


If your triangle has the coordinates (0, 0, 0), (0, 1, 0), (1, 1, 0), your window has a size of (800, 600) and you set up an orthographic projection linke this:

viewProjMatrix.setOrtho(0, 800, 600, 0, 0.01f, 10)

the the triangle has a size of 1 pixel on the screen.

You have to change the orthographic projection:

float aspect = 800.0f/600.0f;
viewProjMatrix.setOrtho(-aspect, aspect, 1, -1, 0.01f, 10)

Note, the projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. At Orthographic Projection the coordinates in the view space are linearly mapped to clip space coordinates.


Made it 100x bigger, still no sign of it!

If you just scale the triangle triangle to (0, 0, 0), (0, 100, 0), (100, 100, 0), you won't see the triangle either, because of the view matrix:

lookAt(0, 0, -1, 0, 0, 0, 0, 1, 0 );

With this view matrix the x-axis is inverted in a Right-handed coordinate system. The view coordinates system describes the direction and position from which the scene is looked at. The view matrix transforms from the world space to the view (eye) space. In view space, the X-axis points to the left, the Y-axis up and the Z-axis out of the view (Note in a right hand system the Z-Axis is the cross product of the X-Axis and the Y-Axis).

Your view is defined as follows

position = (0, 0, -1)
center   = (0, 0, 0)
up       = (0, 1, 0)

the y-axis and z-axis are so:

y-axis = up = (0, 1, 0)
z-axis = position - center = (0, 0, -1)

the x-axis is the cross product of the y-axis and the z-axis:

x-axis = cross(y-axis, z-axis) = (-1, 0, 0)

This means, that you look at the back of the triangle. This causes that the triangle is "flipped" out of the viewport. It is drawn at the left out of the screen, so you can't see it:

        (0, 0)
              X---------------------------x
            / |                           |
          /   |                           |
        X-----X                           |
(-100, 100)   |         viewport          |
              |                           |
              |                           |
              |                           |
              x---------------------------x 
                                            (800, 600)

Invert the line of sight to solve the issue:

lookAt(0, 0, 1, 0, 0, 0, 0, 1, 0 );

Question:

I am trying to figure out why I can't get any textures to render with LWJGL 3. I've tried multiple ways to load (PNGDecoder, STB, BufferedImage) and to render textures. But the result is always a white quad.

Main Class:

public static void main(String[] args)
{
    glfwInit();
    window = glfwCreateWindow(640, 480, "TEST", 0, 0);
    glfwShowWindow(window);
    glfwMakeContextCurrent(window);
    GL.createCapabilities();

    GL11.glEnable(GL11.GL_TEXTURE_2D);

    Loader loader = new Loader();
    TestRenderer renderer = new TestRenderer();
    ModelTexture texture = new ModelTexture(loader.loadTextureManual("blue"));
    while(!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        renderer.prepare();
        renderer.renderWithFixedFunctions(texture);
        glfwSwapBuffers(window);
        clearErrorBuffer(true);
    }
    loader.cleanUp();
}

Loading Method:

    public int loadTextureManual(String fileName)
{
    String imagePath = "./res/" + fileName + ".png";
    try {
        System.out.println("Trying to load texture \""+imagePath+"\"");

        BufferedImage bi = ImageIO.read(new File(imagePath));
        int width = bi.getWidth();
        int height = bi.getHeight();

        int[] pixels_raw = new int[width*height];
        pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);

        ByteBuffer pixels = BufferUtils.createByteBuffer(width*height*4);

        for(int i = 0; i < width; i++)
        {
            for(int j = 0; j < height; j++)
            {
                int pixel = pixels_raw[i*width+j];
                pixels.put((byte) ((pixel >> 16) & 0xFF));  //RED
                pixels.put((byte) ((pixel >> 8) & 0xFF));   //GREEN
                pixels.put((byte) ((pixel) & 0xFF));        //BLUE
                pixels.put((byte) ((pixel >> 24) & 0xFF));  //ALPHA
            }
        }

        pixels.flip();

        byte[] info = new byte[pixels.capacity()];
        pixels.get(info);

        int textureID = GL11.glGenTextures();

        if(GL.getCapabilities().GL_EXT_texture_filter_anisotropic)
        {
            float amount = Math.min(ANISOTROPIC_FILTERING_AMOUNT, GL11.glGetFloat(EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT));
            GL11.glTexParameterf(GL11.GL_TEXTURE_2D, EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, amount);
        }
        else
        {
            System.out.println("Anisotropic filtering not supported!");
        }

        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0,
                GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);

        return textureID;
    }
    catch (Exception e)
    {
        e.printStackTrace();
        System.err.println("Couldn'l load texture \""+imagePath+"\"");
        System.exit(-1);
    }
    return 0;
}

Rendering Method:

public void renderWithFixedFunctions(ModelTexture texture)
{
    glBindTexture(GL_TEXTURE_2D, texture.getID());
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex2f(-0.5f, 0.5f);

    glTexCoord2f(0, 1);
    glVertex2f(0.5f, 0.5f);

    glTexCoord2f(1, 1);
    glVertex2f(0.5f, -0.5f);

    glTexCoord2f(1, 0);
    glVertex2f(-0.5f, -0.5f);
    glEnd();
}

The ModelTexture class just stores some info that is not used right now and the blue.png is 16x16 png file.

This is the output that I get when starting the program:


Answer:

Looks like an incomplete texture.

Set GL_TEXTURE_MIN_FILTER to GL_NEAREST or GL_LINEAR (default is GL_NEAREST_MIPMAP_LINEAR) or upload a complete mipmap chain.

Question:

In this example i try to render a simple textured triangle in java with lwjgl, but i simply can't figure out why it render the triangle filled with one color.

The color seems to be the average color of the whole texture or just one pixel of the texture, if i make the image for example green it renders the triangle green.

Thanks in advance for you help.

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.system.MemoryUtil.*;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import org.joml.Matrix4f;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;

import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;

public class TEST
{
    public int WIDTH = 1000;
    public int HEIGHT = 1000;
    public float vertices[] = new float[]
    {
            //COORDINATES
            0.0f, 0.8f, 0.0f,1.0f,
            //COLOR NOT USED
            0.0f,1.0f,0.0f,1.0f,
            //TEXTURE COORDINATES
            0.5f, 1.0f,

            //COORDINATES
            -0.8f,-0.8f, 0.0f,1.0f,
            //COLOR NOT USED
            1.0f,0.0f,0.0f,1.0f,
            //TEXTURE COORDINATES
            0.0f, 0.0f,

            //COORDINATES
            0.8f,-0.8f, 0.0f,1.0f,
            //COLOR NOT USED
            0.0f,0.0f,1.0f,1.0f,
            //TEXTURE COORDINATES
            1.0f, 0.0f
    };

    public TEST()
    {

    }


    public int start() throws IOException
    {
        glfwInit();
        glfwDefaultWindowHints(); 
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GL11.GL_TRUE);
        long window = glfwCreateWindow(WIDTH, HEIGHT, "HAHA", NULL, NULL);

        glfwMakeContextCurrent(window);
        glfwSwapInterval(1);
        glfwShowWindow(window);
        GL.createCapabilities();

        //CALLBACKS
        GLFWKeyCallback keycallback = new GLFWKeyCallback()
        {

            @Override
            public void invoke(long window, int key, int scancode, int action, int mods)
            {
                if(key==GLFW_KEY_ESCAPE&&action==GLFW_PRESS)
                {
                    glfwSetWindowShouldClose(window, GLFW_TRUE);
                }
            }
        };
        glfwSetKeyCallback(window,keycallback );
        GLFWErrorCallback errorcallback = new GLFWErrorCallback()
        {

            @Override
            public void invoke(int error, long description)
            {
                System.out.println("ERROR CODE: " + error + "  ERROR DESCRITPION: "+description);
            }
        };
        glfwSetErrorCallback(errorcallback);
        GLFWWindowSizeCallback windowsizecallback = new GLFWWindowSizeCallback()
        {
            @Override
            public void invoke(long window, int width, int height)
            {
                glViewport(0, 0, width, height);
                System.out.println(width+"    "+height);
            }
        };
        glfwSetWindowSizeCallback(window, windowsizecallback);



        //////////////////////////
        int VAO = glGenVertexArrays();
        glBindVertexArray(VAO);


        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
        byteBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
        floatBuffer.clear();
        floatBuffer.put(vertices);
        floatBuffer.flip();

        int VBO = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, floatBuffer, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 4, GL_FLOAT, false, 40, 0);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 40, 16);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(2, 2, GL_FLOAT, false, 40, 24);
        glEnableVertexAttribArray(2);

        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindVertexArray(0);
        ///////////////////////
        ///////////////////////
        LoadFile loader = new LoadFile("res/shader.vs", "res/shader.frag");

        int vertexshader = glCreateShader(GL_VERTEX_SHADER);
        int fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

        glShaderSource(vertexshader, loader.readVertex());
        glShaderSource(fragmentshader, loader.readFragment());

        glCompileShader(vertexshader);
        glCompileShader(fragmentshader);

        System.out.println(glGetShaderInfoLog(vertexshader));
        System.out.println(glGetShaderInfoLog(fragmentshader));


        int program = glCreateProgram();

        glAttachShader(program, vertexshader);
        glAttachShader(program, fragmentshader);

        glLinkProgram(program);

        glDeleteShader(vertexshader);
        glDeleteShader(fragmentshader);

        System.out.println(glGetProgramInfoLog(program));
        ///////////////////////////

        int texture1 = glGenTextures();
        InputStream texture1inputstream = new FileInputStream("res/container2.png");
        PNGDecoder texture1decoder = new PNGDecoder(texture1inputstream);
        ByteBuffer texture1buffer = ByteBuffer.allocateDirect(4*texture1decoder.getWidth()*texture1decoder.getHeight()).order(ByteOrder.nativeOrder());
        texture1decoder.decode(texture1buffer, texture1decoder.getWidth()*4, Format.RGBA);
        texture1buffer.flip();

        glBindTexture(GL_TEXTURE_2D, texture1);

        glTexImage2D
        (
                GL_TEXTURE_2D,
                0,
                GL_RGBA,
                texture1decoder.getWidth(),
                texture1decoder.getHeight(),
                0,
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                texture1buffer
        );

        glGenerateMipmap(GL_TEXTURE_2D);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glBindTexture(GL_TEXTURE_2D, 0);

        int textureloc = glGetUniformLocation(program, "texture");

        //MAKE UNIFORM SETTER
        UniformSetter uniformsetter = new UniformSetter(program, "model", "projection","view");
        /////////////////////

        glEnable(GL_DEPTH_TEST);

        boolean running=true;

        while(running&&glfwWindowShouldClose(window)==GLFW_FALSE)
        {
            glfwPollEvents();
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
            glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

            glUseProgram(program);

            glBindVertexArray(VAO);
            ///////////////////////

            for(int a = 0;a<4;a++)
            {
                //MAKE MATRIX MODEL
                Matrix4f model = new Matrix4f();

                model.translate(0.0f,0.0f,0.0f);
                float xang = 0f;
                float yang = 0f;
                float zang = 0f;
                model.rotate((float) Math.toRadians(xang), 1.0f, 0.0f, 0.0f);
                model.rotate((float) Math.toRadians(yang), 0.0f, 1.0f, 0.0f);
                model.rotate((float) Math.toRadians(zang), 0.0f, 0.0f, 1.0f);
                model.scale(0.5f);

                uniformsetter.setModel(model);
                ////////////////////

                //MAKE MATRIX VIEW
                Matrix4f view = new Matrix4f();

                view.lookAt(0.0f, 0.0f, 1.0f,
                            0.0f, 0.0f, 0.0f,
                            0.0f, 1.0f, 0.0f);

                uniformsetter.setView(view);
                //////////////////

                //MAKE MATRIX PROJECTION
                Matrix4f projection = new Matrix4f();

                projection.ortho(-1.0f, 1.0f, -1.0f, 1.0f,1.0f,-1.0f);

                uniformsetter.setProjection(projection);
                /////////////////////////

                //ACTIVATE AND BIND TEXTURE
                glActiveTexture(GL_TEXTURE0);
                glBindTexture(GL_TEXTURE_2D, texture1);
                glUniform1i(textureloc, 0);

                ///////////////////////////

                glDrawArrays(GL_TRIANGLES, 0, 3);

                glBindTexture(GL_TEXTURE_2D, 0);
            }

            ///////////////////////
            glBindVertexArray(0);

            glUseProgram(0);

            glfwSwapInterval(1);
            glfwSwapBuffers(window);
        }

        System.out.println(glGetError());
        glfwTerminate();

        return 0;
    }
}

Vertex Shader:

#version 440
layout (location = 0) in vec4 position;
//NOT USED layout (location = 1) in vec4 colorin;
layout (location = 2) in vec2 texturecoordiantesin;

//NOT USED out vec4 colorout;
out vec2 texturecoordinatesout;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection*view*model*position;
    //NOT USED colorout=colorin;
}

Fragment Shader:

#version 440
out vec4 color;

//NOT USED in vec4 colorout;
in vec2 texturecoordinatesout;
uniform sampler2D texture;

void main()
{
    color = texture2D(texture,texturecoordinatesout);
}

Answer:

Your are missing the propagation of the texturecoordinatesin in the vertex shader. Add this anywhere in the vertex shader:

texturecoordinatesout = texturecoordinatesin;

Also, you are doing a mistake when you set the vertex array pointer. The last parameter of glVertexAttribPointer for attribute 2 should be 32. 4 floats offset for position and 4 floats offset for color is a total of 8 floats offset, or 32 bytes:

    glVertexAttribPointer(0, 4, GL_FLOAT, false, 40, 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, false, 40, 16);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, false, 40, 32);
    glEnableVertexAttribArray(2);

Question:

Below of my main class I am trying to render a obj from a blender .obj file after reformatting it to (supposedly) work for my rendering it gives the error. How can I fix this?

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at flow_control.MainLoop.render(MainLoop.java:85)
    at flow_control.MainLoop.main(MainLoop.java:45)

Main class:

package flow_control;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

import static org.lwjgl.opengl.GL11.*;


public class MainLoop {
    MainLoop(){
        camera = new Camera(this);
        loadTextures();
    }
private static final int WIDTH = 1280
private static final int HEIGHT = 700;
boolean[] keys = new boolean[256];
Camera camera;
Texture TexFloor;
Texture TexWhite;
Model m = null;

public static void main(String[] args) {
    System.out.println("S");
    try {
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create();
    } catch (LWJGLException e) {
        e.printStackTrace();
    }
    MainLoop game = new MainLoop();
    game.load();
    game.loadTextures();
    while(!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)){
        game.update();
        game.render();
        Display.update();
        Display.sync(60);
    }
    Display.destroy();
    System.exit(0);
}
private void loadTextures(){
    try{
        TexFloor = TextureLoader.getTexture("JPG", ResourceLoader.getResourceAsStream("res/floor.jpg"));
    }catch(FileNotFoundException e) {
        System.err.println("Could not find textures");
        e.printStackTrace();
    }catch(IOException e){
        System.err.println("IO problem");
        e.printStackTrace();
    }

}
public void render() {
    clearScreen();

    camera.translatePostion();
    glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex3f(0, 0, 0);

        glTexCoord2f(128/8, 0);
        glVertex3f(500, 0, 0);

        glTexCoord2f(128/8, 128/8);
        glVertex3f(500, 0, 500);

        glTexCoord2f(0, 128/8);
        glVertex3f(0, 0, 500);

    glEnd();

    glBegin(GL_TRIANGLES);
        for (Faces face : m.faces) {
//error occurs on the line below
            Vector3f n1 = m.normals.get((int) face.normals.x - 1);
            glNormal3f(n1.x, n1.y, n1.z);
            Vector3f v1 = m.vertices.get((int) face.Vertex.x - 1);
            glNormal3f(v1.x, v1.y, v1.z);
            Vector3f n2 = m.normals.get((int) face.normals.y - 1);
            glNormal3f(n2.x, n2.y, n2.z);
            Vector3f v2 = m.vertices.get((int) face.Vertex.y - 1);
            glNormal3f(v2.x, v2.y, v2.z);
            Vector3f n3 = m.normals.get((int) face.normals.z - 1);
            glNormal3f(n3.x, n3.y, n3.z);
            Vector3f v3 = m.vertices.get((int) face.Vertex.z - 1);
            glNormal3f(v3.x, v3.y, v3.z);
        }

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
    TexFloor.bind();

}
public void load() {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    GLU.gluPerspective((float) 100, WIDTH/HEIGHT, 0.001f, 1000);
    glMatrixMode(GL_MODELVIEW);

    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    try{
        m = OBJLoader.loadModel(new File("res/tree.obj"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
public void clearScreen() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
}
public void update() {
    mapKeys();
    camera.update();
}
private void mapKeys(){
    for(int i=0;i<keys.length; i++) {
        keys[i] = Keyboard.isKeyDown(i);
         }
    }
}

Class OBJLoader:

package flow_control;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.lwjgl.util.vector.Vector3f;

public class OBJLoader {
    public static Model loadModel(File f) throws FileNotFoundException,     IOException {
    BufferedReader reader = new BufferedReader(new FileReader(f));
    Model m = new Model();
    String line;
    while((line = reader.readLine()) != null){
        //parse object
        if (line.startsWith("v ")){
            float x = Float.valueOf(line.split(" ")[1]);
            float y = Float.valueOf(line.split(" ")[2]);
            float z = Float.valueOf(line.split(" ")[3]);
            m.vertices.add(new Vector3f(x,y,z));
        } else if (line.startsWith("vn ")) {
            float x = Float.valueOf(line.split(" ")[1]);
            float y = Float.valueOf(line.split(" ")[2]);
            float z = Float.valueOf(line.split(" ")[3]);
            m.normals.add(new Vector3f(x,y,z));
        } else if (line.startsWith("f ")) {
            Vector3f vertexIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[0]),Float.valueOf(line.split(" ")[2].split("/")[0]),Float.valueOf(line.split(" ")[3].split("/")[0]));
            Vector3f normalIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[2]),Float.valueOf(line.split(" ")[2].split("/")[2]),Float.valueOf(line.split(" ")[3].split("/")[2]));
            m.faces.add(new Faces(vertexIndices, normalIndices));


        }
    }
    reader.close();
    return m;
    }
}

Class Model:

package flow_control;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.util.vector.Vector3f;

public class Model {
    public List<Vector3f> vertices = new ArrayList<Vector3f>();
    public List<Vector3f> normals = new ArrayList<Vector3f>();
    public List<Faces> faces = new ArrayList<Faces>();
    public Model(){

    }
}

Class Faces:

package flow_control;


import org.lwjgl.util.vector.Vector3f;

 public class Faces {
    public Vector3f Vertex = new Vector3f();
    public Vector3f normals = new Vector3f();

    public Faces(Vector3f vertex, Vector3f normal) {
        this.Vertex = vertex;
        this.normals = normals;
    }
}

Sorry if some of this is excessive I know the errors coming from line 85 but I can't seem to figure out how to fix it.

OBJ file example (slimmed down):

# Blender v2.74 (sub 0) OBJ File: ''

# www.blender.org

mtllib tree.mtl

o Mesh_default
v -0.163260 2.023340 -0.247879

v 0.163260 2.023340 -0.247878

v 0.163260 2.023340 0.247879

f 35//34 39//40 36//35

f 36//35 40//39 37//36

f 38//37 34//41 41//38

vn -0.259900 0.445500 -0.856700

vn 0.087800 0.445500 -0.891000

vn -0.422000 0.445500 -0.789600

Answer:

You made a couple of typo's in your program.

First off, in your OBJLoader class

else if (line.startsWith("vm ")) 

Its looking for lines in the OBJ file that start with "vm " but your obj files uses "vn ". Simply change this and the array won't be empty anymore.

vn -0.259900 0.445500 -0.856700
vn 0.087800 0.445500 -0.891000
vn -0.422000 0.445500 -0.789600

Secondly, in the Faces class

public Faces(Vector3f vertex, Vector3f normal) 
{
    this.Vertex = vertex;
    this.normals = normals;
}

You are setting the "normals" variable equal to itself rather then the Vector3f in the constructor, change it to this.

    this.normals = normal;

Question:

I began using LWJGL and I watched som tutorials on yoututbe. I have a problem with my quad not rendering. Whenever I run the program I would just get a black screen. I searched a lot for the answer but i couldn't find it. I don't know what I did wrong. Could you help me?

Here is my code:

Main class:

package com.tiprojectes.JGames.renderEngine;

import static org.lwjgl.glfw.GLFW.*;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import static org.lwjgl.opengl.GL11.*;

public class Main 
{
    public static final int width = 600;
    public static final int height = 600;
    float x = 0;
    float y = 0;
    float speed = 0.002f;

    public Main()
    {   
        if (!glfwInit())
        {
            System.err.println("Could not initialize GLFW");
        }

        glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);

        long window = glfwCreateWindow(width, height, "No Name Game PRE_ALPHA_0.01", 0, 0);

        glfwMakeContextCurrent(window);

        GL.createCapabilities();

        glEnable(GL_TEXTURE_2D);

        float[] vertexes = new float[] 
        {   
            -0.5f, 0.5f, 0,
            0.5f, 0.5f, 0,
            0.5f, -0.5f, 0,
            -0.5f, -0.5f, 0
        };

        float[] textures = new float[]
        {
                0, 0,
                1, 0,
                1, 1,
                0, 1
        };

        int[] indices = new int[] 
        {
                0, 1, 2,
                2, 3, 0
        };

        Model model = new Model(vertexes, textures, indices);

        Textures texture = new Textures("./res/terrain.png");

        if (window == 0)
        {
            System.err.println("Could not create window");
        }

        GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());

        glfwSetWindowPos(window, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);

        glfwShowWindow(window);

        while (!glfwWindowShouldClose(window))
        {       
            glfwPollEvents();

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            model.render();

            texture.bind();

            glfwSwapBuffers(window);
        }

        glfwTerminate();
    }

    public static void main(String[] args)
    {
        new Main();
    }
}`

Textures class:

package com.tiprojectes.JGames.renderEngine;

import static org.lwjgl.opengl.GL11.*;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import javax.imageio.ImageIO;

import org.lwjgl.BufferUtils;

public class Textures
{
    private int id;
    private int width;
    private int height;

    public Textures(String filename) 
    {
        BufferedImage bi;

        try
        {
            bi = ImageIO.read(new File(filename));
            width = bi.getWidth();
            height = bi.getHeight();

            int[] pixels_raw = new int[width * height];
            pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);

            ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);

            for(int i = 0; i < width; i++)
                for(int j = 0; j < height; j++)
                {
                    int pixel = pixels_raw[i * width + j];
                    pixels.put((byte) ((pixel >> 16) & 0xFF));  // RED
                    pixels.put((byte) ((pixel >> 8) & 0xFF));   // GREED
                    pixels.put((byte) ((pixel & 0xFF)));        // BLUE
                    pixels.put((byte) ((pixel >> 24) & 0xFF));  // ALPHA
                }

            pixels.flip();

            id = glGenTextures();

            glBindTexture(GL_TEXTURE_2D, id);

            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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
        }
        catch (IOException e) 
        {
            e.printStackTrace();
        }
    }

    public void bind()
    {
        glBindTexture(GL_TEXTURE_2D, id);
    }
}

Model class:

package com.tiprojectes.JGames.renderEngine;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
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[] vertexes, float[] tex_coords, int[] indices)
    {
        draw_count = indices.length;

        v_id = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, v_id);
        glBufferData(GL_ARRAY_BUFFER, createBuffer(vertexes), 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);

        IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
        buffer.put(indices);
        buffer.flip();

        glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    public void render()
    {
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindBuffer(GL_ARRAY_BUFFER, v_id);
        glVertexPointer(3, GL_FLOAT, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, t_id);
        glTexCoordPointer(2, GL_FLOAT, 0, 0);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);

        glDrawElements(GL_TRIANGLES, draw_count, GL_UNSIGNED_INT, 0);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

    private FloatBuffer createBuffer(float[] data)
    {
        FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
        buffer.put(data);
        buffer.flip();
        return buffer;
    }

}

Hope I can get some help. Thanks!


Answer:

I solved it. The quad was not rendering. In the model class, at glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW) I had to put instead of GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER. Thanks for the help!

Question:

I started watching these tutorials for creating a 2d top-down game using LWJGL and I read that VBO's should be fast but for rendering 48*48 tiles per frame I get only about 100FPS which is pretty slow because I will add a lot more stuff to the game than just some static, not moving or changing, tiles.

What can I do to make this faster? Keep in mind that I just started learning lwjgl and opengl so I probably won't know many things.

Anyways, here are some parts of my code (I removed some parts from the code that were kinda meaningless and replaced them with some descriptions):

The main loop

double targetFPS = 240.0;
        double targetUPS = 60.0;

        long initialTime = System.nanoTime();
        final double timeU = 1000000000 / targetUPS;
        final double timeF = 1000000000 / targetFPS;
        double deltaU = 0, deltaF = 0;
        int frames = 0, updates = 0;
        long timer = System.currentTimeMillis();

        while (!window.shouldClose()) {
            long currentTime = System.nanoTime();
            deltaU += (currentTime - initialTime) / timeU;
            deltaF += (currentTime - initialTime) / timeF;
            initialTime = currentTime;

            if (deltaU >= 1) {
                // --- [ update ] ---
                --INPUT HANDLING FOR BASIC MOVEMENT, CLOSING THE GAME AND TURNING VSYNC ON AND OFF USING A METHOD FROM THE INPUT HANDLER CLASS--

                world.correctCamera(camera, window);

                window.update();

                updates++;
                deltaU--;
            }

            if (deltaF >= 1) {
                // --- [ render ] ---
                glClear(GL_COLOR_BUFFER_BIT);
                world.render(tileRenderer, shader, camera, window);
                window.swapBuffers();

                frames++;
                deltaF--;
            }
            --PRINTING THE FPS AND UPS EVERY SECOND--
        }

The input handler methods used:

I have this in my constructor:
this.keys = new boolean[GLFW_KEY_LAST];
for(int i = 0; i < GLFW_KEY_LAST; i++)
    keys[i] = false;

And here are the methods: 
public boolean isKeyDown(int key) {
    return glfwGetKey(window, key) == 1;
}
public boolean isKeyPressed(int key) {
    return (isKeyDown(key) && !keys[key]);
}
public void update() {
    for(int i = 32; i < GLFW_KEY_LAST; i++)
        keys[i] = isKeyDown(i);
}

This is the render method from the World class:

public void render(TileRenderer renderer, Shader shader, Camera camera, Window window) {
    int posX = ((int) camera.getPosition().x + (window.getWidth() / 2)) / (scale * 2);
    int posY = ((int) camera.getPosition().y - (window.getHeight() / 2)) / (scale * 2);
    for (int i = 0; i < view; i++) {
        for (int j = 0; j < view; j++) {
            Tile t = getTile(i - posX, j + posY);
            if (t != null)
                renderer.renderTile(t, i - posX, -j - posY, shader, world, camera);
        }
    }
}

This is the renderTile() method from TileRenderer:

public void renderTile(Tile tile, int x, int y, Shader shader, Matrix4f world, Camera camera) {
    shader.bind();
    if (tileTextures.containsKey(tile.getTexture()))
        tileTextures.get(tile.getTexture()).bind(0);

    Matrix4f tilePosition = new Matrix4f().translate(new Vector3f(x * 2, y * 2, 0));
    Matrix4f target = new Matrix4f();

    camera.getProjection().mul(world, target);
    target.mul(tilePosition);

    shader.setUniform("sampler", 0);
    shader.setUniform("projection", target);

    model.render();
}

This is the constructor and render method from Model class:

public Model(float[] vertices, float[] texture_coords, int[] indices) {
    draw_count = indices.length;

    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(texture_coords), GL_STATIC_DRAW);

    i_id = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_id);

    IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
    buffer.put(indices);
    buffer.flip();

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_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_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
}

I store the vertices, texture coords and indices in the tile renderer:

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
    };

I don't know what else to put here but the full source code and resources + shader files are available on github here.


Answer:

With your current system, what I would recommend doing is grouping your tiles based on texture. Create something like this:

Map<Texture, List<Tile>> tiles = new HashMap<Texture, List<Tile>>()

Then when you go to render your map of tiles, you will only need to set the texture once per group of tiles, rather than once per tile. This saves PCI-E bandwidth for pushing textures/texture ids to the GPU. You would achieve that like this (pseudo code):

for (Texture tex : tile.keySet())
{
    BIND TEXTURE
    for (Tile tile : tiles.get(tex))
    {
        SET UNIFORMS
        RENDER
    }
}

Something else I see along these lines is that you are pushing the projection matrix to each tile individually. When you are running a shader program, the value of a given uniform stays the same until you change it or until the program ends. Set the projection matrix uniform once.

It also appears that you are calling this every renderTile(...). Given the value does not change, calculate it once before the render pass, then pass it in as a variable in the renderTile(...) method rather than passing in camera and world.

Question:

How can I render Text in LWJGL/OpenGL with FreeType ? I find only tutorial is C++, but I don't understand C++. If there is no tutorial for rendering text with FreeType. How I can rewrite the C++ code in Java?


Answer:

There is a small FreeType wrapper in libGDX (Java OpenGL related library). The FreeTypeFontGenerator class will use FreeType to generate bitmap font of given size. Then you may use it to render your text through libGDX facilities or standard OpenGl facilities:

FreeTypeFontGenerator generator = new   FreeTypeFontGenerator(Gdx.files.internal("fonts/myfont.ttf"));
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = 12;
BitmapFont font12 = generator.generateFont(parameter); 
generator.dispose(); // don't forget to dispose to avoid memory leaks!

Tweak the FreeTypeFontParameter parameter fields to get result you want. See this short tutorial on libGDX wiki.

Question:

I am learning and programming with LWJGL/OpenGL. I want to render my map in chunks. For this I create a VAO and VBO for each chunk and upload and link them.

The problem is, that if I render the first chunk, all of the following 3 chunks will be rendered on top of that. If I render the second chunk the following 2 chunks will be rendered on top.

This is the log of my application, describing how I setup my VAOs:

Chunk: 0 0
Generate VBO: 1
Generate VAO: 1
Bind VAO: 1
Bind VBO: 1
Enable and set VertexAttribPointer
Bufferdata (Buffersize: 36864)
Bind VAO: 0

Chunk: 0 1
Generate VBO: 2
Generate VAO: 2
Bind VAO: 2
Bind VBO: 2
Enable and set VertexAttribPointer
Bufferdata (Buffersize: 1536)
Bind VAO: 0

Chunk: 1 0
Generate VBO: 3
Generate VAO: 3
Bind VAO: 3
Bind VBO: 3
Enable and set VertexAttribPointer
Bufferdata (Buffersize: 1536)
Bind VAO: 0

Chunk: 1 1
Generate VBO: 4
Generate VAO: 4
Bind VAO: 4
Bind VBO: 4
Enable and set VertexAttribPointer
Bufferdata (Buffersize: 64)
Bind VAO: 0

Draw
Bind VAO: 1
Set Unifoms
Draw Arrays

The buffersizes are as expected.

For binding I use glBindVertexArray() and glBindBuffer(GL_ARRAY_BUFFER, )

For drawing I use glDrawArrays()

Is the way I setup my VAOs wrong, or do you need my code to solve my problem?


Answer:

When using glDrawArrays, the count parameter specifies the number of vertices, not, unlike some other functions, the number of values (floats) or bytes. OpenGL does not check whether the count exceeds the capacity of the VBO. Therefore, when you specify a larger count value than there is storage in the VBO, OpenGL will silently take values from adjacent memory, which in this case contains your other VBOs.

So you have to be sure you pass the number of vertices, because the number of floats is three times as large, drawing all your data instead of just the data for one chunk.


Original Post

It seems that you have depth testing disabled, which is a technique that discards all fragments that are farther away than existing ones to prevent farther objects from covering closer ones.

You can enable it with

glEnable(GL_DEPTH_TEST);

during initialization.

Question:

I've been trying to get into OpenGL with LWJGL and I've run into an issue that I cannot find a solution to. When trying to draw a triangle with the code below, the window opens correctly and begins flashing a shape that isn't necessarily the intended triangle (sometimes it appears briefly, but often there are rectangles in one of the quadrants of the window).

Part of my hesitation is in how OpenGL, by my reading of various posts and docs online, has changed within recent memory to use a less functional and more an object-oriented approach (VBOs and GLSL?) with GL4. Am I correct in this understanding and what are the preferred resources for learning this newer OpenGL for LWJGL?

Thank you in advance!

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

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 {
  private long windowID;

  private float[] tri = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f};

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

  public void run() { // Useful for making an instance class as opposed to a static main class?
    init();
    loop();

    glfwFreeCallbacks(windowID);
    glfwDestroyWindow(windowID);

    glfwTerminate();
    glfwSetErrorCallback(null).free();
  }

  public void init() { // Initializes all LWJGL components
    GLFWErrorCallback.createPrint(System.err).set(); // Create error callback route for GL

    if (!glfwInit()) { // Init GLFW
      throw new IllegalStateException("Failed to initialize GLFW!");
    } else {
      System.out.println("GLFW successfully initialized!");
    }

    windowID = glfwCreateWindow(640, 480, "Creating Window", NULL, NULL);

    if (windowID == NULL) { // Verify window creation
      throw new IllegalStateException("Failed to create window!");
    } else {
      System.out.println("Successfully created window!");
    }

    glfwDefaultWindowHints(); // Set window Proporties
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

    glfwSetKeyCallback(windowID, (window, key, scancode, action, mods) -> { // Key callback for closing the window
      if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
        glfwSetWindowShouldClose(window, true);
    });

    try (MemoryStack stack = stackPush()) { // Center the window
      IntBuffer pWidth = stack.mallocInt(1);
      IntBuffer pHeight = stack.mallocInt(1);

      glfwGetWindowSize(windowID, pWidth, pHeight);

      GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

      glfwSetWindowPos( // Center the window
          windowID, 
          (vidmode.width() - pWidth.get(0)) / 2,
          (vidmode.height() - pHeight.get(0)) / 2
          );
    }

    glfwMakeContextCurrent(windowID); // Make the window current
    glfwSwapInterval(0); // Sets the min num of pushed frames before buffers are swaped (Likely prevents horizontal tearing)
    glfwShowWindow(windowID); // Unhides the window
  }

  private void loop() {
    GL.createCapabilities();
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // The color to clear the buffers with

    while(!glfwWindowShouldClose(windowID)) { // If the window is allowed to live
      glClear(GL_COLOR_BUFFER_BIT); // The OR is nessesary for some reason

      FloatBuffer vBuff = BufferUtils.createFloatBuffer(6);
      vBuff.put(tri);
      glEnableClientState(GL_VERTEX_ARRAY);
      glVertexPointer(2, GL_FLOAT, 0, vBuff);
      glDrawArrays(GL_TRIANGLES, 0, 6);
      glDisableClientState(GL_VERTEX_ARRAY);

      glfwSwapBuffers(windowID);
      glfwPollEvents();
    } 
  }
}

Answer:

You missed vBuff.flip() after the buffer was crated and filled.

vBuff.put(tri) transfers the the data to the buffer, beginning at the current position (which is the start of the buffer in this case). The buffer position is incremented by the size of the data. So the new buffer position is at the end of the new data.

flip() sets the limit (length) of the buffer to the current position and then the position is set to zero.

Further, it is not necessary to create and fill the buffer continuously in the loop, it would be sufficient to do that once before the loop:

FloatBuffer vBuff = BufferUtils.createFloatBuffer(6);
vBuff.put(tri);
vBuff.flip();

while(!glfwWindowShouldClose(windowID)) {
    glClear(GL_COLOR_BUFFER_BIT);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, vBuff);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glDisableClientState(GL_VERTEX_ARRAY);

    glfwSwapBuffers(windowID);
    glfwPollEvents();
}

Question:

Background: I have been working on a game engine in LWJGL. I normally work on my desktop with an NVidia graphics card. When using that card, everything works properly (i.e. the scene renders, UI renders, and everything updates). However, when I use my surface pro 4 and its integrated graphics (Intel 530), the scene and UI seem to render at least 2 times (to fill both front and back buffers), then the scene and UI stop updating. I can confirm that the application is still running, as my in console FPS counter still works.

Code: My window's update method is as follows:

public void update() {
    frameRateCounter.start();
    newFrame();
    calc.layout(ctx, 50, 50);
    render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
    UI.poll();
    glfwSwapBuffers(window);
    clear();
    frameRateCounter.calculate();
}

I use the Nuklear demo provided by LWJGL here. Does anyone have any ideas on why this is, or is this most likely a hardware issue?

Thanks in advance!


Answer:

To answer my own question, it seems that a driver update fixed the issue. Another issue that I just found was that the inputs seem to be several pixels off. I can confirm this with other, 3rd party software such as Blender. Seems that there is nothing I can do, so hopefully this response will be useful for someone else experiencing similar issues.

Question:

Whenever I run this, the window pops up and I see this. (When I run the game, I see this)

This can be recreated if you simply make a new Java Project, import OpenGL, GLFW, and LWJGL, along with natives, and then copy the code (Remove package)

import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.opengl.GL;

public class Game {

    public static void main (String[] args) {

        if(glfwInit() != true) {
            System.err.println("GLFW Failed to initialize!");
            System.exit(1);
        }

        long window = glfwCreateWindow(640,480,"Game", 0, 0);

        glfwShowWindow(window);

        glfwMakeContextCurrent(window);
        GL.createCapabilities();

        while(!glfwWindowShouldClose(window)) {

            glfwPollEvents();

            glClear(GL_COLOR_BUFFER_BIT);

            glBegin(GL_QUADS);

            glVertex2d(-0.5,0.5);
            glVertex2d(0.5,0.5);
            glVertex2d(-0.5,-0.5);
            glVertex2d(0.5,-0.5);

            glEnd();

            glfwSwapBuffers(window);

        }

        glfwTerminate();

    }

}

Answer:

You're drawing the vertices of the quad in the wrong order. Try

glVertex2d(0.5,0.5);
glVertex2d(-0.5,0.5);
glVertex2d(-0.5,-0.5);
glVertex2d(0.5,-0.5);

You usually draw them in counterclockwise order for a quad (or triangle) that is facing you (this is called "winding") and clockwise for one that is facing away from you. In your case, you have drawn them as if they were a letter "Z" which is invalid.

Question:

I am trying to learn how to use LWJGL3 and I just got to a state where I want to render something (a test quad for now). I have a class that represents a mesh where I set up the VAO with vertex, colour and indices buffers and another object later takes the mesh instance, retrieves its VAO ID and attempts to render it.

The problem I have is that no matter what I try, nothing renders in the window. I can change the background colour through the glClearColor() method but the quad never shows up.

The VAO set up:

vertexCount = indices.length;

vaoID = glGenVertexArrays();
glBindVertexArray(vaoID);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

//Vertices
FloatBuffer verticesBuffer = BufferUtils.createFloatBuffer(positions.length);
verticesBuffer.put(positions).flip();

vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * 4, 0);

//Colours
FloatBuffer colorsBuffer = BufferUtils.createFloatBuffer(colors.length);
colorsBuffer.put(colors).flip();

colVboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, colVboID);
glBufferData(GL_ARRAY_BUFFER, colorsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 3 * 4, 0);

//Indices
IntBuffer indicesBuffer = BufferUtils.createIntBuffer(indices.length);
indicesBuffer.put(indices).flip();

idxVboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);

//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

The rendering code:

//Bind the shader
shaderProgram.bind();

//Bind the VAO
glBindVertexArray(mesh.getVaoID());

//Draw
glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0);

//Restore
glBindVertexArray(0);
shaderProgram.unbind();

Vertex shader:

#version 330

layout (location=0) in vec3 pos;
layout (location=1) in vec3 inColor;

out vec3 exColor;

void main()
{
    gl_Position = vec4(pos, 1.0);
    exColor = inColor;
}

Fragment shader:

#version 330

in vec3 exColor;
out vec4 fragColor;

void main()
{
    fragColor = vec4(exColor, 1.0);
}

What am I doing wrong?


Answer:

The problem was not in the parts of code shown, but in the main loop that I copied from a book without thoroughly thinking through what it did. I ended up with a glClear call right before glfwSwapBuffers call, which cleared the buffer right before showing it.

Lesson of the day: don't just copy from a book, think thoroughly about what you're doing

(Thank you to the people of LWJGL formus for helping me discover this mistake)

Question:

I am using LWJGL 3 and Shaders with VAO's. My current implementation does not draw the VAO when using the shaders. However the VAO will draw when not using shaders but the VAO will be white. My question is what am I missing in my shader setup that is preventing me from seeing the VAO when using shaders?

Main Class. Shader and VAO setup is in the gameStart() method.

public class Test {

/** Window Properties **/
private int 
    HEIGHT = 800,
    WIDTH = 1200,
    RESIZABLE = GL11.GL_FALSE,
    REFRESH_RATE = 60;

private String TITLE = "test";

// The window handler
private long window;

// callback reference instances
private GLFWErrorCallback errorCallback;
private GLFWKeyCallback   keyCallback;

private void preWindowSetup() {
    // Setup an error callback
    GLFW.glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

    // Initialize GLFW
    if (GLFW.glfwInit() != GL11.GL_TRUE)
        exit();
}

private void windowSetup() {
    // Configure Window Properties
    glfwDefaultWindowHints();
    GLFW.glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // Keep the window hidden
    glfwWindowHint(GLFW_RESIZABLE, RESIZABLE); // Do not allow resizing
    glfwWindowHint(GLFW_REFRESH_RATE, REFRESH_RATE); // Refresh rate

    // Create the window
    window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, NULL, NULL);
    if ( window == NULL )
        exit();

    // Get the resolution of the primary monitor
    ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    // Center our window
    glfwSetWindowPos(
        window,
        (GLFWvidmode.width(vidmode) - WIDTH) / 2,
        (GLFWvidmode.height(vidmode) - HEIGHT) / 2
    );
}

private void callbackSetup() {
    // Setup a key callback. It will be called every time a key is pressed, repeated or released.
    glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
        @Override
        public void invoke(long window, int key, int scancode, int action, int mods) {//TODO Dispatch key events
            if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                Tasker.executeASyncTask("GLFW_MAIN_THREAD");
        }
    });
}

public void initGL() {
    preWindowSetup();
    windowSetup();
    callbackSetup();

    glfwMakeContextCurrent(window);     // Make the OpenGL context current
    glfwShowWindow(window);             // Make the window visible
    GLContext.createFromCurrent();      // Bind lwjgl with GLFW

    // Initialize openGl
    GL11.glViewport(0, 0, WIDTH, HEIGHT);
    GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glOrtho(0, WIDTH, 0, HEIGHT, 1, -1);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);

    // Enable alpha transparency (for overlay image)
    GL11.glEnable(GL11.GL_BLEND);
    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glDepthFunc(GL11.GL_LEQUAL);
    GL11.glShadeModel(GL11.GL_SMOOTH);
}

public void gameStart() {

    System.out.println("LWJGL Version: ["+Sys.getVersion()+"]");
    System.out.println("OpenGL Version: ["+GL11.glGetString(GL11.GL_VERSION)+"]");

    // ===============================================================================================

    // =================== Shader Setup =====================
    String vertPath = "src/test/java/org/ajgl/test/graphics/shaders/VertexShaderTest.glsl";
    String fragPath = "src/test/java/org/ajgl/test/graphics/shaders/FragmentShaderTest.glsl";

    int sahderVert = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
    GL20.glShaderSource(sahderVert, Shader.loadShader(vertPath));
    GL20.glCompileShader(sahderVert);

    int sahderFrag = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
    GL20.glShaderSource(sahderFrag, Shader.loadShader(fragPath));
    GL20.glCompileShader(sahderFrag);
    // =================== Shader Setup =====================

    // =================== Shader Check =====================
    int status = GL20.glGetShaderi(sahderVert, GL20.GL_COMPILE_STATUS);
    if (status != GL11.GL_TRUE) {
        throw new RuntimeException(GL20.glGetShaderInfoLog(sahderVert));
    }

    int statusN = GL20.glGetShaderi(sahderFrag, GL20.GL_COMPILE_STATUS);
    if (statusN != GL11.GL_TRUE) {
        throw new RuntimeException(GL20.glGetShaderInfoLog(sahderFrag));
    }
    // =================== Shader Check =====================

    // =================== Shader Program ===================
    int programID = GL20.glCreateProgram();

    GL20.glAttachShader(programID, sahderVert);
    GL20.glAttachShader(programID, sahderFrag);

    GL20.glBindAttribLocation(programID, 0, "position");
    GL20.glBindAttribLocation(programID, 1, "color");

    GL20.glLinkProgram(programID);
    // =================== Shader Program ===================

    // =============== Shader Program Check =================
    int statusP = GL20.glGetProgrami(programID, GL20.GL_LINK_STATUS);
    if (statusP != GL11.GL_TRUE) {
        throw new RuntimeException(GL20.glGetProgramInfoLog(programID));
    }
    // =============== Shader Program Check =================

    // =================== VAO Setup ========================
    FloatBuffer vertexBufferVAO = BufferUtils.createFloatBuffer(9);
    vertexBufferVAO.put(new float[]{600,10,0, 550,50,0, 500,10,0});
    vertexBufferVAO.flip();

    FloatBuffer colorBufferVAO = BufferUtils.createFloatBuffer(9);
    colorBufferVAO.put(new float[]{1,0,0, 0,1,0, 0,0,1});
    colorBufferVAO.flip();

    int vaoID = GL30.glGenVertexArrays();
    GL30.glBindVertexArray(vaoID);
    {
        int vertHandle = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertHandle);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBufferVAO, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);

        int colorHandle = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorHandle);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, colorBufferVAO, GL15.GL_STATIC_DRAW);
        GL20.glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 0, 0);
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    }
    GL30.glBindVertexArray(0);

    // =================== VAO Setup ========================

    // ===============================================================================================

    while ( glfwWindowShouldClose(window) == GL_FALSE ) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Run Cycles
        input();

        GL20.glUseProgram(programID);

        GL30.glBindVertexArray(vaoID);
        {
            GL20.glEnableVertexAttribArray(0);
            GL20.glEnableVertexAttribArray(1);

            GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);

            GL20.glDisableVertexAttribArray(0);
            GL20.glDisableVertexAttribArray(1);
        }
        GL30.glBindVertexArray(0);

        GL20.glUseProgram(0);

        // Display Buffer swap
        glfwSwapBuffers(window);
    }

    // Release window and window call backs
    glfwDestroyWindow(window);
    keyCallback.release();
    exit();
}

private void input() {
    glfwPollEvents();
    Tasker.executeASyncTask("GLFW_MAIN_THREAD");
}

public void exit() {
    // Terminate GLFW and release the GLFWerrorfun
    glfwTerminate();
    errorCallback.release();
    System.exit(1);
}

public static void main(String[] args) {
    Test test = new Test();
    test.initGL();
    test.gameStart();
}

}

Shader class.

public class Shader {

    public static CharSequence loadShader(String path) {
        StringBuilder shaderSource = new StringBuilder();
        int shaderID = 0;

        try {
            BufferedReader reader = new BufferedReader(new FileReader(path));
            String line;
            while ((line = reader.readLine()) != null) {
                shaderSource.append(line).append("\n");
            }
            reader.close();
        } catch (IOException e) {
            System.err.println("Could not read file.");
            e.printStackTrace();
            System.exit(-1);
        }

        return shaderSource;
    }
}

Vertex and fragment shaders.

// Vertex Shader
#version 400

in vec3 position;
in vec3 color;

out vec3 Color;

void main()
{
    Color = color;
    gl_Position = vec4(position, 1.0);
}

// Fragment shader
#version 400

in vec3 Color;

out vec4 fragColor;

void main()
{
    fragColor = vec4(Color, 1.0);
}

Answer:

I found the solution to the problem using this site here. The issue is that I was not using device coordinates as said in the link. Instead I was Using the cartesian coordinate system.

The fix.

FloatBuffer vertexBufferVAO = BufferUtils.createFloatBuffer(9);
**vertexBufferVAO.put(new float[]{{-0.95f,-0.95f,0, -0.5f,-0.95f,0, -0.95f,-0.5f,0});
vertexBufferVAO.flip();

Question:

As the title suggests, I am trying to render two three-dimensional objects simultaneously using LWJGL, however, only the second one is rendering. I did a bit of searching around and added glPushMatrix() and glPopMatrix() before and after each render. In addition, I am trying to render each object dynamically, rather than statically, with the use of an ArrayList. Actual rendering code, called once every frame:

//clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//this is done dynamically
for (int i = 0; i < MainProgram.renderer.parts.size(); i++) {
    GL11.glPushMatrix();
    BasePart p = MainProgram.renderer.parts.get(i);
    glTranslatef(p.Position.X+MainProgram.CurrentCamera.CoordinateFrame.X, p.Position.Y-MainProgram.CurrentCamera.CoordinateFrame.Y, -MainProgram.zoom+p.Position.Z-MainProgram.CurrentCamera.CoordinateFrame.Z);
    if (MainProgram.renderer.rbd == true) {
        p.Rotation.Y += MainProgram.renderer.ydif;
        p.Rotation.X += MainProgram.renderer.xdif;
    }
    glRotatef(p.Rotation.X, 0f, 1f, 0f);
    glRotatef(-p.Rotation.Y, 1f, 0f, 0f);
    glBegin(GL_QUADS);
        glColor3f(p.BrickColor.r, p.BrickColor.g, p.BrickColor.b); //green
        glVertex3f(p.Size.X, p.Size.Y, -p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y, -p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(-p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(-p.Size.X, -p.Size.Y, -p.Size.Z);
        glVertex3f(p.Size.X, -p.Size.Y, -p.Size.Z);
        glVertex3f(p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(-p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X,-p.Size.Y,-p.Size.Z);
        glVertex3f(-p.Size.X,-p.Size.Y,-p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y,-p.Size.Z);
        glVertex3f(p.Size.X, p.Size.Y,-p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(-p.Size.X, p.Size.Y, -p.Size.Z);
        glVertex3f(-p.Size.X, -p.Size.Y, -p.Size.Z);
        glVertex3f(-p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, p.Size.Y, -p.Size.Z);
        glVertex3f(p.Size.X, p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, -p.Size.Y, p.Size.Z);
        glVertex3f(p.Size.X, -p.Size.Y, -p.Size.Z);
    glEnd();
    GL11.glPopMatrix();
}

Size, Position, Rotation, and CoordinateFrame are all classes with X, Y, and Z values. MainProgram.renderer.parts is an ArrayList that holds the objects to be rendered. I suspect that the problem lies somewhere in the actual rendering (glBegin() to glEnd()), as I don't really see how the rotation could be a problem. Both objects render separately just fine, they just don't both render at the same time. They are two different sizes, and one is larger than the other. No matter the order they are in, however, only the second one renders.


Answer:

I solved the problem: I was clearing the buffers every time I wanted to draw something. I've moved the clear now, and it works.

Question:

In this code i try to render a simple triangle on the screen, but it only shows the red background, i have tried every thing i know to debug but i just can't understand why it doesn't work

Hope somebody can help me, thanks in advance.

public float vertices[] = new float[]
{
        -0.5f,-0.5f,0.0f,1.0f,

        0.0f,1.0f,0.0f,1.0f,

        0.0f,0.5f,0.0f,1.0f,

        0.0f,1.0f,0.0f,1.0f,

        0.5f,-0.5f,0.0f,1.0f,

        0.0f,1.0f,0.0f,1.0f
};



public TEST()
{

}


public int start() throws IOException
{
    glfwInit();

    long window = glfwCreateWindow(1000, 1000, "HAHA", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwShowWindow(window);
    GLFWKeyCallback keycallback = new GLFWKeyCallback()
    {

        @Override
        public void invoke(long window, int key, int scancode, int action, int mods)
        {
            if(key==GLFW_KEY_ESCAPE&&action==GLFW_PRESS)
            {
                glfwSetWindowShouldClose(window, GLFW_TRUE);
            }
        }
    };
    glfwSetKeyCallback(window,keycallback );
    GLFWErrorCallback errorcallback = new GLFWErrorCallback()
    {

        @Override
        public void invoke(int error, long description)
        {
            System.out.println("ERROR CODE: " + error + "  ERROR DESCRITPION: "+description);
        }
    };
    glfwSetErrorCallback(errorcallback);


    GL.createCapabilities();

    glViewport(0, 0, 1000, 1000);
    //////////////////////////
    int VAO = glGenVertexArrays();
    int VBO = glGenBuffers();
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    FloatBuffer buffer = FloatBuffer.allocate(vertices.length);
    buffer.clear();
    buffer.put(vertices);
    buffer.flip();
    glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 4, GL_FLOAT, false, 8, 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, false, 8, 4);
    glEnableVertexAttribArray(1);

    buffer.clear();
    buffer=null;
    System.gc();

    glBindVertexArray(0);
    ///////////////////////
    ///////////////////////
    LoadFile loader = new LoadFile("res/shader.vs", "res/shader.frag");

    int vertexshader = glCreateShader(GL_VERTEX_SHADER);
    int fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vertexshader, loader.readVertex());
    glShaderSource(fragmentshader, loader.readFragment());

    glCompileShader(vertexshader);
    glCompileShader(fragmentshader);

    System.out.println(glGetShaderInfoLog(vertexshader));
    System.out.println(glGetShaderInfoLog(fragmentshader));


    int program = glCreateProgram();

    glAttachShader(program, vertexshader);
    glAttachShader(program, fragmentshader);

    glLinkProgram(program);

    glDeleteShader(vertexshader);
    glDeleteShader(fragmentshader);

    System.out.println(glGetProgramInfoLog(program));
    ///////////////////////////

    boolean running=true;
    while(running&&glfwWindowShouldClose(window)==GLFW_FALSE)
    {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

        glUseProgram(program);

        glBindVertexArray(VAO);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        glBindVertexArray(0);

        glUseProgram(0);

        glfwSwapInterval(1);
        glfwSwapBuffers(window);
    }

    System.out.println(glGetError());
    glfwTerminate();

    return 0;
}

My vertex shader

#version 330 core

layout (location = 0) in vec4 position;
layout (location = 1) in vec4 colorin;

out vec4 colorout;

void main()
{
    gl_Position = position;
    colorout=colorin;
}

My fragment shader

#version 330 core

out vec4 color;

in vec4 colorout;

void main()
{
    color = colorout;
}

Answer:

EDIT: I just saw that this was 1 day old question.. but oh well..

I have my suspicion here:

FloatBuffer buffer = FloatBuffer.allocate(vertices.length);
buffer.clear();
buffer.put(vertices);
buffer.flip();
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

Have you tried replacing this with BufferUtils from lwjgl library itself? It would turn out to be something like this:

FloatBuffer buff = BufferUtils.createFloatBuffer(vertices.length);
buff.put(vertices);
buff.flip();

Or, if you want the manual one..

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
byteBuffer.order(ByteOrder.nativeOrder());
FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
floatBuffer.put(vertices);
floatBuffer.flip();

Question:

I've looked over the following program over and over and cannot find why nothing renders to the screen when I run it:

Game.java:

public class Game {

    private int fbid, fbid2;

    public void start(){
        DisplayManager.init();

        glViewport(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT, 1, -1);

        glMatrixMode(GL_MODELVIEW);

        FloatBuffer fb = BufferUtils.createFloatBuffer(6);
        fb.put(100).put(100).put(100).put(200).put(200).put(200);
        fb.flip();

        fbid = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, fbid);
        glBufferData(GL_ARRAY_BUFFER, fb, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        FloatBuffer fb2 = BufferUtils.createFloatBuffer(9);
        fb2.put(1).put(1).put(1).put(1).put(1).put(1).put(1).put(1).put(1);
        fb2.flip();

        fbid2 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, fbid2);
        glBufferData(GL_ARRAY_BUFFER, fb2, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        while(!DisplayManager.shouldClose()){
            render();
        }

        DisplayManager.destroy();
    }

    public void render(){
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(0, 0, 0, 0);

        glColor3f(1, 1, 1);

        glEnableClientState(GL_VERTEX_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, fbid);
        glVertexPointer(2, GL_FLOAT, 0, 0);

        glEnableClientState(GL_COLOR_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, fbid2);
        glColorPointer(3, GL_FLOAT, 0, 0);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);

        DisplayManager.update();
    }

}

DisplayManager.java:

public class DisplayManager {

    public static final int SCR_WIDTH = 640;
    public static final int SCR_HEIGHT = 480;

    public static final int FPS = 30;

    public static void init(){
        try {
            Display.setDisplayMode(new DisplayMode(SCR_WIDTH, SCR_HEIGHT));
            Display.setTitle("StepBattler");
            Display.setResizable(false);
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
            Display.destroy();
            System.exit(1);
        }
    }

    public static void update(){
        Display.update();
        Display.sync(FPS);
    }

    public static void destroy(){
        Display.destroy();
        System.exit(0);
    }

    public static boolean shouldClose(){
        return Display.isCloseRequested();
    }

    public static boolean shouldResize(){
        return Display.wasResized();
    }

}

When I run the screen, I just get a window filled with black, and I cannot understand why a white triangle won't render to the window. I've messed around with glClearColor(), and changing its values does succeed in changing the window background color, but I can't make a white triangle appear in the window. Also, I tried using glBegin()...glEnd() to render in immediate mode, with none of the code having to do with buffers in there, and it still didn't render anything. I'm really confused about this, what am I missing?


Answer:

The arguments in you glOrtho() call look to be in the wrong order:

glOrtho(0, 0, DisplayManager.SCR_WIDTH, DisplayManager.SCR_HEIGHT, 1, -1);

The signature of glOrtho(), based on the man page, is:

void glOrtho(GLdouble left, GLdouble right,
             GLdouble bottom, GLdouble top,
             GLdouble nearVal,  GLdouble farVal);

Since you're passing 0 for both left and right, the result would be an invalid projection matrix.

The correct call for your case is:

glOrtho(0, DisplayManager.SCR_WIDTH, 0, DisplayManager.SCR_HEIGHT, 1, -1);

Question:

To create a virtual world I am using Lightweight Java Game Library (LWJGL) (Java + OpenGL). I want to load my terrains into graphics card memory on worker thread, while on main thread I want to take these, already loaded terrains, and render them. In order to do that I have to create Vertex Array Object (VAO), create Vertex Buffer Object (VBO), add VBO into VAO attribute list and finally render everything. This works perfectly on single-threaded system, however I am having problems implementing it on multi-threaded system. I know that VBO can be shared between OpenGL contexts, while VAO cannot be shared (reference1; reference2). Therefore to accomplish my goal I:

  1. create VAO on main thread,
  2. create VBO on worker tread by using these methods:

    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, ID); int ID = GL15.glGenBuffers(); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); GL20.glVertexAttribPointer(attributeNr, coordSize, GL11.GL_FLOAT, false, 0, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

  3. render it on main thread, however I get this exception:

Exception in thread "main" org.lwjgl.opengl.OpenGLException: Cannot use offsets when Element Array Buffer Object is disabled

I am sure that I do not render not loaded terrains, because I load terrains when they are outside render scope. I have read many articles, questions and blogs about OpenGL shared contexts and concurrency, but did not managed to find a solution. I would be very grateful for any help.


Answer:

As you already stated, VAOs are NOT shared between contexts, so it is also impossible to modify them from multiple threads.

GL20.glVertexAttribPointer(attributeNr, coordSize, GL11.GL_FLOAT, false, 0, 0); 

is modifying the VAO state, thus it has to be called from the main thread.

It is perfectly fine to have the data upload (glBufferData) in a separate thread, but constructing the VAO can only be done from the main thread.

Question:

I am working on a project in LWJGL, and the OpenGL setup works on 2.0, but whenever I try to render on LWJGL 3.0, it returns Function is not supported.

The methods that have returned this error:

  1. glColor3f();
  2. glVertex3f();
  3. glColorPointer();
  4. glVertexPointer();
  5. glBegin();
  6. glEnd();

Our project setup is fine, and the window shows without these methods, but whenever we use them, LWJGL spits out that error. We need help and quick, so if you know why this is happening, please tell me.


Answer:

According to this: Why a new version These version(I mean 2.x and 3.x) have not backward compatibillity. Also there is some major changes to API between these version. So you can not just change library.

Question:

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


Answer:

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 
        }
    }
}

Question:


Answer:

I think that enumerating over a series of BufferedImage[] is your best bet for a homemade solution. Someone made a simple example over here. Pull the images from your spritesheet to create the array, then just swap between the sprites as desired. Possibly building an AnimationManager to move between Animations could help.

Question:

I'm working on a simple Minecraft-like game but I used to use some old shaders system and I wanted to start using modern shaders, but I got stuck using renders and nothing appears on screen...

I've tried different things:

  • glGetError() return 0
  • I tried to return vec4(1,0,1,1) in the fragment shader but it didn't worked so I think it's a mistake in the vertex shader...

So could you help me getting where is my error ?

Here are the codes: https://pastebin.com/dWJQkFZu

Here is my renderLoop:

public void render(){
    //check for resize
    if(Display.wasResized()){
        glViewport(0, 0, Display.getWidth(), Display.getHeight());
        guiManager.recalculate();
    }

    //create perspective
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    GLU.gluPerspective(Camera.fov, (float)Display.getWidth()/(float)Display.getHeight(), 0.1f, 1000000.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    cam.render();
    world.render();
    skybox.render(cam.player.position);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 1, -1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_ALPHA_TEST);
    glAlphaFunc(GL_GREATER, 0.5f);
    if(Camera.debug){
        FontManager.getDefaultFont().drawString(0, 0, "Debug - SaintsCube v-A0.5");
        FontManager.getDefaultFont().drawString(0, FontManager.getDefaultFont().getLineHeight()+1, "x: "+Math.floor(player.position.x));
        FontManager.getDefaultFont().drawString(0, FontManager.getDefaultFont().getLineHeight()*2+2, "y: "+Math.floor(player.position.y));
        FontManager.getDefaultFont().drawString(0, FontManager.getDefaultFont().getLineHeight()*3+3, "z: "+Math.floor(player.position.z));
        FontManager.getDefaultFont().drawString(0, FontManager.getDefaultFont().getLineHeight()*4+4, "yaw: "+Math.floor(player.rotation.x*-1));
        FontManager.getDefaultFont().drawString(0, FontManager.getDefaultFont().getLineHeight()*5+5, "pitch: "+Math.floor(player.rotation.y));
    }
    guiManager.render();
    glDisable(GL_ALPHA_TEST);
}

And my shaders:

chunk.vs:

#version 330

in vec3 position;
in vec2 texcoord;
in vec4 color;

uniform mat4 MVP;

out vec2 pass_texcoord;
out vec4 pass_color;

void main() {
    pass_texcoord = texcoord;
    pass_color = color;

    gl_Position = MVP * vec4(position, 1.0);
}

chunk.fs:

#version 330

out vec4 fragcolor;

uniform sampler2D sampler;

in vec2 pass_texcoord;
in vec4 pass_color;

void main() {
    vec4 texturecolor = texture(sampler, pass_texcoord) * pass_color;
    if(texturecolor.a <= 0.5){
        discard;
    }
    fragcolor = texturecolor;
}

Please help me :)


Answer:

If you want to start using the modern shader way, you can't use immediate methods. Everything will be calculated in the shader ( which you have to write yourself, no opengl predefined goodness ). So instead of calling

    glTranslate3f(x, y, z);

you'll have to create your own Model Matrix which gets send to the shader, where it is applied to the position of the models vertices. The whole point of Modern OpenGL is to minimize the Interaction with it. Instead of having CPU and GPU work hand in hand ( GPU wants to run faster, CPU is bottlenecking ), you let the CPU do some math, and when done push it to the GPU in one go.

Whilst your Vertex Shader was already expecting the Matrix, it didnt get it because it was missing in your Java code, you never passed any Matrix.

uniform mat4 MVP;

Big Example:

Vertex Shader Code:

#version 330 core

in vec4 position;
in vec4 color;

uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;

out vec4 vertexColor;

void main() {
    // Just pass the color down to the fragment shader
    vertexColor = color;

    // Calculate the Model, View, Projection matrix into one ( in this order, right to left )
    mat4 mvp = projection * view * model;

    // Calculate the position of the vertex
    gl_Position = mvp * vec4(position.xyz,1);
}

Fragment Shader Code:

#version 330 core

in vec4 vertexColor;

out vec4 fragColor;

void main() {
    fragColor = vec4(vertexColor.xyz,1);
}

I haven't seen your Shader compiling code, but ill assume its right... ( Generate Shader id's, put source into shaders, compile, generate program and attach both shaders to it )

After compilation you'll have to tell OpenGL where the output color goes:

glBindFragDataLocation(program, 0, "fragColor");

When you load your model's, you'll also want to switch to modern Vertex Buffer Array's. By default a VBA can store 16 Vertex Buffer Object's which can contain pretty much any data you want to store for a vertex ( position, color, texture coordinate, giv'em names if you so desire... )

For this loading part, i use one single float array ( later one VBO ) holding all data in sorted order ( see https://www.khronos.org/opengl/wiki/Vertex_Specification_Best_Practices for more info on how to store your data )

In this example i will only give a vertex 3 floats for position, and 3 floats for color. You'll also need to specify an Index Buffer Object

float[] data = {
   // x,   y,   z,    r,  g,  b
    -1f,  1f,  0f,   1f, 0f, 0f,// Left  top   , red  , ID: 0
    -1f, -1f,  0f,   0f, 1f, 0f,// Left  bottom, blue , ID: 1
     1f, -1f,  0f,   0f, 0f, 1f,// Right bottom, green, ID: 2
     1f,  1f,  0f,   1f, 1f, 1f // Right left  , white, ID: 3
};

byte[] indices = {       
    0, 1, 2,// Left bottom triangle
    2, 3, 0 // Right top triangle
};

Now you'll wanna load the data, and specify where what is.

// You have to use LWJGL3's way of memory management which is off-heap
// more info: https://blog.lwjgl.org/memory-management-in-lwjgl-3/
try(MemoryStack stack = MemoryStack.stackPush()){

    FloatBuffer dataBuffer = stack.mallocFloat(data.length);
    dataBuffer.put(data);
    dataBuffer.flip();

    indicesCount = indices.length; // Store for later use ( needed for rendering )
    ByteBuffer indicesBuffer = stack.malloc(indicesCount);
    indicesBuffer.put(indices);
    indicesBuffer.flip();

    vaoId = glGenVertexArrays();
    glBindVertexArray(vaoId);

    vboId = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vboId);
    glBufferData(GL_ARRAY_BUFFER, dataBuffer, GL_STATIC_DRAW);

    // Vectors
    int program_in_position = glGetAttribLocation(program, "position");
    glEnableVertexAttribArray(program_in_position);
    glVertexAttribPointer(program_in_position, 3, GL_FLOAT, false, 6*(Float.SIZE / Byte.SIZE), alreadyTakenBytes);

    // Colors
    int colorAttPos= glGetAttribLocation(program, "color");
    glEnableVertexAttribArray(colorAttPos);
    glVertexAttribPointer(colorAttPos, 3, GL_FLOAT, false, 6*(Float.SIZE / Byte.SIZE), 3*(Float.SIZE / Byte.SIZE));

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // Now the Index VBO
    indexVBO = glGenBuffers();
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

Now for rendering:

    glBindVertexArray(vaoId);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO);
    glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_BYTE, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(0);
    glBindVertexArray(0);

( Yes thats really already it ) Jokes aside, yes thats a bunch of code, learn it, love it. And we haven't even used any Matrix with the Shader, but thats really simple. Everytime you want to push a Matrix ( in form of a FloatBuffer ) to the Shader, using the UniformLocation

// This needs to happen only ONCE ( position stays the same )
int uniModel = glGetUniformLocation(program, "model");

// Create a Matrix
Matrix4f model = Matrix4f.translate(0, 0, -10);

// Create Float Buffer from Matrix4f
FloatBuffer fb = model.toBuffer();

// Push FloatBuffer to Shader
glUniformMatrix4fv(uniModel, false, fb);

The only problem there is, you'll need a Matrix4f Class with all the functions you need... and once again thats your own work, no fancy OpenGL calls. Dont be discouraged tho, there are several Math Libraries out there ( Example: https://github.com/SilverTiger/lwjgl3-tutorial/blob/master/src/silvertiger/tutorial/lwjgl/math/Matrix4f.java )

Question:

We're supposed to use LWJGL 2.9.3 to create a simple application that displays a wireframe object. I created a test class based off of the first example code from http://www.glprogramming.com/red/chapter01.html What I end up with is a program that flashes a white square for a brief moment and then disappears. I'm not sure what I'm doing wrong.

Here's the test code:

package Test.LWJGL;

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import static CS355.LWJGL.LWJGLSandbox.DISPLAY_HEIGHT;
import static CS355.LWJGL.LWJGLSandbox.DISPLAY_WIDTH;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.glFlush;


public class LWJGLTest {
    public static void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3f(1.0f, 1.0f, 1.0f);
        glOrtho(0, 1.0, 0.0, 1.0, -1.0, 1.0);
        glBegin(GL_POLYGON);
            glVertex3f(0.25f, 0.25f, 0.0f);
            glVertex3f(0.75f, 0.25f, 0.0f);
            glVertex3f(0.75f, 0.75f, 0.0f);
            glVertex3f(0.25f, 0.75f, 0.0f);
        glEnd();
        glFlush();
    }

    public static void main(String[] args)  {
        try {
            Display.setDisplayMode(new DisplayMode(DISPLAY_WIDTH,DISPLAY_HEIGHT));
            Display.setFullscreen(false);
            Display.create();

            glClearColor(0.0f,0.0f,0.0f,0.0f);

            while(!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
                if(Display.isVisible()) {
                    render();
                }
                else {
                    if(Display.isDirty()) {
                        render();
                    }
                    try {
                        Thread.sleep(100);
                    }
                    catch(InterruptedException ex) {}
                }
                Display.update();
                Display.sync(60);
            }
        }
        catch(Exception ex) {
            ex.printStackTrace();
        }
        finally {
            Mouse.destroy();
            Keyboard.destroy();
            Display.destroy();
        }
    }
}

Answer:

OpenGL is a state machine. This means, there are lots of states which you can set, and which will influence the final rendering result in some well-defined way. These states are never automatically reset, they just stay as you set them, until you change them. There are no such things as "frames" or "scene objects", just a stream of state-setting or drawing commands.

OpenGL's matrix stack is also just a state. The function glOrtho will multiply the current top element of the currently selected matrix stack with that ortho matrix, and will replace the top element by that result.

Assume the Ortho matrix is called O. Initially, all of GL's matrices will be identiy. So when you call render for the first time, you'll get: M = M * O = I * O = O. However, the second time, you will get M = M * O = O * O. And so on.

You have to explicitely reset your matrix back to identity at the beginning of the frame:

glLoadIdentity();
glOrtho(...);

You should be aware that the code you are using is not very good. It uses the MODELVIEW stack for projection matrices, which is meant to go to GL_PROJECTION. But before you try to learn about that staff, be warned that all of that is completely deprecated in the GL since a decade. Modern core versions of OpenGL do not support these functions at all.

Question:

I want to create a 2D Game with Java and LWJGL. It is a retro styled RPG game. So there is a really big map(about 1000x1000 or bigger). I want to do it with tiles but I don't know how to save it/how to render it.

I thought at something like a 2D-Array with numbers in it and the render just sets the right tile at the right place. But i think the bigger the map gets the more it will slow down. I hope you can help me. :)

My second suggestion was to make a big image and just pick a part of it(the part where the player is) but than its hard to know where I have to do a collision detection, so this ist just an absurd idea.

Thank you for your suggestions!


Answer:

As one of the comments mentioned, this subject is far too large to be easily covered with a single answer. But I will give you some advice from personal experience.

As far as saving the map in a 2D array, as long as the map is fairly simple in nature there is no problem. I have created similar style maps (tiled) using 2D integer arrays to represent the map. Then have a drawing method to render the map to an image which I can display. I use multiple layers so I just render each layer of the map separately. Mind you most of my maps are 100x100 or smaller.

I would recommend for such large maps to use some sort of buffer. For example, render only the playable screen plus a slight offset area outside of the map. E.g. if your screen if effectively 30x20 tiles, render 35x25, and just change what is rendered based on current location. One way that you could do this would be to load the map in "chunks". Basically have your map automatically break the map into 50x50 chunks, and only render a chunk if you get close enough that it might be used.

I also recommend having the drawing methods run in their own thread outside of the main game methods. This way you constantly draw the map, without having random blinking or delays.

Question:

I'm using java and LWJGL/openGL to create some graphics. For rendering I use the following:

Constructor of RawModel:

public RawModel(int vaoID, int vertexCount, String name){
    this.vaoID = vaoID;
    this.vertexCount = vertexCount;
    this.name = name;
}

Renderer:

public void render(Entity entity, StaticShader shader){
        RawModel rawModel = entity.getRaw(active);
        GL30.glBindVertexArray(rawModel.getVaoID());
        GL20.glEnableVertexAttribArray(0);
        GL20.glEnableVertexAttribArray(1);
        GL20.glEnableVertexAttribArray(3);
        Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(),
            entity.getRotX(), entity.getRotY(), entity.getRotZ(), entity.getScale());
        shader.loadTransformationMatrix(transformationMatrix);
        GL11.glDrawElements(GL11.GL_TRIANGLES, rawModel.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
        GL20.glDisableVertexAttribArray(0);
        GL20.glDisableVertexAttribArray(1);
        GL20.glDisableVertexAttribArray(3);
        GL30.glBindVertexArray(0);
}

I'm using GL11.GL_TRIANGLES cuz that's how I can make models' lines show up instead of faces. But when I set color for a vertex, it just colors surrounding lines to the color set, in some cases all of it's lines just take the color of surrounding vertices. How could I make it so that it kind of combines those 2 colors depending on the distance of each vertex and the colors?

Fragment shader:

#version 400 core

in vec3 colour;
in vec2 pass_textureCoords;

out vec4 out_Color;

uniform sampler2D textureSampler;

void main(void){

    vec4 textureColour = texture(textureSampler, pass_textureCoords);

    //out_Color = texture(textureSampler, pass_textureCoords);
    out_Color = vec4(colour, 1.0);

}

Vertex shader:

#version 400 core

in vec3 position;
in vec2 textureCoords;
in int selected;

out vec3 colour;
out vec2 pass_textureCoords;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;

void main(void){

    gl_Position = projectionMatrix * viewMatrix * transformationMatrix * vec4(position, 1.0);
    pass_textureCoords = textureCoords;
    if(selected == 1){
        colour = vec3(200, 200, 200);
    }
    else{
        colour = vec3(0, 0, 0);
    }
    gl_BackColor = vec4(colour, 1.0);
}


Answer:

I'm using GL11.GL_TRIANGLES cuz that's how I can make models' lines show up instead of faces.

Well, GL_TRIANGLES is for rendering triangles, which are faces. If you only want the models' lines, you can use one of the line drawing modes (GL_LINES, GL_LINE_LOOP, GL_LINE_STRIP etc).

However, a better way is to enable

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

, which makes only the outline of the triangles show up.

You can switch it off again with

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

How could I make it so that it kind of combines those 2 colors depending on the distance of each vertex and the colors?

I'm not sure what you mean with this; by default values passed from the vertex shader to the fragment shader are already interpolated across the mesh; so the color a fragment receives already depends on all the vertices' color and distance.


Edit:

In the vertex shader:

if(selected == 1){
    colour = vec3(200, 200, 200);
}

I assume you want to assign an RGB value of (200, 200, 200), which is a very light white. However, OpenGL uses floating-point color components in the range 0.0 to 1.0. Values that go above or below this range are clipped. The value of colour is now interpolated across the fragments, which will receive values with components far higher than 1.0. These will be clipped to 1.0, meaning all your fragments appear white.

So, in order to solve this issue, you have to instead use something like

colour = vec3(0.8, 0.8, 0.8);

Question:

I am attempting to render a cube with different colors on certain sides as a practice exercise, but the problem is that as I rotate the cube along the y-axis, I can still see the different color side through the sides facing the camera. I've tried splitting up the code into seperate glBegin() blocks for each side and I've tried looking around on google for the answer with no luck. According to the Microsoft documentation on glColor3f, "glcolor3 variants specify new red, green, and blue values explicitly and set the current alpha value to 1.0 (full intensity) implicitly.", so the transparency shouldn't be a problem...

Here is the picture representing the problem

Here is the rendering code for the cube:

@Override public void render() 
{
    glPushMatrix( );
    {
        glTranslatef( 0, 0, -4 );
        glRotatef( x, 0, 1, 0 );

        glColor3f( 0f, 1f, 0f );

        glBegin( GL_QUADS );
        {
            glVertex3f( -1, 1, 1 );
            glVertex3f( -1, -1, 1 );
            glVertex3f( 1, -1, 1 );
            glVertex3f( 1, 1, 1 );

            glVertex3f( -1, 1, -1 );
            glVertex3f( -1, -1, -1 );
            glVertex3f( 1, -1, -1 );
            glVertex3f( 1, 1, -1 );

            glVertex3f( -1, 1, -1 );
            glVertex3f( -1, 1, 1 );
            glVertex3f( 1, 1, 1 );
            glVertex3f( 1, 1, -1 );

            glVertex3f( -1, -1, -1 );
            glVertex3f( -1, -1, 1 );
            glVertex3f( 1, -1, 1 );
            glVertex3f( 1, -1, -1 );

            glVertex3f( -1, 1, -1 );
            glVertex3f( -1, -1, -1 );
            glVertex3f( -1, -1, 1 );
            glVertex3f( -1, 1, 1 );

            glColor3f( 1f, 0f, 0f );
            glVertex3f( 1, 1, -1 );
            glVertex3f( 1, -1, -1 );
            glVertex3f( 1, -1, 1 );
            glVertex3f( 1, 1, 1 );
        }

        glEnd( );
    }

    glPopMatrix( );
}

Here is my render loop:

protected void render( )
{
    glClear( GL_COLOR_BUFFER_BIT );
    glLoadIdentity( );

    for ( IGameObject gameObject : gameObjects )
        gameObject.render( );

    glfwSwapBuffers( window );
}

Answer:

It looks like you're not using depth testing.

OpenGL draws shapes in the order that you tell it to, so if you draw the red face last, its fragments (i.e. pixels) overwrite the green ones that were drawn earlier. Since you (presumably) want to see the faces that are "in front" to actually appear in front, you have to tell OpenGL not to draw fragments that are "behind" things that have already been drawn.

Replace the glClear( GL_COLOR_BUFFER_BIT ) line with:

glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LESS );
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BIT );

This tells OpenGL that each time it's about to draw a fragment, it should compare its depth against the depth of what's already been drawn, and discard the new fragment if it's farther away than the old one. It also clears the depth buffer so that initially every pixel on the screen is "infinitely" far away, so that the faces of the cube will all be in front of the background. This will prevent the red face from appearing when there's a green one closer to the camera.

Question:

Working with LWJGL's OpenGL version 1.1 and 2D Textures, I find myself stuck...

For some reason, the LWJGL engine will not render loaded textures on the 2D Layer... Instead, I get a white square..

I'm assuming that it is highly likely that I'm missing something somewhere in my code.. Below is the entire code, as related to such event..

Loading up the OpenGL Environment:

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnable(GL_TEXTURE_2D);
glClearColor(0, 0, 0, 1);
glClearDepth(1);
glClearStencil(0);
glColor3f(1.0f, 1.0f, 1.0f);

Entering the 2D Drawing Mode (functional for the purpose of drawing a solid colored square - tested via the glcolor function followed by glvertex calls for dimensions):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

Loading the image (This has been verified to be functional, via a Swing testing environment):

this.ref = ref;
if (!fmt.isImage()) {
    return;
}
f = new File("file/path/to/image.gif");
if (!f.exists() || !f.canRead()) {
    return;
}
BufferedImage tmp = ImageIO.read(f);
WritableRaster raster = WritableRaster.createInterleavedRaster(DataBuffer.TYPE_BYTE, tmp.getWidth(), tmp.getHeight(), 4, null);
img = new BufferedImage(glColorModel, raster, false, new Hashtable());
Graphics g = img.getGraphics();
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 0, img.getWidth(), img.getHeight());
g.drawImage(tmp, 0, 0, null);
g.dispose();

Converting the image data:

byte[] data = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
buff = ByteBuffer.allocateDirect(data.length);
buff.put(data);
buff.flip();

Moving the data into the OpenGL Buffers:

id = glGenTextures();
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
             GL_UNSIGNED_BYTE, buff);

Drawing the texture on the 2D surface:

glBindTexture(GL_TEXTURE_2D, tex.getId());
glTranslatef(x, y, 0);
glBegin(GL_QUADS);
{
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(w, 0);
    glVertex2f(w, 0);
    glTexCoord2f(w, h);
    glVertex2f(w, h);
    glTexCoord2f(0, h);
    glVertex2f(0, h);
}
glEnd();

I'm not exactly experienced with LWJGL, or even OpenGL for that matter, however, this code looks proper to me, as a Java developer and having studied a few bits of example source codes...

Ultimately, my question is "How can I fix this?" I added the "glEnable(GL_TEXTURE_2D);" while typing this, which had caused the drawing area to go from white to a blood red color...


Answer:

In OpenGL texture coordinates are given from [0,0] (meaning bottom left corner) to [1,1] (upper right corner). When texture coordinates are out of this range and GL_TEXTURE_WRAP_[R|S|T] is set to GL_REPEAT (as by default), the actual lookup positions into the texture are calculated by

lookup.xy = fract(texCoord.xy)

In the special case given here, the texture coordinates range from 0-w, which will result in w repetitions of the texture. Since the viewports width is also set to w, each of this repetitions will only be of 1px width.

Question:

I have made a simple application in lwjgl and created simple gui. For now I have frame and panel. But there is a problem. Because (Display 800x600) when I make panel on Panel(x,y,w,h) (0,0,64,64) everything works fine, but when I create it on other position (x,y where point 0,0 is in left upeper corner) it render moved panel. The white space is my panel which should change color when I drag mouse on it. It is created on (417,417,64,64), but it's rendered on somethink like (90,90). I have rendered fonts to show all of itss positions. The blue box I draw on this image is where it should be and it looks like there the panel is, because the white space is changing color when I drag mouse there, but this white space should be there. My code looks like that: I am adding all components to HashMap like Panels.

glColor3f(backgroundColor.getRed(), backgroundColor.getGreen(),
                backgroundColor.getBlue());
        if (hasFocus()) {
            glColor3f(1f, 0f, 0f);
        }
        glPushMatrix();
        glRecti(getX(), getY(), getWidth(), getHeight());
        glPopMatrix();

And initGL method:

glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glScalef(1.0f, 1.0f, 1.0f);
        glOrtho(0, 800, 600, 0, 1, -1);
        glFrustum(-1, 1, -1, 1, 0.0, 40.0);
        glViewport(0, 0, Display.getWidth(), Display.getHeight());
        glMatrixMode(GL_MODELVIEW);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glShadeModel(GL_SMOOTH);

Answer:

glRecti doesn't work that way it expects the coordinates of the corners

so instead you should do:

glRecti(getX(), getY(), getX()+getWidth(), getY()+getHeight());

Question:

I have two VBOs I am trying to render, both of them should have two different positions on the screen. When I try to modify the position of one of the VBOs, it gets transferred to the other.

Example- I change the y position of object 2, both object 1 and object 2 now exist at that y position.

My code for transforming the VBOs:

    Matrix4f.scale(scale, modelMatrix, modelMatrix);
    Matrix4f.translate(position, modelMatrix, modelMatrix);
    Matrix4f.rotate(Toolkit.degToRad(rotation.x), new Vector3f(1f,0f,0f), modelMatrix, modelMatrix);
    Matrix4f.rotate(Toolkit.degToRad(rotation.y), new Vector3f(0f,1f,0f), modelMatrix, modelMatrix);
    Matrix4f.rotate(Toolkit.degToRad(rotation.z), new Vector3f(0f,0f,1f), modelMatrix, modelMatrix);

Please note that position, rotation, and scale are all Vector3fs, and modelMatrix is well, the model matrix.

Also, Toolkit.degToRad is similar to a Math.toRadians() type method.

My code for passing info to the shaders:

    //Apply Transformations
    camera.reset();
    camera.transform();

    glUseProgram(ss.pId);

    //Projection Matrix
    camera.projectionMatrix.store(camera.matrixBuffer);
    camera.matrixBuffer.flip();
    projection.Matrix4(camera.matrixBuffer);
    //View Matrix
    camera.viewMatrix.store(camera.matrixBuffer);
    camera.matrixBuffer.flip();
    view.Matrix4(camera.matrixBuffer);

    glUseProgram(0);

    //Apply Transformations
    obj.reset();
    obj.transform();

    glUseProgram(ss.pId);

    //Object 1
    obj.modelMatrix.store(camera.matrixBuffer);
    camera.matrixBuffer.flip();
    model.Matrix4(camera.matrixBuffer);

    glUseProgram(0);

    //Apply Transformations
    obj2.reset();
    obj2.transform();


    glUseProgram(ss.pId);

    obj2.modelMatrix.store(camera.matrixBuffer);
    camera.matrixBuffer.flip();
    model.Matrix4(camera.matrixBuffer);

    glUseProgram(0);

obj and obj2 are VBOs, model is a shader uniform, camera is the camera, and ss is the shader program and ss.pId is the program id.

My code for drawing the VBOs: Note that this is found in obj and obj2 and is used like this

obj.draw();
obj2.draw();

And here is the drawing method

    GL20.glUseProgram(ss.pId);

    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, t.id);

    GL30.glBindVertexArray(g.vaoId);
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(1);
    GL20.glEnableVertexAttribArray(2);

    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, g.vboiId);

    GL11.glDrawElements(GL11.GL_TRIANGLES, g.indices, GL11.GL_UNSIGNED_BYTE, 0);

    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    GL20.glDisableVertexAttribArray(0);
    GL20.glDisableVertexAttribArray(1);
    GL20.glDisableVertexAttribArray(2);
    GL20.glUseProgram(0);


    GL20.glUseProgram(ss.pId);

    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, t.id);

    GL30.glBindVertexArray(g.vaoId);
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(1);
    GL20.glEnableVertexAttribArray(2);

    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, g.vboiId);

    GL11.glDrawElements(GL11.GL_TRIANGLES, g.indices, GL11.GL_UNSIGNED_BYTE, 0);

    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
    GL20.glDisableVertexAttribArray(0);
    GL20.glDisableVertexAttribArray(1);
    GL20.glDisableVertexAttribArray(2);
    GL20.glUseProgram(0);

g is the geometry class,

g contains indices buffer id, and vertices buffer id. t contains texture and id.

Thanks for your help.


Answer:

Your whole program structure looks fairly unusual, and I believe this is part of what is tripping you up. For example, while I'm all for encapsulation, wrapping a single uniform in an object, like you appear to be doing with your model variable, is pushing it too far IMHO. A uniform value is really an attribute of a shader program, not an independent object.

Anyway, without going too deep into design aspects, I believe your main problem is in this code sequence (with parts omitted):

// calculate camera.matrixBuffer for object 1
model.Matrix4(camera.matrixBuffer);
...
// calculate camera.matrixBuffer for object 2
model.Matrix4(camera.matrixBuffer);

The second of these calls will overwrite the value written in the first one, without the first one ever being used. When you later render object 1 and object 2, they will both use the second value for the uniform.

As long as you use the same shader program for both objects (which is a good thing, unless they really need different shaders), you will have to set the uniform value before you draw each of the objects.

So the calls to set the uniforms should go into the draw function, where the structure will look roughly like this:

// calculate camera.matrixBuffer for object 1
model.Matrix4(camera.matrixBuffer);
obj1.draw();
...
// calculate camera.matrixBuffer for object 2
model.Matrix4(camera.matrixBuffer);
obj2.draw();

Question:

I have an issue in my project where I am trying to draw a pyramid on screen but the depth is not being displayed.

public void create(float[] vertices, int[] indices, int numberOfVertices, int numberOfIndices) {
        indexCount = numberOfIndices;
        vao = gl.genVertexArrays(); 
        gl.bindVertexArray(vao);

        IntBuffer indicesBuffer = factory.create(indices);
        ibo = gl.genBuffers();
        gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);

        FloatBuffer verticesBuffer = factory.create(vertices);
        vbo = gl.genBuffers();
        gl.bindBuffer(GL_ARRAY_BUFFER, vbo);
        gl.bufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);

        gl.vertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(0);

        gl.bindBuffer(GL_ARRAY_BUFFER, 0);          
        gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        gl.bindVertexArray(0);
    }

I create my mesh object with following code where Vertices and Indices are defined as :

private void createTriangles() {
    float[] vertices = new float[] { 
            //x     y      z
           -1.0f, -1.0f, 0.0f, //0
            0.0f,  0.0f, 1.0f, //1
            1.0f, -1.0f, 0.0f, //2
            0.0f,  1.0f, 0.0f  //3
    };

    int[] indices = new int[] {
        0, 3, 1,
        1, 3, 2, 
        2, 3, 0,
        0, 1, 2
    };
    mesh.create(vertices, indices, 12, 12);
}

In order to display them to screen I call my render function from my game loop which is defined as.

public void render() {
    gl.bindVertexArray(vao);
    gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    gl.drawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
    gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    gl.bindVertexArray(0);
}

To create my FloatBuffer and IntBuffer I have a factory class defined as.

public class BufferFactory {
    public IntBuffer create(int[] indices) {
        IntBuffer buffer = BufferUtils.createIntBuffer(indices.length);
        buffer.put(indices);
        buffer.flip();
        return buffer;
    }

    public FloatBuffer create(float[] vertices) {
        FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length);
        buffer.put(vertices);
        buffer.flip();
        return buffer;
    }

}

So the issue i'm getting is that it should have drawn four triangles to screen to form a pyramid, however my output looks like this.

I have rotated the image to try and see the depth but it is a flat object.

I have tried to identify where the issue may be coming from by attempting to draw each triangle individually by changing my render method to gl.drawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0); So that it only draws one triangle. I have tried to draw all four faces individually and all are drawn to screen.


Answer:

I found the issue. I was originally scaling the triangle such that

model.scale(new Vector3f(0.2f, 0.2f, 0.0f));

As a result the z axis was being multiplied by 0. Silly mistake, hope this helps someone in the future.

Question:

I've got some code that's supposed to render text to a texture so that I don't have to render each character each draw step, and can instead use the rendered texture. However, my code does not as it's supposed to, and the texture is left blank. After a few hours of trying different things, I cannot figure it out, and so I bring the question to you.

I'm fairly certain the problem is somewhere in this code chunk below, but if you think it's not, I'll gladly post whatever other samples of code you would like. I just really want to get this done already. The exact problem is that the created texture is blank, and never is rendered to (it seems like). I've tried just drawing one massive quad on it, and that didn't seem to work either.

Edit: After flipping the buffer, I can get some color to be rendered to the texture, but it's all just one color (which makes me think it's only sampling one pixel), and I can't figure out how to get the actual image I want to render to show on it.

public Text(String text, int x, int y, Font font, float size, GUIComponent parent, Binding binding) {
    super(null, x, y, font.getStringWidth(size, text), font.getStringHeight(size), parent, binding, false);
    this.text = text;
    this.font = font;
    this.width = font.getStringWidth(size, text);
    this.height = font.getStringHeight(size);
    int fbo = glGenFramebuffers();
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    int tex = glGenTextures();
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
    IntBuffer intBuffer = BufferUtils.createIntBuffer(1);
    intBuffer.put(GL_COLOR_ATTACHMENT0);
    intBuffer.flip();
    glDrawBuffers(intBuffer);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        throw new RuntimeException("Something really bad happened");
    }
    //RENDER
    RenderUtil.recalibrate(width, height, 1.0f); //Does glViewport(width, height), and some matrix stuff
    Camera.updateShader("textshader", "projection", false); //Update projection matrix
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    int width = 0;
    float f = this.width / 1.0f;
    int charWidth = 0;
    for (char c : text.toCharArray()) {
        font.bind(0, c % 256); // calls glBindTexture, this works, have tested
        //ResourceManager.getTexture("grassroadedger1").bind(0, 0);
        charWidth = font.getCharWidth(size, c);
        //float[] verts = new float[] { -1f, 1f, 1f, 1f, 1f, -1f, -1f, -1f };
        float[] verts = new float[] { -1.0f + (width / f), 1.0f, 1.0f + ((width + charWidth) / f), 1.0f, 1.0f + ((width + charWidth) / f), -1.0f, -1.0f + (width / f), -1.0f };
        width += charWidth;
        glBindBuffer(GL_ARRAY_BUFFER, vertexPointer);
        glBufferSubData(GL_ARRAY_BUFFER, 0, RenderUtil.createBuffer(verts));
        glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RenderUtil.getIndicesPointer());
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    //END
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    RenderUtil.recalibrate(Window.getWidth(), Window.getHeight(), LuminaEngine.getGlobalImageScale());
    this.setTexture(new Texture(tex, "text_"+size+"_"+text));
}

FragmentShader

    #version 330 core
    in vec2 uv;

    layout(location = 0) out vec4 color;

    uniform sampler2D sampler;

    void main(){

        color = texture2D( sampler, uv );
    }

Vertex Shader

    #version 330 core

    layout(location = 0) in vec3 vertices;
    layout(location = 1) in vec2 textures;

    out vec2 uv;

    uniform mat4 projection;

    void main(){

         gl_Position =  projection * vec4(vertices,1);

         uv = textures;
    }

Edit: After flipping the intBuffer for drawBuffers, I can get some things to appear, mostly just a big blue square. Progress nonetheless


Answer:

You never defined an array of generic vertex attribute data for the texture coordinates (in vec2 textures;).

Add something like this to your code:

int texCoordBuffer;
glGenBuffers(1, texCoordBuffer);

float[] texCoord = new float[] { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };

glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, RenderUtil.createBuffer(texCoord), GL_STATIC_DRAW);

int tax_attr_i = 1; // layout(location = 1) in vec2 textures;
glVertexAttribPointer(tax_attr_i, 2, GL_FLOAT, false, 0, 0);

Question:

I am currently working on sub dividing my icosphere and it ends up looking crazy (see below). It works fine if I don't subdivide it at all so I believe the error is either in my recursion for loop or the getMiddlePoint method (see below). My thought on why this is happening is that I am adding the vertices and indices in the wrong order. If this is the case what order should I be adding them in? Any ideas on how to fix this?

Result:

Recursion for loop:

for (int i = 0; i < RECURSION_LEVEL; i++) {
            List<Vector3i> indices2 = new ArrayList<Vector3i>();
            for (Vector3i face : indices) {
                int a = getMiddlePoint(face.x, face.y);
                int b = getMiddlePoint(face.y, face.z);
                int c = getMiddlePoint(face.z, face.x);

                indices2.add(new Vector3i(face.x, a, c));
                indices2.add(new Vector3i(face.y, b, a));
                indices2.add(new Vector3i(face.z, c, b));
                indices2.add(new Vector3i(a, b, c));
            }
            indices = indices2;
        }

getMiddlePoints method:

private int getMiddlePoint(int p1, int p2) {
        boolean firstIsSmaller = p1 < p2;
        int smallerIndex = firstIsSmaller ? p1 : p2;
        int greaterIndex = firstIsSmaller ? p2 : p1;
        int key = (smallerIndex << 32) + greaterIndex;

        Integer ret = middlePointIndexCache.get(key);
        if (ret != null) {
            return ret;
        }

        Vector3f point1 = vertices.get(p1);
        Vector3f point2 = vertices.get(p2);
        Vector3f middle = new Vector3f(
                (point1.x + point2.x) / 2.0f,
                (point1.y + point2.y) / 2.0f,
                (point1.z + point2.z) / 2.0f
                );

        int i = addVertex(middle);
        middlePointIndexCache.put(key, i);
        return i;
    }

All of the code for my icosphere generator: (Ignore the texture coordinates they are temporary to prevent my renderer from crashing.)

package com.robert.game.planet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector3i;

import com.robert.engine.loader.Loader;
import com.robert.engine.models.Mesh;

public class BasePlanetGenerator {

    private List<Vector3f> vertices = new ArrayList<Vector3f>();
    private List<Vector3f> normals = new ArrayList<Vector3f>();
    private List<Vector3i> indices = new ArrayList<Vector3i>(); // think of this as faces
    private List<Vector2f> textureCoords = new ArrayList<Vector2f>();
    private Map<Integer, Integer> middlePointIndexCache = new HashMap<Integer, Integer>();

    private static final int RECURSION_LEVEL = 2;

    private int index = 0;

    float t = (float) ((1.0 + Math.sqrt(5.0)) / 2);

    // Initial vertices
    {
//      vertices.add(new Vector3f(-1,  t,  0));
//      vertices.add(new Vector3f(1,  t,  0));
//      vertices.add(new Vector3f(-1, -t,  0));
//      vertices.add(new Vector3f(1, -t,  0));
//      
//      vertices.add(new Vector3f(0, -1,  t));
//      vertices.add(new Vector3f(0,  1,  t));
//      vertices.add(new Vector3f(0, -1, -t));
//      vertices.add(new Vector3f(0,  1, -t));
//      
//      vertices.add(new Vector3f(t,  0, -1));
//      vertices.add(new Vector3f(t,  0,  1));
//      vertices.add(new Vector3f(-t,  0, -1));
//      vertices.add(new Vector3f(-t,  0,  1));

        addVertex(new Vector3f(-1,  t,  0));
        addVertex(new Vector3f(1,  t,  0));
        addVertex(new Vector3f(-1, -t,  0));
        addVertex(new Vector3f(1, -t,  0));

        addVertex(new Vector3f(0, -1,  t));
        addVertex(new Vector3f(0,  1,  t));
        addVertex(new Vector3f(0, -1, -t));
        addVertex(new Vector3f(0,  1, -t));

        addVertex(new Vector3f(t,  0, -1));
        addVertex(new Vector3f(t,  0,  1));
        addVertex(new Vector3f(-t,  0, -1));
        addVertex(new Vector3f(-t,  0,  1));
    }

    // Initial indices
    {
        indices.add(new Vector3i(0, 11, 5));
        indices.add(new Vector3i(0, 5, 1));
        indices.add(new Vector3i(0, 1, 7));
        indices.add(new Vector3i(0, 7, 10));
        indices.add(new Vector3i(0, 10, 11));

        indices.add(new Vector3i(1, 5, 9));
        indices.add(new Vector3i(5, 11, 4));
        indices.add(new Vector3i(11, 10, 2));
        indices.add(new Vector3i(10, 7, 6));
        indices.add(new Vector3i(7, 1, 8));

        indices.add(new Vector3i(3, 9, 4));
        indices.add(new Vector3i(3, 4, 2));
        indices.add(new Vector3i(3, 2, 6));
        indices.add(new Vector3i(3, 6, 8));
        indices.add(new Vector3i(3, 8, 9));

        indices.add(new Vector3i(4, 9, 5));
        indices.add(new Vector3i(2, 4, 11));
        indices.add(new Vector3i(6, 2, 10));
        indices.add(new Vector3i(8, 6, 7));
        indices.add(new Vector3i(9, 8, 1));

//      indices = Arrays.asList(new Integer[] {
//              0, 11, 5,
//              0, 5, 1,
//              0, 1, 7,
//              0, 7, 10,
//              0, 10, 11,
//              
//              1, 5, 9,
//              5, 11, 4,
//              11, 10, 2,
//              10, 7, 6,
//              7, 1, 8,
//              
//              3, 9, 4,
//              3, 4, 2,
//              3, 2, 6,
//              3, 6, 8,
//              3, 8, 9,
//              
//              4, 9, 5,
//              2, 4, 11,
//              6, 2, 10,
//              8, 6, 7,
//              9, 8, 1
//      });
    }

    // Inital textureCoords
    {
        textureCoords.add(new Vector2f(1, 1));
    }

    float[] verticesArray;
    int[] indicesArray;
    float[] normalsArray;
    float[] textureCoordsArray;

    public Mesh generateBasePlanet(Loader loader) {

        for (int i = 0; i < RECURSION_LEVEL; i++) {
            List<Vector3i> indices2 = new ArrayList<Vector3i>();
            for (Vector3i face : indices) {
                int a = getMiddlePoint(face.x, face.y);
                int b = getMiddlePoint(face.y, face.z);
                int c = getMiddlePoint(face.z, face.x);

                indices2.add(new Vector3i(face.x, a, c));
                indices2.add(new Vector3i(face.y, b, a));
                indices2.add(new Vector3i(face.z, c, b));
                indices2.add(new Vector3i(a, b, c));
            }
            indices = indices2;
        }

        for (int i = 0; i < vertices.size(); i ++) {
            Vector3f normal = vertices.get(i);
//          normal.normalize();
//          float length = normal.length();     
//          normals.add(new Vector3f(normal.x / length, normal.y / length, normal.z / length));
            normals.add(normal);
        }

        convertToArrays();

        return loader.createMesh(verticesArray, textureCoordsArray, normalsArray, indicesArray);
    }

    private int getMiddlePoint(int p1, int p2) {
        boolean firstIsSmaller = p1 < p2;
        int smallerIndex = firstIsSmaller ? p1 : p2;
        int greaterIndex = firstIsSmaller ? p2 : p1;
        int key = (smallerIndex << 32) + greaterIndex;

        Integer ret = middlePointIndexCache.get(key);
        if (ret != null) {
            return ret;
        }

        Vector3f point1 = vertices.get(p1);
        Vector3f point2 = vertices.get(p2);
        Vector3f middle = new Vector3f(
                (point1.x + point2.x) / 2.0f,
                (point1.y + point2.y) / 2.0f,
                (point1.z + point2.z) / 2.0f
                );

        int i = addVertex(middle);
        middlePointIndexCache.put(key, i);
        return i;
    }

    private void convertToArrays() {
        verticesArray = new float[vertices.size() * 3];
        indicesArray = new int[indices.size() * 3];
        normalsArray = new float[normals.size() * 3];
        textureCoordsArray = new float[textureCoords.size() * 2];

        for (int i = 0; i < vertices.size(); i ++) {        
            Vector3f vertex = vertices.get(i);
            verticesArray[(i * 3)] = vertex.x;
            verticesArray[(i * 3) + 1] = vertex.y;
            verticesArray[(i * 3) + 2] = vertex.z;
        }

        for (int i = 0; i < indices.size(); i ++) {
            Vector3i indice = indices.get(i);
            indicesArray[(i * 3)] = indice.x;
            indicesArray[(i * 3) + 1] = indice.y;
            indicesArray[(i * 3) + 2] = indice.z;
//          indicesArray[i] = indices.get(i);
        }

        for (int i = 0; i < normals.size(); i ++) {
            Vector3f normal = normals.get(i);
            normalsArray[(i * 3)] = normal.x;
            normalsArray[(i * 3) + 1] = normal.y;
            normalsArray[(i * 3) + 2] = normal.z;
        }

        for (int i = 0; i < textureCoords.size(); i ++) {
            textureCoordsArray[(i * 2)] = textureCoords.get(i).x;
            textureCoordsArray[(i * 2) + 1] = textureCoords.get(i).y;
        }
    }

    private int addVertex(Vector3f vector) {
        float length = vector.length();
        vertices.add(new Vector3f(vector.x / length, vector.y / length, vector.z / length));
        return index++;
    }
}

Answer:

The oracle java specification clearly says:

The values of the integral types are integers in the following ranges: - For int, from -2147483648 to 2147483647, inclusive

This means the data type int is a integral data type with a size of 32 bits.

In the function getMiddlePoint, the line

int key = (smallerIndex << 32) + greaterIndex;

causes an overflow.

Change it to

int key = (smallerIndex << 16) + greaterIndex;

and your code will proper work.

Question:

When I draw a texture with transparency(in file) over ShapeRenderer any shape isn't being updating. When I set batch.setColor(1f, 1f, 1f, 0.5f) result is almost the same: I see stuck shapes with 50% transparency and also see the same animated shapes underneath. I've tried to use Gdx.gl.glEnable(GL20.GL_BLEND) but it didn't help.

shape.begin(ShapeRenderer.ShapeType.Filled);
       shape.setColor(0f / 255f, 7f / 255f, 32f / 255f, 1f);
       shape.rect(0,0, width, height);
       for(Star star : stars)  {
            star.render(shape);
            star.update(dx, dy, delta);
        }
shape.end();

batch.begin();
batch.draw(overlay, 0, 0, width, height);
app.batch.end();

render method inside the Star class:

public void render(ShapeRenderer shape) {
            r = (position.z / max_depth);
            g = (position.z / max_depth);
            b = (position.z / max_depth);
            a = 1.f;                

            if(r < 0) r = 0;
            if(g < 7f / 255f) g = 7f / 255f;
            if (b < 32f / 255f) b = 32f / 255f

            float radius = (position.z / max_depth) * maxRadius;
            if(radius < 1) radius = 1;

            shape.setColor(r, g, b, a);
            shape.circle(position.x, position.y, radius);
}

Answer:

You need to set BlendFunction to batch according to your desired blend output. By default it is enabled with GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA

so try to change to :

batch.setBlendFunction(GL20.GL_SRC_ALPHA,GL20.GL_DST_COLOR); 

May be this not fit your requirement so choose appropriate one, according to your requirement.

Question:

I have been spending the last few days trying to scale a texture to a Quad (OpenGL 3)...

But for some reason I am getting only the top left pixel of the image rendered on to the quad, I am using Slick-Utils to load and bind the texture....

Here is the code:

MainGame.java

package test.game;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.newdawn.slick.opengl.Texture;

import test.engine.Loader;
import test.engine.rendersystem.Model;
import test.engine.rendersystem.ShaderProgram;

import static org.lwjgl.opengl.GL11.*;

import java.io.IOException;
import java.util.HashMap;

public class MainGame {

// Constants
public static final String WINDOW_TITLE = "Neon Indev";
public static final int WIDTH = 800;
public static final int HEIGHT = 480;
public static final ContextAttribs OPENGL_CONTEXTS_ATTRIBS = new ContextAttribs(3, 2).withForwardCompatible(true).withProfileCore(true);
public static final int SYNC_FPS = 60;

static float[] vertexData = 
    {
            -0.5f, 0.5f,
            0.5f, 0.5f,
            0.5f, -0.5f,
            -0.5f, -0.5f
    };
static float[] colorData = { 0f, 1f, 1f, 1f,
                            0f, 1f, 1f, 1f,
                            0f, 1f, 1f, 1f,
                            0f, 1f, 1f, 1f,
                            0f, 1f, 1f, 1f,
                            0f, 1f, 1f, 1f};
static int[] indexData = {
        0, 1, 3,
        3, 1, 2
};

static float[] texData = {
        0,0,
        1,0,
        1,1,
        0,1
};

static Model model;
static ShaderProgram shader;
static Texture testTexture;

public static void main(String[] args) {
    init();
    render();
}

private static void init() {
    // Display Initialization
    try {
        Display.setTitle(WINDOW_TITLE);
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create(new PixelFormat(), OPENGL_CONTEXTS_ATTRIBS);
    } catch (LWJGLException e) {
        e.printStackTrace();
        System.exit(1);
    }

    // OpenGL Initialization
    glViewport(0, 0, WIDTH, HEIGHT);
    glClearColor(0f, 0f, 0f, 1f);

    model = new Model(vertexData, colorData, indexData);
    try {
        testTexture = Loader.loadTexture("res/images/png/image02 (1).png", "PNG");
    } catch (IOException e) {
        e.printStackTrace();
        System.exit(1);
    }
    model.setTexture(testTexture, texData);


    // Shader Initialization
    HashMap<String, Integer> vboDataToBind = new HashMap<String, Integer>();
    vboDataToBind.put("in_Position", Model.ATTRIB_VERTEX);
    vboDataToBind.put("in_Color", Model.ATTRIB_COLOR);
    vboDataToBind.put("in_TextureCoord", Model.ATTRIB_TEXTURE);

    shader = new ShaderProgram("res/shaders/frag/color.frag", "res/shaders/vert/color.vert", true, true, vboDataToBind);
}

private static void render() {
    // Resize Check
    if (Display.wasResized()) {
        resize();
    }

    // Render loop
    while (!Display.isCloseRequested()) {

        glClear(GL_COLOR_BUFFER_BIT);

        shader.bind();
        model.render();
        shader.unbind();

        Display.update();
        Display.sync(SYNC_FPS);
    }

    // Dispose if out of the loop
    dispose();
}

private static void resize() {
    // Resize code goes here
}

private static void dispose() {
    model.dispose();
    shader.dispose();
    Display.destroy();
}

}

ShaderProgram.java

package test.game.engine.rendersystem;

import java.io.IOException;
import java.util.HashMap;
import java.util.Set;

import test.engine.Loader;

import static org.lwjgl.opengl.GL20.*;

public class ShaderProgram {

String fragmentShader;
String vertexShader;

int programID, vertexShaderID, fragmentShaderID;
boolean initialized;

public ShaderProgram(String fragmentShader, String vertexShader, boolean url, boolean init, HashMap<String, Integer> vboDataToBind) {
    if (url) {
        try {
            this.fragmentShader = Loader.getStringFromTextFile(fragmentShader);
            this.vertexShader = Loader.getStringFromTextFile(vertexShader);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    } else {
        this.fragmentShader = fragmentShader;
        this.vertexShader = vertexShader;
    }

    if (init) {
        init(vboDataToBind);
        this.initialized = true;
    } else {
        this.initialized = false;
    }
}

public void init(HashMap<String, Integer> vboDataToBind) {
    if (!initialized) {
        // Initialize the shaders
        vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
        fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

        // Setting up the shader values
        glShaderSource(vertexShaderID, vertexShader);
        glShaderSource(fragmentShaderID, fragmentShader);

        // Compile the shaders
        glCompileShader(vertexShaderID);
        glCompileShader(fragmentShaderID);

        // Create the shader program and attach them
        programID = glCreateProgram();
        glAttachShader(programID, vertexShaderID);
        glAttachShader(programID, fragmentShaderID);

        // Bind any needed data
        if (!vboDataToBind.isEmpty()) {
            Set<String> keys = vboDataToBind.keySet();
            for (String key : keys) {
                bindVBOAttrib(vboDataToBind.get(key), key);
            }
        }

        // Link and validate the program
        glLinkProgram(programID);
        glValidateProgram(programID);
    }
}

public void bind() {
    glUseProgram(programID);
}

public void unbind() {
    glUseProgram(0);
}

public void dispose() {
    glDeleteProgram(programID);
    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);
}

public void bindVBOAttrib(int attribNumber, String variableName) {
    glBindAttribLocation(programID, attribNumber, variableName);
}

public String getFragmentShader() {
    return fragmentShader;
}
public String getVertexShader() {
    return vertexShader;
}

public int getProgramID() {
    return programID;
}

public int getVertexShaderID() {
    return vertexShaderID;
}

public int getFragmentShaderID() {
    return fragmentShaderID;
}
}

Vertex Shader:

#version 150 core

in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;

out vec4 pass_Color;
out vec2 pass_TextureCoord;

void main(void) {
gl_Position = in_Position;

pass_Color = in_Color;
pass_TextureCoord = in_TextureCoord;
}

Fragment Shader:

#version 150 core

uniform sampler2D texture_diffuse;

in vec4 pass_Color;
in vec2 pass_TextureCoord;

out vec4 out_Color;

void main(void) {
out_Color = pass_Color;
// Override out_Color with our texture pixel
out_Color = texture(texture_diffuse, pass_TextureCoord);
}

Loader.java

package test.game.engine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

public class Loader {

public static String getStringFromTextFile(String url) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader(new File(url)));
    String line;
    StringBuilder response = new StringBuilder();
    while ((line = reader.readLine()) != null) {
        response.append(line).append("\n");
    }
    reader.close();
    return response.toString();
}

public static Texture loadTexture(String url, String format) throws IOException {
    return TextureLoader.getTexture(format, ResourceLoader.getResourceAsStream(url));
}

}

Model.java

package test.game.engine.rendersystem;

import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL11.*;

import org.newdawn.slick.opengl.Texture;

public class Model {

// Attribute Numbers
public static final int ATTRIB_VERTEX = 0;
public static final int ATTRIB_INDEX = 1;
public static final int ATTRIB_COLOR = 2;
public static final int ATTRIB_TEXTURE = 3;

// Dimensions
public static final int DIMEN_VERTEX = 2;
public static final int DIMEN_INDEX = 1;
public static final int DIMEN_COLOR = 4;
public static final int DIMEN_TEXTURE = 2;

int vaoID;
int vertexCount;
VBO vertexData;
VBO colorData;
VBO textureData;
IntVBO indexData;

boolean textured;
Texture texture;

public Model(float[] vertexData, float[] colorData, int[] indexData) {
    this.vertexCount = vertexData.length;
    this.vaoID = glGenVertexArrays();
    this.textured = false;

    bindVertexArray();
    this.vertexData = new VBO(ATTRIB_VERTEX, vaoID, vertexData, DIMEN_VERTEX, true);
    this.colorData = new VBO(ATTRIB_COLOR, vaoID, colorData, DIMEN_COLOR, true);
    this.indexData = new IntVBO(ATTRIB_INDEX, vaoID, indexData, DIMEN_INDEX, true);
    unbindVertexArray();
}

public boolean isTextured() {
    return textured;
}

public void setTexture(Texture texture, float[] texCoords) {
    this.textured = true;
    this.textureData = new VBO(ATTRIB_TEXTURE, vaoID, texCoords, DIMEN_TEXTURE, true);
    this.texture = texture;
}

public void unbindVertexArray() {
    glBindVertexArray(0);
}

public void bindVertexArray() {
    glBindVertexArray(vaoID);
}

public void dispose() {
    vertexData.dispose();
    colorData.dispose();
    indexData.dispose();
    glDeleteVertexArrays(vaoID);
}

public void render() {
    bindVertexArray();
    colorData.bind();
    vertexData.bind();
    if (textured) textureData.bind();
    indexData.bind();

    vertexData.enable();
    if (textured) textureData.enable();
    colorData.enable();
    indexData.enable();

    // Loading in the texture data
    if (textured) {
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture.getTextureID());
    }

    glDrawElements(GL_TRIANGLES, this.vertexCount, GL_UNSIGNED_INT, 0);

    colorData.disable();
    vertexData.disable();
    indexData.disable();
    if (textured) textureData.disable();

    vertexData.unbind();
    colorData.unbind();
    indexData.unbind();
    if (textured) textureData.disable();

    unbindVertexArray();
}
}

VBO.java

package test.game.engine.rendersystem;

import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL11.*;

import java.nio.FloatBuffer;

import org.lwjgl.BufferUtils;

import static org.lwjgl.opengl.GL15.*;

public class VBO {

public int vboID;
public int attributeNumber;
public int vaoID;
public int dataDimensions;
public float[] data;

public VBO(int attributeNumber, int vaoID, float[] data, int dimensions, boolean loadToVBO) {
    this.attributeNumber = attributeNumber;
    this.vaoID = vaoID;
    this.data = data;
    this.dataDimensions = dimensions;

    if (loadToVBO) {
        loadToVBO();
    }
}

public void loadToVBO() {
    this.vboID = glGenBuffers();
    bind();
    glBufferData(GL_ARRAY_BUFFER, storeDataInFloatBuffer(), GL_STATIC_DRAW);
    glVertexAttribPointer(attributeNumber, dataDimensions, GL_FLOAT, false, 0, 0);
    unbind();
}

public void bind() {
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
}

public void unbind() {
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

public void enable() {
    glEnableVertexAttribArray(attributeNumber);
}

public void disable() {
    glDisableVertexAttribArray(attributeNumber);
}

public void dispose() {
    glDeleteBuffers(vboID);
}

private FloatBuffer storeDataInFloatBuffer() {
    FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
    buffer.put(data);
    buffer.flip();
    return buffer;
}

}

Here is the image I wanted to render (It is a test image) (It is in PNG) A cow:

Here is the output I got. A cow on the quad:

P.S I am a new to OpenGL and low level graphics APIs.... So forgive me if I did any newb/noob mistakes.


Answer:

I believe your problem lies here:

public void setTexture(Texture texture, float[] texCoords) { 
this.textured = true; 
this.textureData = new VBO(ATTRIB_TEXTURE, vaoID, texCoords, DIMEN_TEXTURE, true);
this.texture = texture; 
}

When you created the initial vbos you bound the VAO then unbound it which allowed the drawing to take place, but when you add the texture coordinates no VAO is bound leading to your vbo being bound to nothing. When render is then called and the texture coordinates called upon nothing is found and so the default 0;0 coordinates, aka the single corner pixel, are used.

Question:

I am trying to make a basic render engine using LWJGL, and I have recently run into a block. Whenever I try to change the shader uniforms that objects are being drawn with twice in a frame, the program just displays the clear color. Where I think it is screwing up is line 82 of the SceneLoader class, but I have no idea. This is my first time using Lwjgl, so any help with this would be greatly appreciated. Thanks!

I put some notable classes to the problem below, but here is the full source code: https://github.com/SomeRandomPerson9/3DT/tree/master/src/com/harry9137/api

SceneLoader.java

package com.harry9137.api.scenes;

import com.bulletphysics.linearmath.Transform;
import com.harry9137.api.main.Game;
import com.harry9137.api.physics.MathHelper;
import com.harry9137.api.render.Material;
import com.harry9137.api.render.Mesh;
import com.harry9137.api.render.math.Matrix4f;
import com.harry9137.api.render.math.Vector3f;
import com.harry9137.api.scenes.Objects.ChoiceMenuObject;
import com.harry9137.api.scenes.Objects.logic.GenericObject;
import com.harry9137.api.scenes.Objects.logic.RenderObject;
import com.harry9137.api.scenes.Objects.logic.TextObject;
import com.harry9137.api.util.ProgramRefrence;
import com.harry9137.api.util.RenderUtil;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.glu.Sphere;
import org.newdawn.slick.Color;

import java.util.HashMap;

public class SceneLoader {
private static HashMap <Integer, SceneBase> scenes = new HashMap<>();
private static SceneBase selectedScene;
private static int selectedSceneNumber;
private static Sphere sphere = new Sphere();

public static void addScene(Integer integer, SceneBase scene){
    scenes.put(integer, scene);
}
public static void selectScene(Integer integer){
    if(selectedScene != null) {
        selectedScene.cleanup();
        //selectedScene.getRegShader().updateUniforms(new Matrix4f(),new Matrix4f(), null);
    }
    selectedScene = scenes.get(integer);
    selectedSceneNumber = integer;
    selectedScene.specialInit();
}
public static void updateScene(){
    if(selectedScene != null) {
        selectedScene.update();
        if(selectedScene.getDynamicsWorld() != null) {
            //System.out.println("blah");
            GL11.glLoadIdentity();
            selectedScene.getDynamicsWorld().stepSimulation(1.0f / 60.0f);
            for(RenderObject renderObject : selectedScene.getObjects()){
                if (renderObject.isPhys() && !MathHelper.anyGreaterThan(0.1f, renderObject.getRigidBodyShape().getLinearVelocity(new javax.vecmath.Vector3f(0,0,0)))) {
                    renderObject.setLocation(MathHelper.vecMathToBaked3f(renderObject.getRigidBodyShape().getMotionState().getWorldTransform(new Transform()).origin));
                    System.out.println(renderObject.getRigidBodyShape().getMotionState().getWorldTransform(new Transform()).origin);
                }
            }

        }
        for (int i = 0; i < scenes.size(); i++) {
            if (scenes.get(i) != null) {
                if (scenes.get(i).getBtsUpdateLvl() > 0) {
                    scenes.get(i).update();
                }
                if (selectedSceneNumber == i) {
                    selectedScene.update();
                }
            }
        }
    }
}
public static void renderScene(){
    if(selectedScene.sceneType == SceneType.THREE_DIMENSIONAL) {
        for (RenderObject renderObject : selectedScene.getObjects()) {
            /*if(renderObject.isHeld()) {
                    Object[] temp = (renderObject.getTransform().getProjectedTransformationHeld(new Matrix4f().initTranslation(renderObject.getLocation().GetX(), renderObject.getLocation().GetY(), renderObject.getLocation().GetZ())));
                    selectedScene.getRegShader().updateUniforms(renderObject.getTransform().getTransformation(), (Matrix4f) temp[0], renderObject.getMaterial());
                    //renderObject.setLocation(((Matrix4f)temp[2]).get;
            }
            else{
                selectedScene.getRegShader().updateUniforms(renderObject.getTransform().getTransformation(), renderObject.getTransform().getProjectedTransformation(new Matrix4f().initTranslation(renderObject.getLocation().GetX(), renderObject.getLocation().GetY(), renderObject.getLocation().GetZ())), renderObject.getMaterial());
            }*/
            for(Mesh meshyThing : renderObject.getMeshs().values()){
                selectedScene.getRegShader().bind();
                System.out.println("Object " + meshyThing.getObjName() + " has material " + meshyThing.getRequiredMtl());
                selectedScene.getRegShader().updateUniforms(renderObject.getTransform().getTransformation(), renderObject.getTransform().getProjectedTransformation(new Matrix4f().initTranslation(renderObject.getLocation().GetX(), renderObject.getLocation().GetY(), renderObject.getLocation().GetZ())), renderObject.getMaterial(meshyThing.getRequiredMtl()));
                meshyThing.draw();
            }

            //renderObject.getMesh().draw();
            /*if(Game.showBoundingBoxes && selectedScene.getDynamicsWorld() != null && renderObject.isPhys()){
                GL11.glPushMatrix();
                javax.vecmath.Vector3f position = renderObject.getRigidBodyShape().getMotionState().getWorldTransform(new Transform()).origin;
                sphere.setDrawStyle(GLU.GLU_SILHOUETTE);
                GL11.glTranslatef(position.x, position.y, position.z);
                GL11.glColor4f(0, 1, 0, 1);
                sphere.draw(renderObject.getRigidBodyShape().getCollisionShape().getAngularMotionDisc(), 30, 30);
                GL11.glPopMatrix();
            */
        }
        for(GenericObject genericObject : selectedScene.getOverlayObjects()){
            /*if(genericObject instanceof TextObject){
                TextObject textObj = (TextObject)genericObject;
                try {
                    GL11.glPushMatrix();
                    selectedScene.getOverlayShader().bind();
                    selectedScene.getOverlayShader().updateUniforms(null, null, new Material(null, new Vector3f(0,0,0)));
                    ProgramRefrence.fonts.arialFont.drawString(textObj.getX(), textObj.getY(), textObj.getString(), Color.black);
                    GL11.glPopMatrix();
                }catch(NullPointerException e){
                    if(ProgramRefrence.fonts.arialFont == null){ 
                        System.err.println("Global font is null");
                    }
                    //if(textObj.getFont() == null) {
                    //    System.err.println("Text Object " + textObj.getObjName() + ": Font is Null");
                    //}
                    if(textObj.getString() == null){
                        System.err.println("Text Object " + textObj.getObjName() + ": String is Null");
                    }
                }
            }
            else if(genericObject instanceof ChoiceMenuObject){
                ChoiceMenuObject choiceMenuObject = (ChoiceMenuObject)genericObject;

                try{
                    choiceMenuObject.mesh.draw(choiceMenuObject.xPos, choiceMenuObject.yPos);
                }
                catch(Exception e){

                }
            }*/
        }
    }
    else if(selectedScene.sceneType == SceneType.TWO_DIMENSIONAL){
        if(selectedScene instanceof Scene2DVideo){

            ((Scene2DVideo) selectedScene).render();
        }
    }
}
/* public static void calcPhysics(){
    if(selectedScene != null) {
        for (RenderObject object : selectedScene.getObjects()) {
            if(object.isPhys()) {

                object.getTransform().addTranslation(object.getLocation());

                int tps = Game.getInstance().getTps();
                //Gravity
                if (object.getVelocity().GetY() >= ProgramRefrence.terminalVelocity) {
                    object.setAcceleration(new Vector3f((float) object.getAcceleration().GetX(), (float) (object.getAcceleration().GetY() - ProgramRefrence.gravity / tps), (float) object.getAcceleration().GetZ()));
                }

                //Acceleration to Velocity
                if (object.getAcceleration().GetX() != 0) {
                    object.getVelocity().SetX((float) (object.getAcceleration().GetX() / tps) + object.getVelocity().GetX());
                }
                if (object.getAcceleration().GetY() != 0) {
                    object.getVelocity().SetY((float) (object.getAcceleration().GetY() * Launch.TPS / 100) + object.getVelocity().GetY());
                }
                if (object.getAcceleration().GetX() != 0) {
                    object.getVelocity().SetZ((float) (object.getAcceleration().GetZ() * Launch.TPS / 100) + object.getVelocity().GetZ());
                }
                object.setAcceleration(new Vector3f(0, 0, 0));

                //Velocity to Location
                if (object.getAcceleration().GetX() != 0) {
                    object.getLocation().SetX((float) (object.getAcceleration().GetX() / tps) + object.getVelocity().GetX());
                }
                if (object.getAcceleration().GetY() != 0) {
                    if(object.getLocation().GetY() > 0f) {
                        object.getLocation().SetY((float) (object.getAcceleration().GetY() * Launch.TPS / 100) + object.getVelocity().GetY());
                    }
                }
                if (object.getAcceleration().GetX() != 0) {
                    object.getLocation().SetZ((float) (object.getAcceleration().GetZ() * Launch.TPS / 100) + object.getVelocity().GetZ());
                }
            }

        }
    }
}   */
public static void updateSceneInput(){
    if(selectedScene != null) {
        selectedScene.input();
    }
}
public static int getSelectedSceneNumber(){
    return selectedSceneNumber;
}
public static SceneBase getSelectedScene(){
    return selectedScene;
}
public static HashMap<Integer, SceneBase> getScenes() {
    return scenes;
}

}

PhongShader.java (The shader that the scene I'm having problems with has)

package com.harry9137.api.render.shaders;

import com.harry9137.api.render.Material;
import com.harry9137.api.util.ResourceLoader;
import com.harry9137.api.render.math.Matrix4f;
import com.harry9137.api.render.math.Vector3f;
import com.harry9137.api.render.lighting.BaseLight;
import com.harry9137.api.render.lighting.DirectionalLight;
import com.harry9137.api.util.RenderUtil;

import org.newdawn.slick.Color;

import java.awt.*;

public class PhongShader extends Shader {
private static final PhongShader instance = new PhongShader();

public static PhongShader getInstance() {
    return instance;
}

private static Vector3f ambientLight = new Vector3f(0.1f,0.1f,0.1f);
private static DirectionalLight directionalLight = new DirectionalLight(new BaseLight(new Vector3f(1,1,1), 0f), new Vector3f(0,0,0));

private PhongShader() {
    super();

    addVertexShader(ResourceLoader.loadShader("phongVertex.vs"));
    addFragmentShader(ResourceLoader.loadShader("phongFragment.fs"));
    compileShader();

    addUniform("transform");
    addUniform("baseColor");
    addUniform("ambientLight");

    addUniform("directionalLight.base.color");
    addUniform("directionalLight.base.intensity");
    addUniform("directionalLight.direction");
}

public static DirectionalLight getDirectionalLight() {
    return directionalLight;
}

public static void setDirectionalLight(DirectionalLight directionalLight) {
    PhongShader.directionalLight = directionalLight;
}

public void updateUniforms(Matrix4f worldMatrix, Matrix4f projectedMatrix, Material material) {
    setUniform("transform", projectedMatrix.mul(worldMatrix));
    if(material != null && material.getColor() != null) {
        setUniform("baseColor", material.getColor());
    }
    else{
        setUniform("baseColor", new Vector3f(255,255,255));
        //Color.white.bind();
    }

    if (material != null && material.getTexture() != null) {
        material.getTexture().bind();
    }
    else
        RenderUtil.unbindTextures();

    setUniform("ambientLight", ambientLight);

    setUniform("directionalLight", directionalLight);
}

public static Vector3f getAmbientLight() {
    return ambientLight;
}

public static void setAmbientLight(Vector3f ambientLight) {
    PhongShader.ambientLight = ambientLight;
}
public void setUniform(String uniformName, BaseLight baseLight){
    setUniform(uniformName + ".color", baseLight.getColor());
    setUniformf(uniformName + ".intensity", baseLight.getIntensity());
}
public void setUniform(String uniformName, DirectionalLight directionalLight)
{
    setUniform(uniformName + ".base", directionalLight.getBase());
    setUniform(uniformName + ".direction", directionalLight.getDirection());
}
}

phongVertex.vs

#version 330

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;

out vec2 texCoord0;
out vec3 normal0;

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(position, 1.0);
    texCoord0 = texCoord;
    normal0 = normal;
}

phongFragment.fs

#version 330

in vec2 texCoord0;
in vec3 normal0;

out vec4 fragColor;

struct BaseLight{
    vec3 color;
    float intensity;
};

struct DirectionalLight{
    BaseLight base;
    vec3 direction;
};
uniform DirectionalLight directionalLight;
uniform vec3 baseColor;
uniform vec3 ambientLight;
uniform sampler2D sampler;

vec4 calcLight(BaseLight base, vec3 direction, vec3 normal){

float diffuseFactor = dot(-direction, normal);

vec4 diffuseColor =  vec4(0,0,0,0);

if(diffuseFactor > 0)
    diffuseColor = vec4(base.color, 1.0) * base.intensity * diffuseFactor;

return diffuseColor;

}

vec4 calcDirectionalLight(DirectionalLight directionalLight, vec3 normal){
    return calcLight(directionalLight.base, directionalLight.direction,         normal);
}

void main()
{
    vec4 totalLight = vec4(ambientLight, 1);
    vec4 color = fragColor = vec4(baseColor, 1);
    vec4 textureColor = texture(sampler, texCoord0.xy);

    if(textureColor != vec4(0,0,0,0))
        color *= textureColor;

    vec3 normal = normalize(normal0);

    totalLight += calcDirectionalLight(directionalLight, normal);

    fragColor = color * totalLight;
}

Mesh.java

package com.harry9137.api.render;

import com.harry9137.api.render.math.Vector3f;
import com.harry9137.api.scenes.Objects.logic.GenericObject;
import com.harry9137.api.util.Util;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;

public class Mesh extends GenericObject {
private int vbo;
private int ibo;
private int size;
private String requiredMtl;

public Mesh(){
    vbo = glGenBuffers();
    ibo = glGenBuffers();
    size = 0;
}
public void addVertices(Vertex[] data, int[] indices) {
    addVertices(data, indices, false);
}

public void addVertices(Vertex[] data, int[] indices, boolean calcNormals){
    if(calcNormals){
        calcNormals(data, indices);
    }
    size = indices.length;

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(data), GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);

}
public void draw(){
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0,3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
    glVertexAttribPointer(1,2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
    glVertexAttribPointer(2,3, GL_FLOAT, false, Vertex.SIZE * 4, 20);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
}
private void calcNormals(Vertex[] vertexes, int[] integers){
   for(int i = 0; i < integers.length; i += 3){
       int i0 = integers[i];
       int i1 = integers[i + 1];
       int i2 = integers[i + 2];

       Vector3f v1 = vertexes[i1].getPos().Sub(vertexes[i0].getPos());
       Vector3f v2 = vertexes[i2].getPos().Sub(vertexes[i0].getPos());

       Vector3f normal = v1.cross(v2).Normalized();
       vertexes[i0].setNormal(vertexes[i0].getNormal().Add(normal));
       vertexes[i1].setNormal(vertexes[i0].getNormal().Add(normal));
       vertexes[i2].setNormal(vertexes[i0].getNormal().Add(normal));
   }
    for(int i = 0; i < vertexes.length; i++){
        vertexes[i].setNormal(vertexes[i].getNormal().Normalized());
    }
}

public int getIbo() {
    return ibo;
}

public int getVbo() {
    return vbo;
}

public String getRequiredMtl() {
    return requiredMtl;
}

public void setRequiredMtl(String requiredMtl) {
    this.requiredMtl = requiredMtl;
}
}

Answer:

Never mind. It was a problem with how I was importing the models.

Question:

When I try to execute my Java code that uses Lightweight Java Game Library (LWJGL) in one thread, everything works fine. However when I start second Java thread that simply constantly prints text (see my text thread class pseudocode below) my OpenGL program becomes unresponsive, but the text is still printed. No errors are shown.

 public class TextPrinterThread implements Runnable {
    public void run() {
        while(true) {
            System.out.println("My text");
        }
    }
}

I have read that OpenGL has problems with multithreading here and here and so on, however I do not try to separate OpenGL job in multiple threads. I use One thread solely for OpenGL and other thread to execute non OpenGL code. I did not find any suggestions on internet what is the cause of my problem, I tried changing thread priorities, but it did not help. Any help would be appreciated.


Answer:

because this thread occupies CPU,

verify: add sleep after print, see if main thread gets recovered.

Question:

Please advise why is the cube rendered without colors although my VBO contains colors? What am I doing wrong? Many thanks in advance!

Voxel.java

    package cz.rv.cubeworld.mesh;

    import org.lwjgl.BufferUtils;
    import org.lwjgl.opengl.GL11;
    import org.lwjgl.opengl.GL15;

    import java.nio.FloatBuffer;

    public class Voxel {

        /**
               H_______________G
               /.             /|
              / .            / |
            D/_____________C/  |
            |   .          |   |
            |   .          |   |
            |   ...........|...|
            | . E          |  /F
            |______________|/
            A              B
        */

        private static final float[] vertexData = {
                // Position             // Normal               // Color

                // Back side - E H G F
                -1.0f, -1.0f,  -1.0f,    0.0f,  0.0f,  -1.0f,    1.0f, 1.0f, 1.0f, 1.0f, // E
                 1.0f, -1.0f,  -1.0f,    0.0f,  0.0f,  -1.0f,    1.0f, 1.0f, 1.0f, 1.0f, // F
                 1.0f,  1.0f,  -1.0f,    0.0f,  0.0f,  -1.0f,    1.0f, 1.0f, 1.0f, 1.0f, // G
                -1.0f,  1.0f,  -1.0f,    0.0f,  0.0f,  -1.0f,    1.0f, 1.0f, 1.0f, 1.0f, // H

                // Bottom side - F B A E
                 1.0f, -1.0f, -1.0f,     0.0f, -1.0f,  0.0f,    0.0f, 1.0f, 1.0f, 1.0f, // F
                 1.0f, -1.0f,  1.0f,     0.0f, -1.0f,  0.0f,    0.0f, 1.0f, 1.0f, 1.0f, // B
                -1.0f, -1.0f,  1.0f,     0.0f, -1.0f,  0.0f,    0.0f, 1.0f, 1.0f, 1.0f, // A
                -1.0f, -1.0f, -1.0f,     0.0f, -1.0f,  0.0f,    0.0f, 1.0f, 1.0f, 1.0f, // E

                // Right side - F G C B
                 1.0f, -1.0f, -1.0f,     1.0f,  0.0f,  0.0f,    1.0f, 0.0f, 1.0f, 1.0f, // F
                 1.0f,  1.0f, -1.0f,     1.0f,  0.0f,  0.0f,    1.0f, 0.0f, 1.0f, 1.0f, // G
                 1.0f,  1.0f,  1.0f,     1.0f,  0.0f,  0.0f,    1.0f, 0.0f, 1.0f, 1.0f, // C
                 1.0f, -1.0f,  1.0f,     1.0f,  0.0f,  0.0f,    1.0f, 0.0f, 1.0f, 1.0f, // B

                // Top side - C G H D
                 1.0f,  1.0f, -1.0f,     0.0f,  1.0f,  0.0f,    1.0f, 1.0f, 0.0f, 1.0f, // C
                 1.0f,  1.0f,  1.0f,     0.0f,  1.0f,  0.0f,    1.0f, 1.0f, 0.0f, 1.0f, // G
                -1.0f,  1.0f,  1.0f,     0.0f,  1.0f,  0.0f,    1.0f, 1.0f, 0.0f, 1.0f, // H
                -1.0f,  1.0f, -1.0f,     0.0f,  1.0f,  0.0f,    1.0f, 1.0f, 0.0f, 1.0f, // D

                // Left side - A D H E
                -1.0f, -1.0f, -1.0f,    -1.0f,  0.0f,  0.0f,    0.0f, 1.0f, 0.0f, 1.0f, // A
                -1.0f,  1.0f, -1.0f,    -1.0f,  0.0f,  0.0f,    0.0f, 1.0f, 0.0f, 1.0f, // D
                -1.0f,  1.0f,  1.0f,    -1.0f,  0.0f,  0.0f,    0.0f, 1.0f, 0.0f, 1.0f, // H
                -1.0f, -1.0f,  1.0f,    -1.0f,  0.0f,  0.0f,    0.0f, 1.0f, 0.0f, 1.0f, // E

                // Front side - A D C B
                -1.0f, -1.0f, 1.0f,      0.0f,  0.0f,  1.0f,    1.0f, 0.0f, 1.0f, 1.0f, // A
                -1.0f,  1.0f, 1.0f,      0.0f,  0.0f,  1.0f,    1.0f, 0.0f, 1.0f, 1.0f, // D
                 1.0f,  1.0f, 1.0f,      0.0f,  0.0f,  1.0f,    1.0f, 0.0f, 1.0f, 1.0f, // C
                 1.0f, -1.0f, 1.0f,      0.0f,  0.0f,  1.0f,    1.0f, 0.0f, 1.0f, 1.0f, // B
        };

        private static final int TOTAL_NUMBER_OF_VERTICES = 24;
        private static final int VERTEX_ATTRIBUTE_SIZE = 10 * Float.BYTES;      // In bytes
        private static final int VERTEX_POSITION_SIZE = 3;                      // In floats
        private static final int VERTEX_COLOR_SIZE = 4;                         // In floats
        private static final int FIRST_VERTEX_POSITION_POINTER = 0;             // In bytes
        private static final int FIRST_VERTEX_NORMAL_POINTER = 3 * Float.BYTES; // In bytes
        private static final int FIRST_VERTEX_COLOR_POINTER = 6 * Float.BYTES;  // In bytes

        private final int vertexBufferObjectHandle;
        private final FloatBuffer vertexBufferObject;

        public Voxel() {
            vertexBufferObject = BufferUtils.createFloatBuffer(vertexData.length);  // Allocate direct float buffer
            vertexBufferObject.put(vertexData).flip();  // Write data to the buffer and reset the position to zero

            vertexBufferObjectHandle = GL15.glGenBuffers(); // Create named buffer object
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBufferObjectHandle);  // Hey, GL, we will be using named buffer object we just generated
            GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vertexBufferObject, GL15.GL_STATIC_DRAW);   // Write vertexBufferObject data to our named buffer object
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Tell GL we aren't using any named buffer since now
        }

        public void render(float x, float y, float z, float xrot, float yrot, float zrot) {
            GL11.glLoadIdentity();

            GL11.glTranslatef(x, y, z);
            GL11.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
            GL11.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
            GL11.glRotatef(zrot, 0.0f, 0.0f, 1.0f);

            GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
            GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
            GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);

            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBufferObjectHandle);

            GL11.glVertexPointer(VERTEX_POSITION_SIZE, GL11.GL_FLOAT, VERTEX_ATTRIBUTE_SIZE, FIRST_VERTEX_POSITION_POINTER);
            GL11.glColorPointer(VERTEX_COLOR_SIZE, GL11.GL_FLOAT, VERTEX_ATTRIBUTE_SIZE, FIRST_VERTEX_COLOR_POINTER);
            GL11.glNormalPointer(GL11.GL_FLOAT, VERTEX_ATTRIBUTE_SIZE, FIRST_VERTEX_NORMAL_POINTER);

            GL11.glDrawArrays(GL11.GL_QUADS, 0, TOTAL_NUMBER_OF_VERTICES);

            GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
            GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
            GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
        }
    }

DisplayExample.java

package cz.rv.cubeworld;

import cz.rv.cubeworld.mesh.Voxel;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class DisplayExample {

    private float xrot;
    private float yrot;
    private float zrot;
    private float lightAmbient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    private float lightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    private float lightPosition[] = { 0.0f, 0.0f, 0.1f, 1.0f };
    private Voxel voxel;

    public static void main(String[] args) {
        DisplayExample displayExample = new DisplayExample();
        displayExample.start();
    }

    public void start() {
        try {
            init();
            voxel = new Voxel();
            while (!Display.isCloseRequested()) {
                render();
                Display.update();
                Display.sync(60);
                xrot += 0.2f;
                yrot += 0.3f;
                zrot += 0.1f;
            }

            cleanup();
        } catch (LWJGLException | IOException e) {
            e.printStackTrace();
            System.exit(0);
        }
    }

    private void init() throws LWJGLException, IOException {
        createWindow();
        initGL();
    }

    private void createWindow() throws LWJGLException {
        DisplayMode displayMode = null;
        for (DisplayMode mode : Display.getAvailableDisplayModes()) {
            if (mode.getWidth() == 640 && mode.getHeight() == 480 && mode.getBitsPerPixel() == 24) {
                displayMode = mode;
                break;
            }
        }
        Display.setDisplayMode(displayMode);
        Display.setTitle("CubeWorld");
        Display.create();
    }

    private void initGL() {
        //GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
        GL11.glShadeModel(GL11.GL_SMOOTH); // Enable Smooth Shading
        GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
        GL11.glClearDepth(1.0); // Depth Buffer Setup
        GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
        GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
        GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
        GL11.glLoadIdentity(); // Reset The Projection Matrix
        GLU.gluPerspective(45.0f, (float) Display.getWidth() / (float) Display.getHeight(), 0.1f, 100.0f); // Calculate The Aspect Ratio Of The Window
        GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
        GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); // Really Nice Perspective Calculations

        GL11.glEnable(GL11.GL_LIGHTING);

        ByteBuffer lightBuffer = ByteBuffer.allocateDirect(16);
        lightBuffer.order(ByteOrder.nativeOrder());
        GL11.glLight(GL11.GL_LIGHT1, GL11.GL_AMBIENT, (FloatBuffer) lightBuffer.asFloatBuffer().put(lightAmbient).flip()); // Setup The Ambient Light
        GL11.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, (FloatBuffer) lightBuffer.asFloatBuffer().put(lightDiffuse).flip()); // Setup The Diffuse Light
        GL11.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, (FloatBuffer) lightBuffer.asFloatBuffer().put(lightPosition).flip()); // Position The Light
        GL11.glEnable(GL11.GL_LIGHT1);  // Enable Light One
    }

    private void cleanup() {
        Display.destroy();
    }

    private void render() {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

        voxel.render(0, 0, -5, xrot, yrot ,zrot);
    }
}


Answer:

It looks like you're missing:

GL11.glEnable(GL11.GL_COLOR_MATERIAL);

Question:

In the picture I have rendered my terrain with a few basic models (tree + shrub), but I had been noticing some glitching that was occuring with the models. Knowing this, I rendered a flat plane of "water" onto my world and it showed what I had thought. I am still unsure of what is wrong here, any insight would be helpful!

Note: I am using LWJGL The plane of "water" is flat, and the area that it is in is concave, so no part of it sticks above the "water"


Answer:

FIXED: This is the result of having too small of a zNear value when calculating projection method. If you dont know what that is, search up how to create a projection matrix 3d and it will explain :) Finally solved it and can get moving with my game, hope this can help others!

Question:

I am starting to create GUI for my 3D OpenGL game and for that I use the fixed - pipeline functionality.

This is what I am trying to do:

Enable 2d:

public void Enable2D() {
      //GL11.glDisable(GL11.GL_LIGHTING);
      GL11.glMatrixMode(GL11.GL_PROJECTION);
      GL11.glPushMatrix();
      GL11.glLoadIdentity();
      GL11.glOrtho(0, Display.getDisplayMode().getWidth(),
                Display.getDisplayMode().getHeight(), 0, -1, 1);
      GL11.glDisable(GL11.GL_DEPTH_TEST);
      //GL11.glDisable(GL11.GL_CULL_FACE);
      GL11.glEnable(GL11.GL_TEXTURE_2D);
      GL11.glMatrixMode(GL11.GL_MODELVIEW);
      GL11.glPushMatrix();
      GL11.glLoadIdentity();
   }

Render the quad:

GL11.glColor3f(0.5f,0.5f,1.0f);
    // draw quad
    GL11.glBegin(GL11.GL_QUADS);
        GL11.glVertex2f(boundingBox.getLocation().x,boundingBox.getLocation().y);
        GL11.glVertex2f(boundingBox.getLocation().x+boundingBox.getSize().x,boundingBox.getLocation().y);
        GL11.glVertex2f(boundingBox.getLocation().x+boundingBox.getSize().x,boundingBox.getLocation().y+boundingBox.getSize().y);
        GL11.glVertex2f(boundingBox.getLocation().x,boundingBox.getLocation().y+boundingBox.getSize().y);
    GL11.glEnd();

Disable 2d:

  public void Disable2D() {
     // GL11.glEnable(GL11.GL_LIGHTING);
      GL11.glEnable(GL11.GL_DEPTH_TEST);
      GL11.glDisable(GL11.GL_TEXTURE_2D);
      //GL11.glEnable(GL11.GL_CULL_FACE);
      GL11.glMatrixMode(GL11.GL_PROJECTION);
      GL11.glPopMatrix();
      GL11.glMatrixMode(GL11.GL_MODELVIEW);
      GL11.glPopMatrix();
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
   }

This doesn't render the QUAD. Yet the weird part is that I am drawing text as well using Slick2D font rendering and it works perfectly. Just this quad doesn't get rendered.

Why is this happening?

EDIT: Here is my GL Init code, see if you can maybe spot something that would cause this behaviour:

    GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight());
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GLU.gluPerspective(FIELD_OF_VIEW,
            ((float) Display.getWidth() / (float) Display.getHeight()),
            NEAR_DISTANCE, FAR_DISTANCE);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glLoadIdentity();
    GL11.glShadeModel(GL11.GL_SMOOTH);
    GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);

    // FUNCTIONS
    GL11.glClearColor(204f / 255f, 1f, 248f / 255f, 0.0f); // Blueish
                                                            // Background
    GL11.glClearDepth(1.0f); // Depth Buffer Setup
    GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
    GL11.glDepthMask(true);
    GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Test To Do
    GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST); // Really Nice
    // Perspective Calculations
    GL11.glEnable(GL11.GL_CULL_FACE);
    GL11.glCullFace(GL11.GL_BACK);
    GL11.glEnable(GL11.GL_BLEND);
    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

    GL11.glEnable(GL11.GL_LIGHTING);
    // LIGHTING
    float lightAmbient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; // Ambient Light
                                                        // Values
    float lightDiffuse[] = { 1.3f, 1.3f, 1.3f, 1.0f }; // Diffuse Light
                                                        // Values
    float lightPosition[] = { 35f, 500f, 35f, 1.0f }; // Diffuse Light
                                                        // Values

    ByteBuffer temp = ByteBuffer.allocateDirect(16);
    temp.order(ByteOrder.nativeOrder());
    GL11.glEnable(GL11.GL_LIGHT0);
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, (FloatBuffer) temp
            .asFloatBuffer().put(lightAmbient).flip()); // Setup The Ambient
                                                        // Light
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, (FloatBuffer) temp
            .asFloatBuffer().put(lightDiffuse).flip()); // Setup The Diffuse
                                                        // Light
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, (FloatBuffer) temp
            .asFloatBuffer().put(lightPosition).flip()); // Setup The
                                                            // Diffuse Light

    // calculate the lighting for both front and back faces correctly
    //GL11.glLightModeli(GL11.GL_LIGHT_MODEL_TWO_SIDE, GL11.GL_TRUE);

    GL11.glEnable(GL11.GL_COLOR_MATERIAL);
    GL11.glColorMaterial(GL11.GL_FRONT_AND_BACK,
            GL11.GL_AMBIENT_AND_DIFFUSE);


    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glEnable(GL11.GL_NORMALIZE);

Answer:

What I ended up doing is use VBOs to render. Didn't take too long to implement and the result was awesome. I use a VBO per GUI Element type. I truly recommend not to use GL11 even for this basic type of stuff. Just stick with the 'advanced methods'.

Question:

The problem

I am having trouble rendering absolutely anything with LWJGL 3. It will not render anything, whilst creating the GLFW display and clearing the color successfully.

The tools
  • Eclipse Neon (Java IDE)
  • LWJGL 3.1.1 build 16 with GLFW, JAWT and OPENGL bindings, natives.
The code
package init;

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.nio.IntBuffer;

import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryStack;

import exception.ExceptionHandler;
import util.Time;

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

public class DisplayInstance {

    public String title = "The SuperMatrix";
    public GraphicsDevice gd;
    public Game game;
    public Config conf;
    private long display;

    private GLFWErrorCallback glfwerrorcallback;

    public DisplayInstance(Game game) {

        this.gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        this.game = game;
        this.conf = Config.returnConfig(this);
        this.glfwerrorcallback = GLFWErrorCallback.createPrint(System.err);
        this.glfwerrorcallback.set();
        this.start();

    }

    public void start() {

        if (!glfwInit()) 
            ExceptionHandler.handleException(new IllegalStateException("Cannot initialize GLFW"));

        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

        this.display = glfwCreateWindow(this.conf.width, this.conf.height, this.title, 0, 0);
        if (this.display == 0L) {

            ExceptionHandler.handleException(new RuntimeException("Cannot create GLFW window"));

        }

        System.out.println(this.display);

        try (MemoryStack stack = stackPush()) {

            IntBuffer pWidth = stack.mallocInt(1);
            IntBuffer pHeight = stack.mallocInt(1);

            glfwGetWindowSize(this.display, pWidth, pHeight);
            GLFWVidMode mode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            glfwSetWindowPos(this.display,
                    (mode.width()-pWidth.get(0))/2,
                    (mode.height()-pHeight.get(0))/2
                    );

        } catch (Exception e) {
            ExceptionHandler.handleException(e);
        }

        glfwMakeContextCurrent(this.display);
        glfwSwapInterval(1);
        glfwShowWindow(this.display);

        this.loop();

    }

    public void loop() {

        GL.createCapabilities();

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0,this.conf.width, 0, this.conf.height, -1, 1);
        glMatrixMode(GL_MODELVIEW);
        glDisable(GL_DEPTH_TEST);

        Time time = new Time();

        while(!glfwWindowShouldClose(this.display)) {

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glfwSwapBuffers(this.display);
            glfwPollEvents();
            glPushMatrix();

            glBegin(GL_QUADS);

            glColor3f(1,0,1);
            glVertex2f(0, 0);
            glVertex2f(0, 64);
            glVertex2f(64, 64);
            glVertex2f(64, 0);

            glEnd();

            glPopMatrix();

            float deltaSeconds = time.getDelta()/Time.SECOND;
            float fps = deltaSeconds;
            System.out.println(fps);

        }

        this.destroy();

    }

    public void destroy() {

        glfwFreeCallbacks(this.display);
        glfwDestroyWindow(this.display);

        glfwTerminate();
        this.glfwerrorcallback.free();

        this.game.stopGame();

    }

}

Thank you. Absolutely any help would be appreciated.


Answer:

Alright, I finally found the answer.

The cause of the problem

The problem was that I called glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) right before I called glfwSwapBuffers(this.display):

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(this.display);

This essentially means that I clear the buffers right before I show them.

The fix

To fix this, all I had to do is move glfwSwapBuffers(this.display) down to after the glPopMatrix() call. Here is how the loop() function looks like now:

    GL.createCapabilities();

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0,this.conf.width, 0, this.conf.height, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glDisable(GL_DEPTH_TEST);

    Time time = new Time();

    while(!glfwWindowShouldClose(this.display)) {

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glfwPollEvents();
        glPushMatrix();

        glBegin(GL_QUADS);

        glColor3f(1,0,1);
        glVertex2f(0, 0);
        glVertex2f(0, 64);
        glVertex2f(64, 64);
        glVertex2f(64, 0);

        glEnd();

        glPopMatrix();
        glfwSwapBuffers(this.display);

        float deltaSeconds = time.getDelta()/Time.SECOND;
        float fps = deltaSeconds;
        System.out.println(fps);

    }

    this.destroy();
Everybody, have a great day!

P.S. Please don't mind the FPS system, I'm still trying to figure it out.

Question:

I'm following an online tutorial regarding building a game engine using LWJGL, I'm coming along great and really try to understand the code I'm being taught, however I now get this error and I really don't know what I'm doing wrong.

I tried adding specular lighting, this is the tutorial I'm following if that helps: https://www.youtube.com/watch?v=GZ_1xOm-3qU&index=12&list=PLRIWtICgwaX0u7Rf9zkZhLoLuZVfUksDP

When I try to run my application this shows in my console:

Could not compile shader.
0(25) : error C1101: ambiguous overloaded function reference "mul(mat4, vec3)"
(0) : mat3x4 mul(mat3x1, mat1x4)
(0) : mat3 mul(mat3x1, mat1x3)
(0) : mat3x2 mul(mat3x1, mat1x2)
(0) : mat3x1 mul(mat3x1, mat1)
(0) : mat2x4 mul(mat2x1, mat1x4)
(0) : mat2x3 mul(mat2x1, mat1x3)
(0) : mat2 mul(mat2x1, mat1x2)
(0) : mat2x1 mul(mat2x1, mat1)
(0) : mat1x4 mul(mat1x3, mat3x4)
(0) : mat1x3 mul(mat1x3, mat3)
(0) : mat1x2 mul(mat1x3, mat3x2)
(0) : mat1 mul(mat1

This is the method that's outputting those messages:

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);
}

I hope anyone could help fixing this, thanks in advance :)

With kind regards, Stan

EDIT: Here's my shader code (indeed written in GLSL)

vertexShader.txt:

#version 400 core

in vec3 position;
in vec2 textureCoords;
in vec3 normal;

out vec2 pass_textureCoords;
out vec3 surfaceNormal;
out vec3 toLightVector;
out vec3 toCameraVector;

uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 lightPosition;

void main(void) {

    vec4 worldPosition = transformationMatrix * vec4(position, 1.0);
    gl_Position = projectionMatrix * viewMatrix * worldPosition;
    pass_textureCoords = textureCoords;

    surfaceNormal = (transformationMatrix * vec4(normal, 0.0)).xyz;
    toLightVector = lightPosition - worldPosition.xyz;
    toCameraVector = inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0).xyz - worldPosition.xyz;
}

fragmentShader.txt

#version 400 core

in vec2 pass_textureCoords;
in vec3 surfaceNormal;
in vec3 toLightVector;
in vec3 toCameraVector;

out vec4 out_Color;

uniform sampler2D textureSampler;
uniform vec3 lightColour;
uniform float shineDamper;
uniform float reflectivity; 


void main(void) {

    vec3 unitNormal = normalize(surfaceNormal);
    vec3 unitLightVector = normalize(toLightVector);

    float nDotl = dot(unitNormal, unitLightVector);
    float brightness = max(nDotl, 0.0);
    vec3 diffuse = brightness * lightColour;

    vec3 unitVectorToCamera = normalize(toCameraVector);
    vec3 lightDirection = -unitLightVector;
    vec3 reflectedLightDirection = reflect(lightDirection, unitNormal);

    float specularFactor = dot(reflectedLightDirection, unitVectorToCamera);
    specularFactor = max(specularFactor, 0.0);
    float dampedFactor = pow(specularFactor, shineDamper);
    vec3 finalSpecular = dampedFactor * lightColour;

    out_Color = vec4(diffuse, 1.0) * texture(textureSampler, pass_textureCoords) + vec4(finalSpecular, 1.0);

}

Answer:

I'm not an expert in GLSL but the error message seems to suggest that you are trying to multiply a mat4 by a vec3, for which there is no multiply function available.

You are trying to do this in this line:

toCameraVector = inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0).xyz - worldPosition.xyz;

Note that inverse(viewMatrix) is a mat4 and vec4(0.0, 0.0, 0.0, 1.0).xyz is a vec3.

You probably want to do something like this instead:

toCameraVector = (inverse(viewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz - worldPosition.xyz;

Question:

import static org.lwjgl.glfw.GLFW.*;
import  static org.lwjgl.opengl.GL11.*;
import  static org.lwjgl.opengl.GL20.*;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import  static org.lwjgl.opengl.GL15.*;

import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFWCursorPosCallback;
import   org.lwjgl.opengl.GL;


import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;



public class man {
private static final int VERTEX_COUNT = 128;
private static final float SIZE = 1;
public static int count;
public static int vid;
public static int iid;


public static int program;

public static float fov = 70f;
public static float near = 0.1f;
public static float far = 1000f;

public static Matrix4f modelMatrix = new Matrix4f() ;
public static Matrix4f view = new Matrix4f();

public static Matrix4f projectionmatrix = new Matrix4f();




public static GLFWCursorPosCallback mouseCallback;

public static boolean t = true;
    public static void main(String[] argv) throws IOException {

        glfwInit();
        int prog = 0 , id=0;
      long window =  glfwCreateWindow(1920, 
              1080, "HI", 0 , 0);


      glfwShowWindow(window);


      glfwMakeContextCurrent(window);


      GL.createCapabilities();



    //  glfwSetCursorPosCallback(window, mouseCallback = new mouse());


      while (!glfwWindowShouldClose(window))
      {





          glfwSwapBuffers(window);
          glfwPollEvents();

           new man().createShader();
          new man().bind();





        GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);
        GL11.glEnable(GL11.GL_DEPTH_TEST);

        GL11.glLoadIdentity();

        glEnable(GL_PROJECTION_MATRIX);
        glEnable(GL_PROJECTION);



        new man().createprojection();
        new man().createview();

        glUseProgram(program);

        new man().loadtoshader();
         glEnableClientState(GL_VERTEX_ARRAY);
        glBindBuffer(GL_ARRAY_BUFFER, vid);
        glVertexPointer(3, GL_FLOAT , 0, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iid);

        glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0);


        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glDisable(GL_VERTEX_ARRAY);


      }

    }






    public void createShader() throws IOException
    {
        StringBuilder vertex = new StringBuilder();
        StringBuilder  frag = new StringBuilder();
        BufferedReader vert ,fragment;
        vert = new BufferedReader(new FileReader("D:/work/opengl2/src/opengl2/vertexShader.txt"));
        fragment = new BufferedReader(new FileReader("D:/work/opengl2/src/opengl2/frageShader.txt"));
        //vertex Shader

        String line, line2;
        while ( (line =  vert.readLine()) != null)
        {
            vertex.append(line).append('\n');
        }
        while ( (line2 =  fragment.readLine()) != null)
        {
            frag.append(line2).append('\n');
        }
        //create and comile shaders
            int vertexShader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
            GL20.glShaderSource(vertexShader, vertex);
            GL20.glCompileShader(vertexShader);
            int fragmentShader = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
            GL20.glShaderSource(fragmentShader, frag);
            GL20.glCompileShader(fragmentShader);
             program = GL20.glCreateProgram();


            GL20.glAttachShader(program, vertexShader);
            GL20.glAttachShader(program, fragmentShader);           
            GL20.glBindAttribLocation(program, 0 , "postion");


            GL20.glLinkProgram(program);


            if (GL20.glGetProgrami(program, GL20.GL_LINK_STATUS) != 1)
            {
                System.err.println(GL20.glGetProgramInfoLog(program));
                System.exit(1);
            }


            GL20.glValidateProgram(program);

    }



    public void bind()
    {

        float[] vertices = new float[128 * 128 * 3];
        int[] indices = new int[6*(VERTEX_COUNT-1)*(VERTEX_COUNT-1)];


     //generaete terrain 



        int vertexPointer = 0;
        for(int i=0;i<VERTEX_COUNT;i++){
            for(int j=0;j<VERTEX_COUNT;j++){
                vertices[vertexPointer*3] = (float)j/((float)VERTEX_COUNT - 1) * SIZE;
                vertices[vertexPointer*3+1] = 0;
                vertices[vertexPointer*3+2] = (float)i/((float)VERTEX_COUNT - 1) * SIZE;

                vertexPointer++;
            }
        }
        int pointer = 0;
        for(int gz=0;gz<VERTEX_COUNT-1;gz++){
            for(int gx=0;gx<VERTEX_COUNT-1;gx++){
                int topLeft = (gz*VERTEX_COUNT)+gx;
                int topRight = topLeft + 1;
                int bottomLeft = ((gz+1)*VERTEX_COUNT)+gx;
                int bottomRight = bottomLeft + 1;
                indices[pointer++] = topLeft;
                indices[pointer++] = bottomLeft;
                indices[pointer++] = topRight;
                indices[pointer++] = topRight;
                indices[pointer++] = bottomLeft;
                indices[pointer++] = bottomRight;
            }
        }



    //end generate terrain

        FloatBuffer buffer = BufferUtils.createFloatBuffer(vertices.length);
        buffer.put(vertices);
        buffer.flip();

        count = indices.length ;

         vid = GL15.glGenBuffers();
         GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vid);
         GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);



         iid = GL15.glGenBuffers();
         GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, iid);
         IntBuffer indbuf = BufferUtils.createIntBuffer(indices.length);
         indbuf.put(indices);
         indbuf.flip();

         GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indbuf, GL15.GL_STATIC_DRAW);
         GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
         GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);


    }



    public void createprojection()
    {

        float aspect = (float) 1920/1080;

        float y_scale = (float) (1/Math.tan(Math.toRadians(fov/2f)));
        float x_scale = y_scale / aspect;
        float frustum_length = far - near;

        projectionmatrix.m00 = x_scale;
        projectionmatrix.m11 = y_scale;
        projectionmatrix.m22 = -((far + near) / frustum_length);
        projectionmatrix.m23 = -1;
        projectionmatrix.m32 = -((2 * near * far) / frustum_length);
        projectionmatrix.m33 = 0;

    }

    public void createview()
    {

        Vector3f modelPos = null;
        Vector3f modelAngle = null;
        Vector3f modelScale = null;
        Vector3f camera = new Vector3f(0,1f,-2f);

        modelPos = new Vector3f(0,0,0);
        modelAngle = new Vector3f(0,0,0);
        modelScale = new Vector3f(1, 1, 1);



        modelMatrix.setIdentity();
        Matrix4f.scale(modelScale, modelMatrix, modelMatrix);
        Matrix4f.translate(modelPos, modelMatrix, modelMatrix);
        Matrix4f.rotate((float) Math.toRadians(modelAngle.z), new Vector3f(0, 0, 1), 
                modelMatrix, modelMatrix);
        Matrix4f.rotate((float) Math.toRadians(modelAngle.y), new Vector3f(0, 1, 0), 
                modelMatrix, modelMatrix);
        Matrix4f.rotate((float) Math.toRadians(modelAngle.x), new Vector3f(1, 0, 0), 
                modelMatrix, modelMatrix);



            Matrix4f.translate(camera, view, view);




    }



    public void loadtoshader()
    {

        int loc1 = glGetUniformLocation(program, "projection"); 

        FloatBuffer matrixx  = BufferUtils.createFloatBuffer(16);
        projectionmatrix.store(matrixx);
        matrixx.flip();

            glUniformMatrix4fv(loc1, false,matrixx);

            int loc2 = glGetUniformLocation(program, "view"); 

            FloatBuffer matrixx2  = BufferUtils.createFloatBuffer(16);
            view.store(matrixx2);
            matrixx2.flip();

            glUniformMatrix4fv(loc2, false,matrixx2);


                int loc3 = glGetUniformLocation(program, "model"); 

                FloatBuffer matrixx3  = BufferUtils.createFloatBuffer(16);
                modelMatrix.store(matrixx3);
                matrixx3.flip();

                glUniformMatrix4fv(loc3, false,matrixx3);
    }






}






class mouse extends GLFWCursorPosCallback
{

    @Override
    public void invoke(long arg0, double x, double y) {
        // TODO Auto-generated method stub

    System.out.println(x+ " "+ y );

    }

}

Hi guys ! I want to generate a simple flat terrain in lwjgl but this code doesn't produce me anything. I am very new in this chapter so if you can explain why this code does nothing please do it! I am generating the terrain with the code shared by ThinMatrix , then i upload the vertices to the buffers and then render them in the main game loop . When i compile it , it shows me a black screen. I have searched for a lot of tutorials but I didn't find anything that can help me .


Answer:

I see several issues with your code:

Issue Number 1: You are generating a new instance of the man class on every iteration of the loop. Create a single instance of the object outside of the loop and use it in the loop.

Issue Number 2: You are using the old, static pipeline OpenGL. Following ThinMatrix's tutorials, you should be using OpenGL 3 or newer. Everything should be going through shaders, rather than using the GL_PROJECTION_MATRIX and the likes of that.

Your program should look something like the following:

man instance = new man() while (!glfwWindowShouldClose(window)) { RENDER THE TERRAIN HERE glfwPoll glfwSwapBuffers glClear }

If you want some example code, I have a repository here that should help, as I used to watch ThinMatrix tutorials.

EDIT: SOLUTION

The vertex shader code should read:

gl_Position = projection * view * model * position;

Question:

I am working on a Java + LWJGL Project. Currently I am trying to implement Variance Shadow Mapping, but only the first shadow map that I sample in my shader shows up at the correct position.

Fragment shader:

#version 330 core

in vec2 passTexCoords;
in vec4[4] shadowCoords;

//Fragment color
out vec4 out_Color;

uniform sampler2D modelTexture;
uniform sampler2D[4] shadowMaps;

#define SHADOW_BIAS 0.0005

float linstep(float low, float high, float v) {
    return clamp((v-low)/(high-low), 0.0, 1.0);
}

//compare ... The depth of the fragment in shadow map sapce
float sampleVarianceShadowMap(in sampler2D shadowMap, in vec2 coords, in float compare) {

    /* This is the Code that I want to use when I know what the problem was.
    vec2 moments = texture(shadowMap, coords.xy).rg;

    float p = step(compare, moments.x);
    float variance = max(moments.y - moments.x * moments.x, 0.00002);

    float d = compare - moments.x;
    float pMax = linstep(0.2, 1.0, variance / (variance + d*d));

    return min(max(p, pMax), 1.0);
    */

    //============================================================================HERE=========================================================================HERE====================
    //THE ERROR OCCURES HERE:

    //This doesn't work:
    float visibility = step(compare-SHADOW_BIAS, texture(shadowMap, coords.xy).r);  
    return visibility;

    //The shadows on the ground move in a weird way when the camera moves.

    //But this does:
    return step(compare-SHADOW_BIAS, texture(shadowMap, coords.xy).r);

    //With this code the shadows are at the correct place.

    //===========================================================================HERE==========================================================================HERE=====================
}

//To create a smooth darkness falloff at the edge of the shadow map
float calcShadowMapVisibilityFalloff(in vec2 coords, in float falloffStart, in float gradient) {
    float distFromTexCenter = length(coords * vec2(2.0) - vec2(1.0));
    float falloff = (clamp(pow(distFromTexCenter, gradient), falloffStart, 1.0) - falloffStart) * (1/(1-falloffStart));

    if(falloff > 1.0 || falloff < 0.0) {
        falloff = 0;
    }

    return 1-falloff;
}

void main(void){

    float shadowInvertedBrightness = 1.0;
    for(int i = 0; i < shadowMaps.length(); i++)
    {
        float visibility = 1 - sampleVarianceShadowMap(shadowMaps[i], shadowCoords[i].xy, shadowCoords[i].z);
        shadowInvertedBrightness -= (visibility / shadowMaps.length()) * calcShadowMapVisibilityFalloff(shadowCoords[i].xy, 0.85, 2.0);
    }

    shadowInvertedBrightness = clamp(shadowInvertedBrightness, 0.2, 1.0);

    //.bgra because I save textures with the BGRA format (I've read its faster)
    out_Color = texture(modelTexture, passTexCoords).bgra * vec4(shadowInvertedBrightness,shadowInvertedBrightness,shadowInvertedBrightness,1);
}

Vertex Shader:

#version 330 core

//Vertex coords
in vec3 position;
//Texture coords
in vec2 texCoords;

//The MVP matrix of the entity
uniform mat4 MVPMat;
//The "To Shadow Map Space" matrix
uniform mat4[4] shadowMVPBiasMats;
//The Transformation matrix of the entity
uniform mat4 transformMat;

out vec2 passTexCoords;
//Shadow map sample coords
out vec4[4] shadowCoords;

void main(void) {
    gl_Position = MVPMat * vec4(position, 1.0);

    vec4 worldPos = transformMat * vec4(position, 1.0);

    for(int i = 0; i < shadowMVPBiasMats.length(); i++) {
        shadowCoords[i] = shadowMVPBiasMats[i] * worldPos;
    }

    passTexCoords = texCoords;
}

Full Code (Example Project that you can import in Eclipse) and Screenshots:

System Information:

  • OS: Windows Home, Version: 10.0.15063
  • GPU: Intel HD Graphics 520
  • GPU Driver Version: 20.19.15.4642 (By Medion)

Answer:

It seems to be an bug in the driver, because it doesn't happen when I run the program with my NVIDIA GPU.

A Workaround for the problem:

float textureShadowMap(in sampler2D shadowMap, in vec2 coords) {
    return texture(shadowMap, coords).r;
}

And in the sampleVarianceShadowMap Method:

float visibility = step(compare-SHADOW_BIAS, textureShadowMap(shadowMap, coords));  
return visibility;

Since I am not 100% sure that it is a bug, it would be nice if someone can confirm this.

Question:

Background Info:

I am using OpenGL and LWJGL 3 to draw some quads onto the screen. I need to know when the mouse is over a quad. When I render the quads to the screen, I use the OpenGL coordinates, ranging from -1 to 1 for both X and Y and with (0,0) at the center of the screen. When I get the mouse position I use

glfwSetCursorPosCallback();

which gives me the coordinates ranging from 0 to the width or height of the window and with (0,0) at the top left corner (below the title bar). I then take the mouse coordinate and calculate the OpenGL coordinates.

For example if my window size is (800, 600) and my mouse was at (200, 200) I would get (-0.5, 0.33) [since (400, 300) would map to (0, 0) in OpenGL's coordinates].

So here's my problem:

OpenGL includes the title bar in its coordinates, where as glfwSetCursorPosCallback(); does not. This means that if I render a vertex at (-0.5, 0.33) [like in my example] it renders at around (200, ~210).

As you can see, because the two coordinate systems cover different areas, its more difficult to switch between the coordinate systems.

I have searched for ways to exclude the title bar from OpenGL's coordinates, to completely get rid of the title bar and to get the height of the title bar (so I can include it in my calculations and make the correct adjustments). I haven't been able to figure out how to do any of these, so I'm looking for a way to do so, or a different method that will resolve my problem.

EDIT 1: Adding Code

@Nicol Bolas informed me that this is not how OpenGL normally works so there must be something causing this in my code. I believe I've provided the parts of my code that would be responsible for my problem:

Here is my Renderer class [I am using the drawQuad() method]

Note: I am not currently using the view, model, or projection matrices in my shaders.

public class Renderer {

    private VertexArrayObject vao;
    private VertexBufferObject vbo;
    private ShaderProgram shaderProgram;

    private FloatBuffer vertices;
    private int numVertices;
    private boolean drawing;

    //private Font font;
    //private Font debugFont;


    public void drawQuad(float x, float y, float width, float height, Color c) {
    /* Calculate Vertex positions */
        float x1 = x;
        float y1 = y;
        float x2 = x + width;
        float y2 = y - height;

    /* Calculate color */
        float r = c.getRed();
        float g = c.getGreen();
        float b = c.getBlue();

    /* Put data into buffer */
        vertices.put(x1).put(y1).put(0.0f).put(r).put(g).put(b);
        vertices.put(x1).put(y2).put(0.0f).put(r).put(g).put(b);
        vertices.put(x2).put(y2).put(0.0f).put(r).put(g).put(b);
        vertices.put(x2).put(y1).put(0.0f).put(r).put(g).put(b);

    /* We drawed X vertices */
        numVertices += 4;
    }


    // Initialize renderer
    public void init(){

        // Set up shader programs
        setupShaderProgram();

        // Enable blending (?????)
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    }

    // Clears drawing area
    public void clear() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    // Begin rendering
    public void begin() {
        if (drawing) throw new IllegalStateException("Renderer is already drawing.");
        drawing = true;
        numVertices = 0;
    }

    // End rendering
    public void end() {
        if (!drawing) throw new IllegalStateException("Renderer is not drawing.");
        drawing = false;
        flush();
    }

    // Flushes data to GPU to get rendered
    public void flush() {
        if (numVertices > 0) {
            vertices.flip();

            if (vao != null) vao.bind();
            else vbo.bind(GL_ARRAY_BUFFER);
            specifyVertexAttributes();
        }
        shaderProgram.use();

        // Upload the new vertex data
        vbo.bind(GL_ARRAY_BUFFER);
        vbo.uploadSubData(GL_ARRAY_BUFFER, 0, vertices);

        // Draw batch
        glDrawArrays(GL_QUADS, 0, numVertices);

        // Clear vertex data for next batch
        vertices.clear();
        numVertices = 0;
    }

    private void setupShaderProgram() {

        // Generate VertexArrayObject
        if (Game.is32Supported()) {
            vao = new VertexArrayObject();
            vao.bind();
        } else {
            throw new RuntimeException("OpenGL 3.2 not supported.");
        }

        // Generate VertexBufferObject
        vbo = new VertexBufferObject();
        vbo.bind(GL_ARRAY_BUFFER);

        // Create FloatBuffer
        vertices = MemoryUtil.memAllocFloat(4096);

        // Upload null data to allocate storage for the VBO
        long size = vertices.capacity() * Float.BYTES;
        vbo.uploadData(GL_ARRAY_BUFFER, size, GL_DYNAMIC_DRAW);

        // Initialize variables
        numVertices = 0;
        drawing = false;

        // Load Shaders:
        Shader vertexShader, fragmentShader;
        if (Game.is32Supported()) {
            vertexShader = Shader.loadShader(GL_VERTEX_SHADER, "res/shaders/vshader.vert");
            fragmentShader = Shader.loadShader(GL_FRAGMENT_SHADER, "res/shaders/fshader.frag");
        } else {
            throw new RuntimeException("OpenGL 3.2 not supported.");
        }

        // Create ShaderProgram
        shaderProgram = new ShaderProgram();
        shaderProgram.attachShader(vertexShader);
        shaderProgram.attachShader(fragmentShader);
        if (Game.is32Supported()) {
            shaderProgram.bindFragmentDataLocation(0, "fragColor");
        }
        shaderProgram.link();
        shaderProgram.use();

        // Delete linked shaders
        vertexShader.delete();
        fragmentShader.delete();

        // Get width & height of framebuffer
        long window = GLFW.glfwGetCurrentContext();
        int width, height;
        try (MemoryStack stack = MemoryStack.stackPush()) {
            IntBuffer widthBuffer = stack.mallocInt(1);
            IntBuffer heightBuffer = stack.mallocInt(1);
            GLFW.glfwGetFramebufferSize(window, widthBuffer, heightBuffer);
            width = widthBuffer.get();
            height = heightBuffer.get();
        }

        // Specify vertex pointers
        specifyVertexAttributes();

        // Set Model Matrix to identity matrix
        Matrix4f model = new Matrix4f();
        int uniModel = shaderProgram.getUniformLocation("model");
        shaderProgram.setUniform(uniModel, model);

        // Set View Matrix to identity matrix
        Matrix4f view = new Matrix4f();
        int uniView = shaderProgram.getUniformLocation("view");
        shaderProgram.setUniform(uniView, view);

        // Set Projection Matrix to an orthographic projection
        Matrix4f projection = Matrix4f.orthographic(0f, width, 0f, height, -1f, 1f);
        int uniProjection = shaderProgram.getUniformLocation("projection");
        shaderProgram.setUniform(uniProjection, projection);

    }

    // Specifies the vertex shader pointers (attributes)
    private void specifyVertexAttributes() {

        int posAttrib = shaderProgram.getAttributeLocation("position");
        shaderProgram.enableVertexAttribute(posAttrib);
        shaderProgram.pointVertexAttribute(posAttrib, 3, 6 * Float.BYTES, 0);

        int colAttrib = shaderProgram.getAttributeLocation("color");
        shaderProgram.enableVertexAttribute(colAttrib);
        shaderProgram.pointVertexAttribute(colAttrib, 3, 6 * Float.BYTES, 3 * Float.BYTES);

    }

}

And here is my init() method that creates and sets up my window:

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_FALSE); // the window will be resizable

    // ONLY ON MAC OSX (?)
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Tell GLFW to use OpenGL verison 3.x
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Tell GLFW to use OpenGL version x.2 (combined -> 3.2)
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // Should be forward compatible

    // Create the window
    window = glfwCreateWindow(WIDTH, HEIGHT, "Game_19_v0.0.1", 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);

    // 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();

    // Input
    glfwSetCursorPosCallback(window, cursorPosCallback = new MouseInput());

    // Create renderer
    renderer = new Renderer();
    renderer.init();

    // To Render:
    buttonManager = new ButtonManager();

}

EDIT 2: Temporary Solution

I was able to use glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); to remove the entire border from the window, title bar included, which fixed the issue. Now however, I obviously don't have the options to close, minimize, etc., on my window, although I suppose I can program those in myself if necessary. Will update if I find out any other solutions.


Answer:

GLFW functions typically work with the client area of a window (the inside window area not including titlebars, scrollbars, etc.) so glfwSetCursorPosCallback is giving you the expected values. If your OpenGL framebuffer is for some reason rendering things behind the title bar (whether it's an improper setup or just a platform specific detail) you should still be able to get the title bar size using glfwGetWindowFrameSize:

IntBuffer pLeft = stack.mallocInt(1); // int*
IntBuffer pTop = stack.mallocInt(1); // int*
IntBuffer pRight = stack.mallocInt(1); // int*
IntBuffer pBottom = stack.mallocInt(1); // int*

// Get the window border sizes
glfwGetWindowFrameSize(window, pLeft, pTop, pRight, pBottom);

(Disclaimer: I'm just following the syntax from your code above since I'm only familiar with the C++ API.)

The size of the title bar will be stored in the top variable and can then be added to whatever value you get from glfwSetCursorPosCallback and glfwGetWindowSize.

float adjustedYpos = ypos + top;
float adjustedHeight = height + top;
float normalizedY = adjustedYpos / adjustedHeight;
float openglY = normalizedY * -2.0f - 1.0f

This openglY value should be the OpenGL [-1, 1] clip-space coordinate adjusted based on the title bar size.

Question:

I am rendering a simple quad and have been experimenting with shaders. It worked fine, but I followed a texturing tutorial to add textures and I must have changed something. Because now, even though all the texturing code is commented out, the quad doesn't render when I turn shaders on. I suspect it has something to do with the data binding, as I am still trying to learn it. I can't for the life of me find what's wrong! Shaders (vertex and fragment):

//vertex
#version 400 core

in vec3 position;
out vec3 colour;

void main (void) {

colour = vec3(position.x + 0.5, 1.0, position.y + 0.5);

}

//fragment
#version 400 core

in vec3 colour;
out vec4 out_Colour;

void main (void) {

out_Colour = vec4(colour, 1.0);

}

Shader program:

public abstract class ShaderProgram {

private int programId;
private int vertexId;
private int fragmentId;

public ShaderProgram (String vertexFile, String fragmentFile) {

    vertexId = loadShader(vertexFile, GL20.GL_VERTEX_SHADER);
    fragmentId = loadShader(fragmentFile, GL20.GL_FRAGMENT_SHADER);
    programId = GL20.glCreateProgram();
    GL20.glAttachShader(programId, vertexId);
    GL20.glAttachShader(programId, fragmentId);
    bindAttributes();
    GL20.glLinkProgram(programId);
    GL20.glValidateProgram(programId);


}

public void start () {
    GL20.glUseProgram(programId);
}

public void stop () {
    GL20.glUseProgram(0);
}

public void cleanUp () {
    stop();
    GL20.glDetachShader(programId, vertexId);
    GL20.glDetachShader(programId, fragmentId);
    GL20.glDeleteShader(vertexId);
    GL20.glDeleteShader(fragmentId);
    GL20.glDeleteProgram(programId);
}

protected abstract void bindAttributes ();

protected void bindAttribute (int attribute, String variableName) {
    GL20.glBindAttribLocation(programId, attribute, variableName);
}

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) {
        System.err.println("Could not read shader file!");
        e.printStackTrace();
        System.exit(-1);
    }
    int shaderId = GL20.glCreateShader(type);
    GL20.glShaderSource(shaderId, shaderSource);
    GL20.glCompileShader(shaderId);
    if (GL20.glGetShaderi(shaderId, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
        System.err.println(GL20.glGetShaderInfoLog(shaderId));
        System.err.println("Could not compile shader!");
        System.exit(-1);
    }
    return shaderId;
}

}

Main shader (extends Shader program):

public class MainShader extends ShaderProgram {

private static final String VERTEX_FILE = "src/shaders/vertexShader.txt";
private static final String FRAGMENT_FILE = "src/shaders/fragmentShader.txt";

public MainShader() {
    super(VERTEX_FILE, FRAGMENT_FILE);
}

@Override
protected void bindAttributes() {
    super.bindAttribute(ModelLoader.VERTEX_INDICE, "position");
    //super.bindAttribute(1, "uv");
}

}

Model loader:

public class ModelLoader {

private static List<Integer> vaos = new ArrayList<Integer>();
private static List<Integer> vbos = new ArrayList<Integer>();
private static List<Integer> textures = new ArrayList<Integer>();
public static final int VERTEX_INDICE = 0;
public static final int UV_INDICE = 1;

public static RawModel loadToVAO (float[] positions, int[] indices) {

    int vaoId = createVAO();
    bindIndicesBuffer(indices);
    storeDataInAttributeList(VERTEX_INDICE, 3, positions);
    //storeDataInAttributeList(UV_INDICE, 2, uvCoords);
    unbindVAO();
    return new RawModel(vaoId, indices.length);

}

/*public static int loadTexture (String file, int textureUnit) {

    try {
        return TextureLoader.loadTexture("rsrc/" + file + ".png", GL11.GL_TEXTURE_2D);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return 0;
}*/

public static int loadTexture(String file, int textureUnit) {
    String filename = "rsrc/" + file + ".png";
    ByteBuffer buf = null;
    int tWidth = 0;
    int tHeight = 0;

    try {
        // Open the PNG file as an InputStream
        InputStream in = new FileInputStream(filename);
        // Link the PNG decoder to this stream
        PNGDecoder decoder = new PNGDecoder(in);

        // Get the width and height of the texture
        tWidth = decoder.getWidth();
        tHeight = decoder.getHeight();


        // Decode the PNG file in a ByteBuffer
        buf = ByteBuffer.allocateDirect(
                4 * decoder.getWidth() * decoder.getHeight());
        decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
        buf.flip();

        in.close();
    } catch (IOException e) {
        e.printStackTrace();
        System.exit(-1);
    }

    // Create a new texture object in memory and bind it
    int texId = GL11.glGenTextures();
    GL13.glActiveTexture(textureUnit);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);

    // All RGB bytes are aligned to each other and each component is 1 byte
    GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);

    // Upload the texture data and generate mip maps (for scaling)
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, tWidth, tHeight, 0, 
            GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buf);
    GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);

    // Setup the ST coordinate system
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);

    // Setup what to do when the texture has to be scaled
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, 
            GL11.GL_NEAREST);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, 
            GL11.GL_LINEAR_MIPMAP_LINEAR);

    return texId;
}

private static int createVAO () {

    int vaoId = GL30.glGenVertexArrays();
    vaos.add(vaoId);
    GL30.glBindVertexArray(vaoId);
    return vaoId;

}

private static void bindIndicesBuffer (int[] indices) {

    int vbo = GL15.glGenBuffers();
    vbos.add(vbo);
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vbo);
    IntBuffer buffer = storeDataInIntBuffer(indices);
    GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);

}

public static void cleanUp () {

    for (int vao : vaos) {
        GL30.glDeleteVertexArrays(vao);
    }
    for (int vbo : vbos) {
        GL15.glDeleteBuffers(vbo);
    }
    for (int texture : textures) {
        GL11.glDeleteTextures(texture);
    }

}

private static void storeDataInAttributeList (int attributeNumber, int size, float[] data) {

    int vboId = GL15.glGenBuffers();
    vbos.add(vboId);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
    FloatBuffer buffer = storeDataInFloatBuffer(data);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
    GL20.glVertexAttribPointer(attributeNumber, size, GL11.GL_FLOAT, false, 0, 0);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

}

private static void unbindVAO () {

    GL30.glBindVertexArray(0);

}

private static IntBuffer storeDataInIntBuffer (int[] data) {

    IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
    buffer.put(data);
    buffer.flip();
    return buffer;

}

private static FloatBuffer storeDataInFloatBuffer (float[] data) {

    FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
    buffer.put(data);
    buffer.flip();
    return buffer;

}

}

Answer:

I had forgotten to assign gl_Position in the vertex shader.

Question:

Hi I am new to LWJGL and I need help with drawing items on the screen. I have a problem when I render my 2D tiles my background's colour is changed to the one the tile is coloured with. So for example if I make a green tile the background goes green too! Here is my code:

MainClass:

    public class Mian {

    public static void main(String[] args) throws Exception {
        Display.setDisplayMode(new DisplayMode(640, 480));
        Display.create();

        while (!Display.isCloseRequested()) {

            setCamera();
            drawBackground();
            createLevel();
            Display.update();
            Display.sync(60);

        }
        Display.destroy();

    }

    public static void setCamera() {
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, 640, 0, 480, -1, 1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }

    public static void drawBackground(){
        glBegin(GL_QUADS);

        glColor3d(0.6, 0.7, 1);
        glVertex2d(0, 0);
        glVertex2d(640, 0);

        glColor3d(0.3, 0.5, 1);
        glVertex2d(640, 480);
        glVertex2d(0, 480);

        glEnd();
    }

    public static void createLevel(){
        List<Tile> tileList = new ArrayList<Tile>();
        tileList.add(new Tile(0,0,"res/GrassTile"));
        tileList.add(new Tile(32,0,"res/GrassTile"));
        tileList.add(new Tile(64,0,"res/GrassTile"));
        tileList.add(new Tile(96,0,"res/GrassTile"));
        tileList.add(new Tile(128,0,"res/GrassTile"));
        tileList.add(new Tile(160,0,"res/GrassTile"));
        tileList.add(new Tile(192,0,"res/GrassTile"));
        tileList.add(new Tile(224,0,"res/GrassTile"));
        tileList.add(new Tile(256,0,"res/GrassTile"));
        tileList.add(new Tile(288,0,"res/GrassTile"));
        tileList.add(new Tile(320,0,"res/GrassTile"));
        tileList.add(new Tile(352,0,"res/GrassTile"));
        tileList.add(new Tile(384,0,"res/GrassTile"));
        tileList.add(new Tile(416,0,"res/GrassTile"));
        tileList.add(new Tile(448,0,"res/GrassTile"));
        tileList.add(new Tile(480,0,"res/GrassTile"));
        tileList.add(new Tile(512,0,"res/GrassTile"));
        tileList.add(new Tile(544,0,"res/GrassTile"));
        tileList.add(new Tile(576,0,"res/GrassTile"));
        tileList.add(new Tile(608,0,"res/GrassTile"));


    }

}

Tile Class:

package Entitites;

import java.io.IOException;

import org.lwjgl.opengl.GL11;
import org.newdawn.slick.Color;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

public class Tile {
    public static int x;
    public static int y;
    public static Texture texture;

    public Tile(int tileX, int tileY, String path) {
        x = tileX;
        y = tileY;
        try {
            texture = TextureLoader.getTexture("PNG",
                    ResourceLoader.getResourceAsStream(path + ".png"));
        } catch (IOException e) {
            System.out.println("Error loading a tile texture! X:" + x + " - Y:"
                    + y);
            e.printStackTrace();
        }
        drawTile();
    }

    public static void drawTile() {

        Color.white.bind();
        texture.bind();

        GL11.glPushMatrix();
        GL11.glEnable(GL11.GL_TEXTURE_2D);
        GL11.glTranslated(x, y, 0);
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(1, 1);
        GL11.glTexCoord2f(1, 0);
        GL11.glVertex2f(1 + texture.getTextureWidth(), 0);
        GL11.glTexCoord2f(1, 1);
        GL11.glVertex2f(1 + texture.getTextureWidth(),
                1 + texture.getTextureHeight());
        GL11.glTexCoord2f(0, 1);
        GL11.glVertex2f(1, 1 + texture.getTextureHeight());

        GL11.glEnd();
        GL11.glDisable(GL11.GL_BLEND);
        GL11.glPopMatrix();
    }

}

I really cant figure it out. Any help would be appreciated :)


Answer:

You enable texturing at the start of drawTile():

GL11.glEnable(GL11.GL_TEXTURE_2D);

but never disable it again. This means that next time you call displayBackground(), the background will also be rendered using the texture of the last tile you rendered.

To fix this, add this call at the end of drawTile():

GL11.glDisable(GL11.GL_TEXTURE_2D);

Question:

I have followed ThinMatrix tutorial. I did everything excatly how he does in tutorial. I don't think there is mutch wrong with the code because I have checked it few times and I copied it from the comments and still same result. I am pretty sure it is something to do with the model, but hes model worked but my blender cube doesnt. Mine draws only half of the triangles.

Screenshot: Image

Code I copied: code

My .obj cube:

# Blender v2.77 (sub 0) OBJ File: ''
# www.blender.org
mtllib untitled.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.0000 0.6667
vt 0.3333 0.6667
vt 0.3333 1.0000
vt 0.0000 1.0000
vt 0.3333 0.3333
vt 0.3333 0.6667
vt 0.0000 0.6667
vt 0.0000 0.3333
vt 0.6667 0.3333
vt 0.3333 0.0000
vt 0.6667 0.0000
vt 0.0000 0.3333
vt 0.0000 0.0000
vt 0.3333 0.0000
vt 0.3333 0.3333
vt 1.0000 0.3333
vt 0.6667 0.3333
vt 0.6667 0.0000
vt 1.0000 0.0000
vt 0.6667 0.6667
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
usemtl Material.001
s off
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 8/6/2 7/7/2 6/8/2
f 1/9/3 5/5/3 6/10/3 2/11/3
f 2/12/4 6/13/4 7/14/4 3/15/4
f 3/16/5 7/17/5 8/18/5 4/19/5
f 5/5/6 1/9/6 4/20/6 8/6/6

Thanks!

UPDATE: It is fixed now but now the texture looks weird even when it looks fine in blender. No screenshot avaible because I don't have enought reputations for many links.


Answer:

It seems that the code you have can only work with triangles. Try triangulating your cube and using that OBJ.