PDA

View Full Version : Stuck ... not able to draw triangle



NoobCoder
12-26-2015, 04:20 PM
Hello all! I am stuck and I would greatly appreciate some help. I am sure I am screwing up something extremely basic (I've been working with OpenGL for a grand total of a week) ...

I am trying to draw a triangle using lwjgl on Scala (yes I am certifiably insane).

This is the set up code:


private def setupgeometry() {

vaoID = glGenVertexArrays()
glBindVertexArray(vaoID)
var vertices: Array[Float] = Array(-1.0f, -1.0f, 0.0f, 0.0f, //pos
1.0f, 0.4f, 0.0f, 1.0f, //color
0.0f, 1.0f, 0.0f, 0.0f, //pos
1.0f, 0.0f, 0.3f, 1.0f, //color
1.0f, -1.0f, 0.0f, 0.0f, //pos
0.2f, 0.2f, 1.0f, 1.0f) //color
var verticesBuffer: FloatBuffer = BufferUtils.createFloatBuffer(vertices.length);
verticesBuffer.put(vertices)
verticesBuffer.flip

// Create a Buffer Object and upload the vertices buffer
vboID = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, vboID)
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW)

glVertexAttribPointer(0, 4, GL_FLOAT, false, 32, 0)
glVertexAttribPointer(1, 4, GL_FLOAT, false, 32, 16)

glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)

}


this is the render code


private def render(delta: Double) {
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

// Use our program
glUseProgram(pID)

// Bind the vertex array and enable our location
glBindVertexArray(vaoID)
glEnableVertexAttribArray(0)
glEnableVertexAttribArray(1)

// Draw a triangle of 3 vertices
glDrawArrays(GL_TRIANGLES, 0, 3)

// Disable our location
glDisableVertexAttribArray(0)
glBindVertexArray(0)

// Un-bind our program
glUseProgram(0)
}


and this is the view setup code (this is getting called every time the window resizes. it's also getting called right after the window is created when the app starts. I am posting it here in case some of you folks spot something wrong with the glOrtho call):


private def resize(width: Int, height: Int) {
// Compute aspect ratio of the new window
if (height > 0) {
var aspectratio = width.toFloat / height.toFloat;

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

if (width >= height) {
// aspect >= 1, set the height from -1 to 1, with larger width
glOrtho(-3.0 * aspectratio, 3.0 * aspectratio, -3.0, 3.0, -1, 1);
} else {
// aspect < 1, set the width to -1 to 1, with larger height
glOrtho(-3.0, 3.0, -3.0 / aspectratio, 3.0 / aspectratio, -1, 1);
}
glMatrixMode(GL_MODELVIEW)
}
}

If I play around with the glVertexAttribPointer (reducing the stride to 16) I see something (kind of a very warped triangle that is taking up almost the entire window and that stretches if I resize the window). So ... I do have it set up so that SOMETHING can render but clearly not what I expect (I expect a triangle sitting in the middle of the window)

I played around with this code plenty of times to the point that I am afraid I might have messed it up ...

I can post the shaders code if necessary but they are simple pass throughs ...

I'm really stuck and if anyone can help me figure out what's going on that would be great! Thanks!

PS: let me know if you need me to post more of my code (I didn't post everything) in case there's something else you need to look at.

Thank you!!

GClements
12-27-2015, 01:41 AM
I am trying to draw a triangle using lwjgl on Scala
Have you tried converting the code to C? That would help to determine whether the issue is with OpenGL itself, lwjgl, or its use from Scala. OpenGL is a C API, and the further you get from C, the less likely you are to find people who can identify any issues related to the language bindings.


I can post the shaders code if necessary but they are simple pass throughs ...
The vertex shader needs to at least transform the vertex positions by gl_ProjectionMatrix if you want that glOrtho() call to have any effect. If you're using a vertex shader, matrix operations do nothing other than affect some pre-defined uniform variables.

NoobCoder
12-28-2015, 11:27 AM
The vertex shader needs to at least transform the vertex positions by gl_ProjectionMatrix if you want that glOrtho() call to have any effect. If you're using a vertex shader, matrix operations do nothing other than affect some pre-defined uniform variables.

Thanks for your help! You nailed it. That's what was missing.

You have no idea what kind of rabbit hole I fell into once I looked up "matrix" and "shader" on google.

I got it to work ... but holy cow!

I am not entirely sure what was wrong with the original code at this point since I basically gutted it and re-wrote it ... but there's several things that I needed to do:

1 - the vertex shader needs to explicitly multiply the input vector by a transform matrix (which is actually created by multiplying multiple matrices together ... view, projection, etc.). This took me a while to figure out because I had to look into the whole ortho projections deal.
2 - passing the matrix from the code to the shader through the glUniformMatrix4fv function was a whole different type of nightmare. Here's the irony: Scala, Java, C++, C ... doesn't matter AT ALL. They all work exactly the same. lwjgl (which is the java library scala relies on for OpenGL), works like a charm. There's only one requirement: you need to know what you are doing. The issue was that you must call glUniformMatrix4fv after the shaders are completely set up and good to go and you have to do it with a current uniform variable handle using the program ID that the shaders are attached to. You make that call (glUniformMatrix4fv ) at any other time and the shader will completely ignore your matrix, multiply everything by zero and good luck getting yourself out of the nervous breakdown that's going to give you.

Wow ... I feel like I went into this OpenGL adventure like a wide-eyed fool ... I'm sober and awake now. There's a lot of nuances to getting this to work right and it's not that easy to troubleshoot.

Moral of the story: the language platforms are perfectly translatable across languages. For instance: in C++ you can just straight out pass a pointer to the matrix to the glUniformMatrix4fv call. In Java/Scala you make a FloatBuffer instead. A FLAT one ... you take the matrix (4 x 4) turn it into a flat 16 floats array, make a FloatBuffer out of it and feed it into the glUniformMatrix4fv function. It works just fine. One way or another you can pass all the data you need through the API no matter what language you start with.

The real deal is: you need to make all the right calls at the right time in the right sequence. That's platform independent ... that's doing-your-research dependent ... :)

GClements
12-28-2015, 12:02 PM
The issue was that you must call glUniformMatrix4fv after the shaders are completely set up and good to go and you have to do it with a current uniform variable handle using the program ID that the shaders are attached to.

Uniform variables in the default uniform block are part of the shader program. The program must exist (i.e. have been linked successfully) and be current before you can set uniforms.

Uniform variables in named uniform blocks are a different matter. The buffers holding the variables exist as distinct entities. The buffers are bound to a binding point, the program accesses whatever is attached to the binding point. The format has to match what the program is expecting, but otherwise the binding of buffers and programs is independent.



There's a lot of nuances to getting this to work right and it's not that easy to troubleshoot.

OpenGL has a lot of state. Some of that state is global, some of it is part of an "object". In the latter case, sometimes you specify an object handle explicitly when setting its state, sometimes you set state for the "current" object of that type. Uniform variables are part of a program object; glUniform() sets uniforms for the current program, glProgramUniform() (in OpenGL 4.1 and later) sets uniforms for a specific program.

In some cases, there are multiple levels of indirection. E.g. textures are bound to texture units. The active texture unit is set by glActiveTexture(). A texture is bound to the active texture unit with glBindTexture(). A call to glTexParameter() sets parameters for the texture which is currently bound to the active texture unit.

Historically, functions tend to set state for the current object. More recently, direct state access (https://www.opengl.org/wiki/Direct_State_Access) functions allow setting state for specific objects without having to make them current. So you can now e.g. set parameters for a specific texture directly with glTextureParameter() (note "Texture" rather than "Tex").