1
\$\begingroup\$

(I asked the same question on StackOverflow but didn't got an answer. It's the first time I post here so idk if this is not allowed or anything, so if it is please tell me)

I was following ThinMatrix's tutorial on OPENGL/LWJGL 3 3D Game Tutorial series (here), even though my code was wrote a little different from his, it was going well.

I could render an object like the image below using basic LWJGL 3 methods for rendering/shading. Basically, using this method in the Render class:

 //Old method
    
    public void createModel(EntityLoader entity, StaticShader shader) {
        
        ModelLoader model = entity.getModel();
        MeshLoader mesh = model.createModel();
        glBindVertexArray(mesh.getVaoId());
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        shader.setUniformFloat("shineDamper", model.getShineDamper());
        shader.setUniformFloat("reflectivity", model.getReflectivity());
        
        Matrix4f transformationMatrix = Maths.createTransfMatrix(entity.getPosition(), entity.getRotX(), entity.getRotY(), 
                entity.getRotZ(), entity.getScale());
        shader.setUniformMatrix("transformationMatrix", transformationMatrix);
        
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, model.getTexture());
        glUniform1i(glGetUniformLocation(shader.getID(), "texture"), 0); 

        glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0);
        
        mesh.cleanUp();
    }

And calling it out in the main class like this:

public static void main(String[] args){
        
        Render render = new Render();
        window = render.init();
        glfwMakeContextCurrent(window);
        glfwSwapInterval(1);
        
        glfwShowWindow(window);
        
        createCapabilities(); 
        Light light = new Light(new Vector3f(0,0,20), new Vector3f(1,1,1));
        
        ObjLoader obj = new ObjLoader();
        ModelLoader squareModel = obj.loadObj("game_engine/src/Objetos/Ico.obj");
        EntityLoader squareEntity = new EntityLoader(squareModel, new Vector3f(0,0,-5),0,0,0,1);
        
        squareModel.setShineDamper(10);
        squareModel.setReflectivity(1);
        squareModel.loadTexture("game_engine/src/Texturas/awesomeface.png");
        
        Camera camera = new Camera();
        
        StaticShader shader = new StaticShader();
        shader.start();
        shader.use();
        
        while(!glfwWindowShouldClose(window))
        {
            render.prepare();
            processInput(window);
            
            glfwSetFramebufferSizeCallback(window, resizeWindow);
            GLFW.glfwSetScrollCallback(window, new GLFWScrollCallback() {
                @Override public void invoke (long win, double dx, double dy) {
                    XScroll = (float) dx;
                    YScroll = (float) dy;
                }
            });
            
            camera.move(window, YScroll);
            YScroll = 0;
            
            shader.setUniformVector("lightPosition", light.getPosition());
            shader.setUniformVector("lightColour", light.getColour());
        
            Matrix4f viewMatrix = Maths.createViewMatrix(camera);
            shader.setUniformMatrix("viewMatrix", viewMatrix);
        
            shader.setUniformMatrix("projectionMatrix", render.getProjectionMatrix());
            
            render.createModel(squareEntity, shader);
            
            glfwSwapBuffers(window);
            glfwPollEvents();    
        }
        shader.cleanup();
        glfwTerminate();

    }

enter image description here

Until the 13 video, Optimizing, where he teached how to do the same procedure in a more optimized way, using HashMaps and ArrayLists to store the entities and calling the VAO elements only once per list of entities. So, I made this MasterRender class:

public class Master {
    
    private StaticShader shader = new StaticShader();
    private Render renderer = new Render(shader);
    
    private Map<ModelLoader, List<EntityLoader>> entities = new HashMap<ModelLoader, List<EntityLoader>>();
    
    public void render(Light sun, Camera camera){
        renderer.prepare();
        shader.start();
        shader.use();
        
        shader.setUniformVector("lightPosition", sun.getPosition());
        shader.setUniformVector("lightColour", sun.getColour());
        
        Matrix4f viewMatrix = Maths.createViewMatrix(camera);
        shader.setUniformMatrix("viewMatrix", viewMatrix);
        
        shader.setUniformMatrix("projectionMatrix", renderer.getProjectionMatrix());
    }
    
    public void processEntity(EntityLoader entity) {
        ModelLoader entityModel = entity.getModel();
        List<EntityLoader> batch = entities.get(entityModel);
        if(batch!=null) {
            batch.add(entity);
        }else {
            List<EntityLoader> newBatch = new ArrayList<EntityLoader>();
            newBatch.add(entity);
            entities.put(entityModel, newBatch);
        }
    }
    
    public void renderEntity() {
        
        renderer.render(entities);
        
        shader.stop();
        entities.clear();
    }
    
    public long loadWindow() {
        return renderer.init();
    }
    
    public void cleanup() {
        shader.cleanup();
    }

}

And used new methods in the Render class:

