Problem: I can't make the triangle to appear. I'm not able to set up the vertex attributes correctly only by using OpenGL 2.0
Result of a run of the code: Red window 600*800 without a triangle.
Objective: I try to:
float
x 2 (for a
start)int
x 3Java code:
package prot20;
import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.glfw.GLFW.glfwPollEvents;
import static org.lwjgl.glfw.GLFW.glfwShowWindow;
import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
import static org.lwjgl.glfw.GLFW.glfwWindowHint;
import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glDrawElements;
import static org.lwjgl.opengl.GL11.glEnableClientState;
import static org.lwjgl.opengl.GL11.glGetString;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;
import static org.lwjgl.opengl.GL11.glViewport;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.system.MemoryUtil.NULL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import org.lwjgl.opengl.GLCapabilities;
public class prot20_2 {
private long window;
private int width = 800;
private int height = 600;
public static void main(String[] args) {
new prot20_2();
}
public prot20_2() {
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
long monitor = glfwGetPrimaryMonitor();
window = glfwCreateWindow(width, height, "Window20", NULL, NULL);
if (window == NULL) {
throw new AssertionError("Failed to create window");
}
glfwMakeContextCurrent(window);
glfwSwapInterval(0);
glfwShowWindow(window);
GLCapabilities c = GL.createCapabilities();
System.out.println(c.OpenGL20);
System.out.println(glGetString(GL11.GL_VERSION));
int program = util.createProgram(prot20_2.getSimpleVertexShaderCode(), prot20_2.getSimpleFragmentShaderCode());
float[] vertices = { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f };
int[] color = { 0, 128, 128, 128, 0, 128, 128, 128, 0 };
int[] indices = { 0, 1, 2 };
FloatBuffer vb = this.toBuffer(vertices);
IntBuffer ib = this.toBuffer(indices);
IntBuffer cb = this.toBuffer(color);
int vbo = glGenBuffers();
int ibo = glGenBuffers();
int cbo = glGenBuffers();
// Position
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vb, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glBindAttribLocation(program, 0, "position");
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Color
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, cb, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_INT, false, 0, 0);
glBindAttribLocation(program, 1, "color");
glBindBuffer(GL_ARRAY_BUFFER, 0);
// indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ib, GL_STATIC_DRAW);
glEnableClientState(GL_INDEX_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(program);
while (glfwWindowShouldClose(this.window) == false) {
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
float aspect = (float) width / height;
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -1, 1);
// glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0L);
glfwSwapBuffers(this.window);
glfwPollEvents();
}
glDeleteBuffers(vbo);
}
private FloatBuffer toBuffer(float[] f) {
FloatBuffer buffer = BufferUtils.createFloatBuffer(f.length);
buffer.put(f);
buffer.flip();
return buffer;
}
private IntBuffer toBuffer(int[] i) {
IntBuffer buffer = BufferUtils.createIntBuffer(i.length);
buffer.put(i);
buffer.flip();
return buffer;
}
public static String getSimpleFragmentShaderCode() {
StringBuilder sb = new StringBuilder();
sb.append("uniform vec3 color;\n");
sb.append("void main(void) {\n");
sb.append(" gl_FragColor = vec4(color.rgb, 1.0);");
sb.append("}\n");
return sb.toString();
}
public static String getSimpleVertexShaderCode() {
StringBuilder sb = new StringBuilder();
sb.append("uniform vec2 position;\n");
sb.append("void main(void) {\n");
sb.append(" gl_Position = vec4(position.xy,0.0,0.0);\n");
sb.append("}\n");
return sb.toString();
}
}
I have looked for documentation and examples, but either I find trivial examples without attributes, color, indices or shaders, or I find complex code using opengl 3+. I find it hard to locate a good example covering: opengl 2.1 including shader,index,attribute,color and texture.
If you want to draw a triangle with a color associated to each vertex coordinate then you need a vertex shader with 2 attributes. One for the vertex coordinate and one for the color. The color attribute has to be passed from the Vertex Shader to the Fragment Shader, by a varying
variable.
Note, attribute
and varying
are deprecated but have to be used in GLSL version 1.10, which corresponds to OpenGL version 2.0. In "moder" OpenGL the Type Qualifiers (GLSL) in
and out
are used:
Vertex shader
#version 110
attribute vec2 in_pos;
attribute vec3 in_col;
varying vec3 v_volor;
void main()
{
v_color = in_col;
gl_Position = vec4(in_pos.xy, 0.0, 1.0);
}
Fragment shader
varying vec3 v_color;
void main()
{
gl_FragColor = vec4(v_color.rgb, 1.0);
}
After the program is linked you have to get the attribute indices of in_pos
and in_col
by glGetAttribLocation
:
int attr_pos = glGetAttribLocation(program, "in_pos");
int attr_col = glGetAttribLocation(program, "in_col");
If you wat to set the attribute indices by glBindAttribLocation
the this would have to be done, before the program is linked by glLinkProgram
, because this is an information which is processed in the link process.
The color channels in OpenGL Shading Language (GLSL) have to be in the range [0.0, 1.0] where RGB(0.0, 0.0, 0.0) is completely black and RGB(1.0, 1.0, 1.0) is white. So the color attributes have to be floating point values:
float[] vertices = { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f };
float[] color = { 0, 0.5f, 0.5f, 0.5f, 0, 0.5f, 0.5f, 0.5f, 0 };
int[] indices = { 0, 1, 2 };
FloatBuffer vb = this.toBuffer(vertices);
FloatBuffer cb = this.toBuffer(color);
IntBuffer ib = this.toBuffer(indices);
Generate the array buffers and the index buffer:
int vbo = glGenBuffers();
int cbo = glGenBuffers();
int ibo = glGenBuffers();
// Position
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vb, GL_STATIC_DRAW);
// Color
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, cb, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ib, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Specify the arrays of generic vertex attribute data:
// Position
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(attr_pos);
glVertexAttribPointer(attr_pos, 2, GL_FLOAT, false, 0, 0);
// Color
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glEnableVertexAttribArray(attr_col);
glVertexAttribPointer(attr_col, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
For drawing the object the program object has to installed by glUseProgram
and the element buffer has to be bound:
glUseProgram(program);
while (glfwWindowShouldClose(this.window) == false) {
// ....
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0L);
// .....
}
Note, fixed-function attributes (glVertexPointer
, ...), client capabilities (glEnableClientState
/ glDisableClientState
) and the fixed function matrix stack (glMatrixMode
, glLoadIdentity
, ...) have no effect, when a shader program like this is used.
If you want to use matrix transformations, then you have to use Uniform variables of type mat4
and to setup your own projection, view and model matrices - e.g by Matrix4f library.