-1

I'm trying to render a 3D model of a bunny.

I tried to render the .obj file but nothing shows up on my screen, here's the code :

MainDisplay class :

Code:

package com.dryadengine.gui;

import com.dryadengine.core.Model;
import com.dryadengine.framework.OBJLoader;
import com.dryadengine.framework.ShaderFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import org.lwjgl.util.vector.Matrix4f;

/**
 *
 * @author Roy
 */
public class MainDisplay {

private Model bunny;
private Matrix4f mProjection;
private Matrix4f mView;
private Matrix4f mModel;
private int shaderProgramID;
private int vboID;
private int vPositionID;
private int mProjectionID;
private int mViewID;
private int mModelID;

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    MainDisplay md = new MainDisplay();
    md.create();
    md.init();
    md.run();
}

public MainDisplay() {

}

public void create() {
    try {
        Display.setDisplayMode(new DisplayMode(800, 600));
        Display.setTitle("Dryad Engine 1.0.0");
        Display.setFullscreen(false);
        Display.setResizable(true);
        Display.create();
    } catch (LWJGLException ex) {
        Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
        System.exit(-1);
    }
}

public void init() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    try {
        shaderProgramID = ShaderFactory.createShaderProgram("vertexShader", "fragmentShader");
        glUseProgram(shaderProgramID);
        bunny = OBJLoader.parseOBJ(new File("src/com/dryadengine/assets/bunny.obj"));
        FloatBuffer vbo = BufferUtils.createFloatBuffer(bunny.getVertices().length);
        vbo.put(bunny.getVertices());
        vbo.flip();
        vboID = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboID);
        glBufferData(GL_ARRAY_BUFFER, vbo, GL_STATIC_DRAW);
        vPositionID = glGetAttribLocation(shaderProgramID, "vPosition");
        glEnableVertexAttribArray(vPositionID);
        mProjection = new Matrix4f();
        float fieldOfView = 60f;
        float aspectRatio = (float)Display.getWidth() / (float)Display.getHeight();
        float nearPlane = 0.1f;
        float farPlane = 100f;
        float yScale = (float)(1.0f / Math.tan((fieldOfView / 2.0f) * Math.PI / 180));//this.coTangent(this.degreesToRadians(fieldOfView / 2f));
        float xScale = yScale / aspectRatio;
        float frustum_length = farPlane - nearPlane;
        mProjection.m00 = xScale;
        mProjection.m11 = yScale;
        mProjection.m22 = -((farPlane + nearPlane) / frustum_length);
        mProjection.m23 = -1;
        mProjection.m32 = -((2 * nearPlane * farPlane) / frustum_length);
        mProjection.m33 = 0;
        mView = new Matrix4f();
        mView.m23 = -5;
        mModel = new Matrix4f();
        mProjectionID = glGetUniformLocation(shaderProgramID, "mProjection");
        mViewID = glGetUniformLocation(shaderProgramID, "mView");
        mModelID = glGetUniformLocation(shaderProgramID, "mModel");
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glEnable(GL_DEPTH_TEST);
    } catch (FileNotFoundException ex) {
        Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
    }
}



public void run() {
    while (!Display.isCloseRequested()) {
        if (Display.isVisible()) {
            render();
        }
        if (Display.wasResized()) {
            reshape();
        }
        Display.update();
        Display.sync(60);
    }
    destroy();
}

public void render() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    FloatBuffer fb1 = BufferUtils.createFloatBuffer(16);
    FloatBuffer fb2 = BufferUtils.createFloatBuffer(16);;
    FloatBuffer fb3 = BufferUtils.createFloatBuffer(16);;
    mProjection.store(fb1);
    mView.store(fb2);
    mModel.store(fb3);
    glUniformMatrix4(mProjectionID, true, fb1);
    glUniformMatrix4(mViewID, true, fb2);
    glUniformMatrix4(mModelID, true, fb3);
    for (int i = 0; i < bunny.getVertices().length / 3; i += 3) {
        glVertexAttribPointer(vPositionID, 3, GL_FLOAT, false, 0, i);
        glDrawArrays(GL_TRIANGLES, 0, 3);
    }
}

public void reshape() {
    glViewport(0, 0, Display.getWidth(), Display.getHeight());
}

public void dispose() {
    glDeleteProgram(shaderProgramID);
    glUseProgram(0);
    glDeleteBuffers(vboID);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

public void destroy() {
    Display.destroy();
}
}

ShaderFactory class :

package com.dryadengine.framework;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;

/**
 *
 * @author Roy
 */
public class ShaderFactory {

private static final String COMMON_SHADERS_PATH = "/com/dryadengine/shaders/";
private static final String SHADER_EXTENSION = ".dsf";

/**
 * 
 * @param vertexShaderName
 * @param fragmentShaderName
 * @return a shader program
 * @throws FileNotFoundException
 * @throws IOException 
 */
public static int createShaderProgram(String vertexShaderName, String fragmentShaderName) throws FileNotFoundException, IOException {
    ArrayList<Integer> shaders = new ArrayList();
    shaders.add(ShaderFactory.compileShader(GL_VERTEX_SHADER, getShaderFileCode(COMMON_SHADERS_PATH + vertexShaderName + SHADER_EXTENSION)));
    shaders.add(ShaderFactory.compileShader(GL_FRAGMENT_SHADER, getShaderFileCode(COMMON_SHADERS_PATH + fragmentShaderName + SHADER_EXTENSION)));
    return ShaderFactory.linkProgram(shaders);
}

/**
 * 
 * @param shaderFilePath
 * @return a shader file code
 * @throws FileNotFoundException
 * @throws IOException 
 */
private static String getShaderFileCode(String shaderFilePath) throws FileNotFoundException, IOException {
    StringBuilder shaderCode = new StringBuilder();
    String line;
    try {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(ShaderFactory.class.getResourceAsStream(shaderFilePath)))) {
            while ((line = br.readLine()) != null) {
                shaderCode.append(line).append("\n");
            }
        }
    } catch (FileNotFoundException e) {
        throw new FileNotFoundException(e.getMessage());
    }
    return shaderCode.toString();
}