//Optimized methods
    
    public void render(Map<ModelLoader, List<EntityLoader>> entities) {
        for(ModelLoader model:entities.keySet()) {
            prepareModel(model);
            List<EntityLoader> batch = entities.get(model);
            for(EntityLoader entity : batch) {
                prepareEntity(entity);
                glDrawElements(GL_TRIANGLES, model.createModel().getVertexCount(), GL_UNSIGNED_INT, 0);
            }
            unbindModel();
        }
        
    }
    
    private void prepareModel(ModelLoader model) {
        MeshLoader mesh = model.createModel();
        glBindVertexArray(mesh.getVaoId());
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        shader.setUniformFloat("shineDamper", model.getShineDamper());
        shader.setUniformFloat("reflectivity", model.getReflectivity());
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, model.getTexture());
        glUniform1i(glGetUniformLocation(shader.getID(), "texture"), 0); 
        
    }
    
    private void unbindModel() {
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        glDisableVertexAttribArray(2);
        glBindVertexArray(0);

        glBindTexture(GL_TEXTURE_2D, 0);

    }
    
    private void prepareEntity(EntityLoader entity) {
        Matrix4f transformationMatrix = Maths.createTransfMatrix(entity.getPosition(), entity.getRotX(), entity.getRotY(), 
                entity.getRotZ(), entity.getScale());
        shader.setUniformMatrix("transformationMatrix", transformationMatrix);
        
    }

Finally, I adjusted the main class, much like he did in the video

public static void main(String[] args){
        
        Master render = new Master();
        window = render.loadWindow();
...
List<EntityLoader> allIcos = new ArrayList<EntityLoader>();
        allIcos.add(new EntityLoader(squareModel, new Vector3f(0,0,-5),0,0,0,1));
        
        while(!glfwWindowShouldClose(window))
        {
            processInput(window);
            
            glfwSetFramebufferSizeCallback(window, resizeWindow);
            GLFW.glfwSetScrollCallback(window, new GLFWScrollCallback() {
                @Override public void invoke (long win, double dx, double dy) {
                    XScroll = (float) dx;
                    YScroll = (float) dy;
                }
            });
            
            camera.move(window, YScroll);
            YScroll = 0;

            render.render(light, camera);
            for(EntityLoader Ico : allIcos) {
                render.processEntity(Ico);
                Ico.changeRot(0, 3, 0);
            }
            render.renderEntity();
            
            glfwSwapBuffers(window);
            glfwPollEvents();    
        }

Not only it didn't work, it bought up a log error:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ff8b8cd07b0, pid=11800, tid=7260
#
# JRE version: OpenJDK Runtime Environment (16.0.2+7) (build 16.0.2+7-67)
# Java VM: OpenJDK 64-Bit Server VM (16.0.2+7-67, mixed mode, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64)
# Problematic frame:
# C  [nvoglv64.dll+0x8507b0]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   https://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.
#

---------------  S U M M A R Y ------------

Command Line: -Dfile.encoding=Cp1252 -XX:+ShowCodeDetailsInExceptionMessages br.com.renanlima.git.main

---------------  T H R E A D  ---------------

Current thread (0x000001ae5e0ce780):  JavaThread "main" [_thread_in_native, id=7260, stack(0x0000007d29000000,0x0000007d29100000)]

Stack: [0x0000007d29000000,0x0000007d29100000],  sp=0x0000007d290ff350,  free space=1020k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [nvoglv64.dll+0x8507b0]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  org.lwjgl.opengl.GL11C.nglDrawElements(IIIJ)V+0
j  org.lwjgl.opengl.GL11C.glDrawElements(IIIJ)V+4
j  org.lwjgl.opengl.GL11.glDrawElements(IIIJ)V+4
j  br.com.renanlima.render.Render.render(Ljava/util/Map;)V+84
j  br.com.renanlima.render.Master.renderEntity()V+8
j  br.com.renanlima.git.main.main([Ljava/lang/String;)V+254
v  ~StubRoutines::call_stub

siginfo: EXCEPTION_ACCESS_VIOLATION (0xc0000005), reading address 0x0000000000000000
...

My question is: What did I do wrong in this new method of rendering? I looked up other tutorials besides ThinMatrix's one and they seen to all do it in a similar way.

EDIT 1: So, using Eclipse's debugger I found out 2 things: 1 - For some reason, the "transformationMatrix" is loading different, even though the two methods are the same and the parameters they are getting are the same.

This are the matrix variables using the "createModel()" method, the one that works

And this are the matrix variables using the optimized method, the one that doesn't work

This seems to be the only matrix/vertex in which this happens, but I could be overlooking something

2 - I think I've pinpointed the specific part where the crash happens. When running the "glDrawElements" method.

enter image description here

More especificaly, on this part of the method:

enter image description here

But none of the variables seem to be wrong before that method is called. Again, I could be overlooking something, but there are a sh*tton of variables at the "findNative()" part, so I will look better into it.

EDIT 1.2: I solved the transformationMatrix error. It was because of the "changeRot(0, 3, 0);" being called early. But I still can't find out why the crash at "glDrawElements" happens. Can someone please help me with this? If the question is confusing, please tell me so I can try to explain it better.

\$\endgroup\$
2
  • \$\begingroup\$ Surely you've already checked your favorite debugger? What does it say? \$\endgroup\$
    – user35344
    Oct 27 '21 at 12:04
  • \$\begingroup\$ I put an edit with the debugging process, using Eclipse's debugger. \$\endgroup\$
    – Renan Lima
    Oct 28 '21 at 1:13

You must log in to answer this question.

Browse other questions tagged .