It actually does not matter when you enable a generic vertex attribute, just must be before the drawcall.
One advice: Make your code publicly available for people to glance over. Just create a free GitHub repository. It’s hard to keep track of what your code evolved to over time til now and match all the pieces from your posts.
OpenGL 3.2 is fine for being the oldest, operating system and gpu?
About the Hello World, what you saw in the window was right, it just clears the color to red
We can focus on 3.2 at the moment, no big deal, in this case I have another sample where you can take inspiration.
I will use GitHub as suggested, in the meantime here is my complete main class:
package lwjgl;
import java.nio.FloatBuffer;
import java.util.LinkedList;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
public class AnimTest
{ public static void main(String[] args)
{ System.out.println("CPU : "+Runtime.getRuntime().availableProcessors());
new AnimTest().start();
}
private static final Vector3f AXIS = new Vector3f(0, 0, 1), BIGGER = new Vector3f(1f, 1.01f, 1.01f), TINIER = new Vector3f(1f, 1f/1.01f, 1f/1.01f);
private static final int VOF = 0, NOF = VOF+3*4, COF = NOF+3*4, IOF = COF+3*4, WOF = IOF+2*4, VSIZE = WOF+2*4;
private static int VERTEX, NORMAL, COLOR, INDEX, WEIGHT;
private boolean up = false, down = false, left = false, right = false;
private Vector3f[] pos = {new Vector3f(-4, 0, 0), new Vector3f(0, 0, 0), new Vector3f(4, 0, 0)};
private Matrix4f[] rot = {new Matrix4f(), new Matrix4f(), new Matrix4f()};
private Matrix4f[] sca = {new Matrix4f(), new Matrix4f(), new Matrix4f()};
private Matrix4f[] bones = {new Matrix4f(), new Matrix4f(), new Matrix4f()};
private void bone(int i)
{ bones[i].setIdentity();
if (i != 1) Matrix4f.mul(bones[i], rot[1], bones[i]);
bones[i].translate(pos[i]);
Matrix4f.mul(bones[i], rot[i], bones[i]);
bones[i].translate(pos[2-i]);
Matrix4f.mul(bones[i], sca[i], bones[i]);
}
private void rotate(int i, float angle) {rot[i].rotate(angle, AXIS); bone(i); if (i == 1) {bone(0); bone(2);}}
private void bigger(int i) {sca[i].scale(BIGGER); bone(i);}
private void tinier(int i) {sca[i].scale(TINIER); bone(i);}
public AnimTest() {}
public void start()
{ try
{ Display.setFullscreen(true);
Display.setVSyncEnabled(true);
Display.create();
final int W = Display.getWidth(), H = Display.getHeight();
System.out.println("OpenGL version: " + GL11.glGetString(GL11.GL_VERSION));
// Create the camera
Camera camera = new Camera();
camera.updatePerspectiveProjection((float)Math.PI/4, (float)W / (float)H, 0.1f, 100f);
// Create Shader Program
ShaderProgram shaderProgram = new ShaderProgram("VertexShader2.src", "FragmentShader.src");
Vector3f light = new Vector3f();
// Enable face culling
GL11.glPolygonMode(GL11.GL_BACK, GL11.GL_LINE);
// Enable Client states
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
// Use shader
shaderProgram.bind();
shaderProgram.setUniform("ambientCoefficient", 0.5f);
shaderProgram.setUniform("textured", 0);
shaderProgram.setUniform("boned", 1);
GL11.glClearColor(0, 0, 0, 1);
//GL11.glColor3f(0.5f, 0, 1);
// Enable depth testing
GL11.glEnable(GL11.GL_DEPTH_TEST);
boolean running = true, normals = false, colors = false;
int size = 0, resolution = 64, frames = 0, mouseWheel;
long time = System.currentTimeMillis(), log = time+1000;
LinkedList<Triangle3D> faces = null;
FloatBuffer vbuf = null;
float pow = 1;
int vboVertexID = GL15.glGenBuffers();
VERTEX = shaderProgram.getAttributeLocation("Vertex");
NORMAL = shaderProgram.getAttributeLocation("Normal");
COLOR = shaderProgram.getAttributeLocation("Color");
INDEX = shaderProgram.getAttributeLocation("Index");
WEIGHT = shaderProgram.getAttributeLocation("Weight");
System.out.println("Vertex id = "+VERTEX);
System.out.println("Normal id = "+NORMAL);
System.out.println("Color id = "+COLOR);
System.out.println("Index id = "+INDEX);
System.out.println("Weight id = "+WEIGHT);
// Bind the vertex buffer
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboVertexID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, VSIZE, VOF);
GL11.glNormalPointer(GL11.GL_FLOAT, VSIZE, NOF);
GL11.glColorPointer(3, GL11.GL_FLOAT, VSIZE, COF);
GL20.glVertexAttribPointer(VERTEX, 3, GL11.GL_FLOAT, false, VSIZE, VOF);
GL20.glVertexAttribPointer(NORMAL, 3, GL11.GL_FLOAT, false, VSIZE, NOF);
GL20.glVertexAttribPointer(COLOR, 3, GL11.GL_FLOAT, false, VSIZE, COF);
GL20.glVertexAttribPointer(INDEX, 2, GL11.GL_FLOAT, false, VSIZE, IOF);
GL20.glVertexAttribPointer(WEIGHT, 2, GL11.GL_FLOAT, false, VSIZE, WOF);
GL20.glEnableVertexAttribArray(VERTEX);
GL20.glEnableVertexAttribArray(NORMAL);
GL20.glEnableVertexAttribArray(COLOR);
GL20.glEnableVertexAttribArray(INDEX);
GL20.glEnableVertexAttribArray(WEIGHT);
while (running && !Display.isCloseRequested())
{ long t = System.currentTimeMillis(); //float deltaTime = (t-time)/1000f;
if ((time = t) >= log)
{ System.out.println("Resolution = "+resolution+", "+frames+" frames per second");
frames = 0; log += 1000;
}
while (Keyboard.next()) if (Keyboard.getEventKeyState()) switch (Keyboard.getEventKey())
{ case Keyboard.KEY_ESCAPE : running = false; break;
case Keyboard.KEY_ADD : resolution++; faces = null; break;
case Keyboard.KEY_SUBTRACT : if (resolution > 0) {resolution--; faces = null;} break;
case Keyboard.KEY_W : pow *= 1.1f; faces = null; break;
case Keyboard.KEY_X : pow /= 1.1f; faces = null; break;
case Keyboard.KEY_C : colors = !colors; faces = null; break;
case Keyboard.KEY_N : normals = !normals; break;
}
if (Keyboard.isKeyDown(Keyboard.KEY_1)) rotate(0, -(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_2)) rotate(0, +(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_3)) rotate(1, -(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_4)) rotate(1, +(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_5)) rotate(2, -(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_6)) rotate(2, +(float)(Math.PI/180));
if (Keyboard.isKeyDown(Keyboard.KEY_A)) tinier(0);
if (Keyboard.isKeyDown(Keyboard.KEY_Z)) bigger(0);
if (Keyboard.isKeyDown(Keyboard.KEY_E)) tinier(1);
if (Keyboard.isKeyDown(Keyboard.KEY_R)) bigger(1);
if (Keyboard.isKeyDown(Keyboard.KEY_T)) tinier(2);
if (Keyboard.isKeyDown(Keyboard.KEY_Y)) bigger(2);
left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
up = Keyboard.isKeyDown(Keyboard.KEY_UP);
right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
down = Keyboard.isKeyDown(Keyboard.KEY_DOWN);
if (Mouse.isButtonDown(0)) camera.navigate(Mouse.getDX(), Mouse.getDY());
if (Mouse.isButtonDown(1)) camera.navigate(Mouse.getDX(), Mouse.getDY());
if (Mouse.isButtonDown(2)) camera.navigate(Mouse.getDX(), Mouse.getDY());
if (left) camera.navigate(4, 0);
if (right) camera.navigate(-4, 0);
if (up) camera.navigate(0, -4);
if (down) camera.navigate(0, 4);
mouseWheel = Mouse.getDWheel();
if (mouseWheel < 0) camera.move(1); else if (mouseWheel > 0) camera.move(-1);
// Clear the screen and depth buffer
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
double a1 = (time%7000)*2*Math.PI/7000, a2 = (time%11000)*2*Math.PI/11000, d = 1*(Math.cos((time%13000)*2*Math.PI/13000)+3),
cos1 = Math.cos(a1), sin1 = Math.sin(a1), cos2 = Math.cos(a2), sin2 = Math.sin(a2);
light.set((float)(d*cos1*cos2), (float)(d*sin2), (float)(d*sin1*cos2));
shaderProgram.setUniform("lightPos", light);
shaderProgram.setUniform("mProjection", camera.getProjectionMatrix());
camera.apply(shaderProgram);
shaderProgram.setUniform("Bones", bones);
if (faces == null)
{ faces = faces(resolution, pow);
size = 3*faces.size();
int bufferSize = size*VSIZE;
if (vbuf == null || vbuf.capacity() < bufferSize) vbuf = BufferUtils.createFloatBuffer(bufferSize);
if (colors) for (Triangle3D f : faces) f.loadrgb(vbuf); else for (Triangle3D f : faces) f.load(vbuf);
System.out.println(size+" points loaded in buffer.");
vbuf.flip();
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vbuf, GL15.GL_DYNAMIC_DRAW);
}
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, size);
if (normals)
{ GL11.glBegin(GL11.GL_LINES);
GL11.glColor3f (1, 1, 1);
for (Triangle3D f : faces) f.undrawNormals();
for (Triangle3D f : faces) f.drawAnimationNormals(VERTEX, NORMAL, COLOR, INDEX, WEIGHT);
GL11.glEnd();
}
Display.update();
frames++;
}
Display.destroy();
}
catch (Exception e) {e.printStackTrace(); System.exit(0);}
}
private LinkedList<Triangle3D> faces(int resolution, float power)
{ LinkedList<Triangle3D> result = new LinkedList<Triangle3D>();
Point3D[] circle = new Point3D[3+3*resolution];
for (int j = 0; j < circle.length; j++)
{ double a = 2*Math.PI*j/circle.length;
float cos = (float)Math.cos(a), sin = (float)Math.sin(a);
circle[j] = new Point3D(null, -8, cos, sin, 0, cos, sin, 1, 0, 0);
}
for (int i = 0; i<=resolution; i++)
{ Point3D[] old = circle;
circle = new Point3D[3+3*resolution];
float f = (float)(i+1)/(float)(resolution+1);
float x = -8+16*f;
float a, b, c;
if (f < 0.5f)
{ a = f < 0.25f ? 0.5f + 0.5f*(float)Math.pow(1-4*f, power) : 0.5f - 0.5f*(float)Math.pow(4*f-1, power);
b = 1-a;
c = 0;
}
else
{ a = 0;
b = f < 0.75f ? 0.5f + 0.5f*(float)Math.pow(3-4*f, power) : 0.5f - 0.5f*(float)Math.pow(4*f-3, power);
c = 1-b;
}
for (int j = 0; j < circle.length; j++)
{ double angle = 2*Math.PI*(j+0.5*(1-i%2))/circle.length;
float cos = (float)Math.cos(angle), sin = (float)Math.sin(angle);
circle[j] = new Point3D(null, x, cos, sin, 0, cos, sin, a, b, c);
}
for (int j = 0; j < circle.length; j++)
{ int k = (j+1)%circle.length, l = i%2==0 ? j : k, m = (l+1)%circle.length;
result.add(new Triangle3D(old[j], old[k], circle[l], null));
result.add(new Triangle3D(circle[m], circle[l], old[k], null));
}
}
return result;
}
}
So, if I comment this part:
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
and this part:
GL11.glVertexPointer(3, GL11.GL_FLOAT, VSIZE, VOF);
GL11.glNormalPointer(GL11.GL_FLOAT, VSIZE, NOF);
GL11.glColorPointer(3, GL11.GL_FLOAT, VSIZE, COF);
then nothing renders anymore !
The Vertex shader:
// The Vertex Color
varying vec4 vColor;
// The Vertex Position
varying vec3 vPosition;
// The Vertex Normal
varying vec3 vNormal;
// The Vertex Texture Coordinates
varying vec2 vTexture;
// The vertex position
attribute vec3 Vertex;
// The normal
attribute vec3 Normal;
// The color
attribute vec3 Color;
// The bones index attributes
attribute vec2 Index;
// The bones weight for each indexed bone
attribute vec2 Weight;
// The view matrix
uniform mat4 mView;
// The projection matrix
uniform mat4 mProjectionView;
// The texture mode
uniform float textured;
// the bone mode
uniform float boned;
// The bones
uniform mat4 Bones[1000];
void main()
{ if (boned == 1.0)
{ // weighted animation
vec4 v = vec4(Vertex, 1.0);
vec4 n = vec4(Normal, 0.0);
v = vec4((Bones[int(Index.x)] * v * Weight.x + Bones[int(Index.y)] * v * Weight.y).xyz, 1.0);
n = vec4((Bones[int(Index.x)] * n * Weight.x + Bones[int(Index.y)] * n * Weight.y).xyz, 0.0);
// Pass the color to the fragment shader
vColor = vec4(Color, 1.0);
// Pass the vertex to the fragment shader
vPosition = (mView * v).xyz;
// Pass the normal to the fragment shader
vNormal = normalize(mView * n).xyz;
// Pass the texture coordinates to the fragment shader
vTexture = gl_MultiTexCoord0.xy;
// Calculate the transformed vertex
gl_Position = mProjectionView * v;
}
else
{ // Pass the color to the fragment shader
vColor = gl_Color;
// Pass the vertex to the fragment shader
vPosition = (mView * gl_Vertex).xyz;
// Pass the normal to the fragment shader
vNormal = normalize(mView * vec4(gl_Normal.xyz, 0.0)).xyz;
// Pass the texture coordinates to the fragment shader
vTexture = gl_MultiTexCoord0.xy;
// Calculate the transformed vertex
gl_Position = mProjectionView * gl_Vertex;
}
}
windows 7 and ATI Radeon HD 4250 Graphics
gonna check that sample, thanks !
Some progress on the no rendering bug I was mentioning with the full attributes vertex shader!
I updated this machine’s graphics drivers, and now I get OpenGL version: 3.3.11672 Compatibility Profile Context.
For some reason, I had to reduce the declared uniforms by a lot for the shader to compile with this new version ! (The Bones mat4 table)
Also with this version I can use the “layout(location = X)” for my attributes (or still use the GL20.glBindAttribLocation method).
BUT!
I found this explanation. So it seems that my problem is that without asking for specific attributes locations I get those values:
Vertex id = 4
Normal id = 3
Color id = 1
Index id = 2
Weight id = 5
And if I force any location value (in the shader or with GL20.glBindAttribLocation), the shader will fail to link for the location 0 (other values are allowed).
But the reserved location 0 is the one for gl_Vertex or something, and rendering functions won’t do anything without it. That is what I got from the previous link;
[quote]This is because, in GL versions before 3.1, all array rendering functions were defined in terms of calls to glArrayElement, which used immediate mode-based rendering. That means that you need something to provoke the vertex. Recall that, in immediate mode, calling glVertex*() not only sets the vertex position, it also causes the vertex to be sent with the other attributes. Calling glVertexAttrib*(0, …) does the same thing. That’s why older versions require you to use either attribute 0 or GL_VERTEX_ARRAY.
[/quote]
So now I have to find a way to either use this location 0 even if not allowed or another way to render on this old computer…
Great, anyway I’d suggest to use a basic hello triangle as basic scenario to determine/test/learn what is working and how
Ps: glEnableClientState is deprecated for example
Thanks, I translated your example for lwjgl and learned a lot. How to use VAOs and elements indexes buffers for example.
I still have to test some things to get all the details I need. Ideally I would like to be compatible with most openGL versions (even found a friend with an older computer, not a gaming one obviously, but it does not support anything past openGL 2.1 !!!).
I still don’t know what advantages I get from recent openGL, as I did not use those functions yet. For skeletal animation, it seems I won’t be able to write a version for openGL 1.0 or 1.1, as it requires 2.0 functions. Finally, I feel I should write different shaders and associated java code for different openGL contexts.
I managed to remove all usage of glEnableClientState from my code, but to do that I needed to use instead:
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, VSIZE, VOF);
GL20.glEnableVertexAttribArray(0);
The reason is that on this computer’s openGL context, linking a vertex shader with an attribute at index 0 is not allowed. So I had to specifically make those calls for index 0 to get the model rendered!
Excellent, this is some really good news, bravo.
Sure, you can lower everything to a common base, such as 2.1 if you don’t have performances issues.
Otherwise, you need to implement code paths…
2.1 guys will take lighter version of your game/app, 3.3 guys instead a finer and higher quality/features version (4.x maybe faster perfs)
You simply can go faster, damn faster. And implementing features you couldn’t do before, or way much easier.
You might go up to hundred time faster with the right implementations and techniques and have space to implement something you thought it was simply impossible before given the performances.
Modern OpenGL helps moving the bound from CPU to GPU.
If we look at the Steam stats, only 2.23% does not support OpenGL 2.1 (DX 9 and below). So you should meet ~98% targetting GL 3.3 (DX 10).
Can you check if you are using a compatibility or a core profile?
with the last driver I get 3.3.11672 Compatibility Profile Context
Try core
I tried with:
Display.create(new PixelFormat(), new ContextAttribs(3, 3).withForwardCompatible(false).withProfileCore(true));
I got 3.3.11672 Core Profile Context.
It renders correctly without any attribute at location 0, thanks !
Just one minor difference;
GL11.glPolygonMode(GL11.GL_BACK, GL11.GL_LINE);
does not work anymore (the faces are now filled on both sides, but in the compatible profile context with this call only the front was filled and lines for the back side…).
I guess it also is a deprecated function ? Do you know what should replace it ?
Bravo Egraynn. You made it
Yep, they changed it in core because it can be done in shaders now, using a combination of geometry and fragment shader. The only accepted value is now GL_FRONT_AND_BACK as specs say.
I don’t know how to do it in shader, but you can trick it quick by rendering twice the geometry you want by culling each time a different side.
Just use…
GL11.glDrawArrays(GL11.GL_LINES, offset, vertex_count);
or…
GL11.glDrawElements(GL11.GL_LINES, vertex_count, GL11.GL_UNSIGNED_INT, offset);
This has not the same semantics as a triangle rasterized in LINE polygon mode.
You would need to build a separate LINES geometry for this.