/**
 * 
 * @param shaderType
 * @param shaderCode
 * @return a compiled shader file id
 */
public static int compileShader(int shaderType, String shaderCode) {
    int shaderID = glCreateShader(shaderType);
    glShaderSource(shaderID, shaderCode);
    glCompileShader(shaderID);
    int status = glGetShaderi(shaderID, GL_COMPILE_STATUS);
    if (status == GL_FALSE) {
        glDeleteShader(shaderID);
        throw new RuntimeException(glGetShaderInfoLog(shaderID, glGetShaderi(shaderID, GL_INFO_LOG_LENGTH)));
    }
    return shaderID;
}

/**
 * Link the vertex shader and the fragment shader to the shader program
 * @param shaders
 * @return a shader program
 */
public static int linkProgram(ArrayList <Integer> shaders) {
    int shaderProgramID = glCreateProgram();
    for (Integer shader : shaders) {
        glAttachShader(shaderProgramID, shader);
    }
    glLinkProgram(shaderProgramID);
    int status = glGetProgrami(shaderProgramID, GL_LINK_STATUS);
    if (status == GL_FALSE) {
        glDeleteProgram(shaderProgramID);
        throw new RuntimeException(glGetShaderInfoLog(shaderProgramID, glGetProgrami(shaderProgramID, GL_INFO_LOG_LENGTH)));
    }
    for (int shader : shaders) {
        glDeleteShader(shader);
    }
    return shaderProgramID;
}

}

OBJLoader class :

package com.dryadengine.framework;

import com.dryadengine.core.Model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Roy
 */
public class OBJLoader {

/**
 * Parse .obj file and make a model from it.
 * @param f
 * @return a model object
 * @throws FileNotFoundException
 * @throws IOException 
 */
public static Model parseOBJ(File f) throws FileNotFoundException, IOException {
    BufferedReader br = new BufferedReader(new FileReader(f));
    String line;
    Model m;
    List<Float> vertices = new ArrayList<>();
    List<Float> normals = new ArrayList<>();
    while ((line = br.readLine()) != null) {
        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]);
            vertices.add(x);
            vertices.add(y);
            vertices.add(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]);
            normals.add(x);
            normals.add(y);
            normals.add(z);
        }
    }
    br.close();
    float[] a = new float[vertices.size()];
    float[] b = new float[normals.size()];
    for (int i = 0; i < vertices.size(); i++) {
        a[i] = vertices.get(i);
    }
    for (int i = 0; i < normals.size(); i++) {
        b[i] = normals.get(i);
    }
    m = new Model(a, b);
    return m;
}

}

Model class :

package com.dryadengine.core;

/**
 *
 * @author Roy
 */
public class Model {

private float[] vertices;
private float[] normals;

/**
 * Construct a new model object.
 * @param vertices
 * @param normals 
 */
public Model(float[] vertices, float[] normals) {
    this.vertices = vertices;
    this.normals = normals;
}

/**
 * 
 * @return the model vertices array
 */
public float[] getVertices() {
    return vertices;
}

/**
 * 
 * @return the model normals array
 */
public float[] getNormals() {
    return normals;
}

}

vertex shader code :

#version 330

uniform mat4 mProjection;
uniform mat4 mView;
uniform mat4 mModel;

in vec4 vPosition;

void main()
{
    gl_Position = mProjection * mView * mModel * vPosition;
}

fragment shader code :

#version 330

out vec4 color;

void main()
{
    color = vec4(1.0, 0.0, 0.0, 1.0);
}

Result is just black screen

genpfault
  • 51,148
  • 11
  • 85
  • 139

2 Answers2

1

I'm not sure if anything else is wrong since I'm not too experienced with GL, but I noticed that in your OBJLoader class, you're checking if a line starts with 'v' first.

    if (line.startsWith("v")) {

    } else if (line.startsWith("vn")) {

    }

This means that if it detects a 'vn', then it will be handled by the first part of the statement since 'vn' starts with 'v'. The second part of the statement never gets executed. You could either check for 'vn' first, or add a space after 'v', checking for 'v '.

Jeremy MP
  • 21
  • 2
0

You are doing something very strange in your render (...) method; issuing 1 draw call per-triangle.

With the way your data is laid out, you should be able to draw all of your triangles in a single call if you pass the number of vertices in the array instead of setting up a different vertex pointer and passing the value 3 for each triangle.

glVertexAttribPointer (vPositionID, 3, GL_FLOAT, false, 0, 0);
glDrawArrays          (GL_TRIANGLES, 0, bunny.getVertices ().length / 3);

You are also telling GL to transpose your matrices by passing true to glUniformMatrix4. If you transpose your matrices, then you need to reverse the order of your matrix multiplication in the vertex shader for proper transformation.

void main()
{
  gl_Position = vPosition * mModel * mView * mProjection;
}

This runs counter to everything you should be learning in OpenGL (column-major matrices), so rather than modifying your vertex shader that way you should really just stop passing true.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • I thought LWJGL Matrix4f create column major matrices by default guess I was wrong ? anyway I set it to false in the glUniformMatrix4 calls and changed the for loop to what you wrote, still nothing is being rendered to the screen. – user3573780 Apr 26 '14 at 08:08