0

I'm trying to draw a circle in LWJGL, but when I draw I try to draw it, it makes a shape that's more like an oval rather than a circle. Also, when I change my circleVertexCount 350+, the shape like flips out. I'm really not sure how the code works that creates the vertices(I have taken Geometry and I know the basic trig ratios). I haven't really found that good of tutorials on creating circles. Here's my code:

public class Circles {

// Setup variables
private int WIDTH = 800;
private int HEIGHT = 600;
private String title = "Circle";

private float fXOffset;

private int vbo = 0;
private int vao = 0;

int circleVertexCount = 300;

float[] vertexData = new float[(circleVertexCount + 1) * 4];

public Circles() {
    setupOpenGL();
    setupQuad();

    while (!Display.isCloseRequested()) {
        loop();
        adjustVertexData();
        Display.update();
        Display.sync(60);
    }

    Display.destroy();
}

public void setupOpenGL() {
    try {
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT)); 
        Display.setTitle(title);
        Display.create();

    } catch (LWJGLException e) {
        e.printStackTrace();
        System.exit(-1);
    }

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 
}

public void setupQuad() {
    float r = 0.1f;
    float x;
    float y;
    float offSetX = 0f;
    float offSetY = 0f;
    double theta = 2.0 * Math.PI;

    vertexData[0] = (float) Math.sin(theta / circleVertexCount) * r + offSetX;
    vertexData[1] = (float) Math.cos(theta / circleVertexCount) * r + offSetY;

    for (int i = 2; i < 400; i += 2) {
        double angle = theta * i / circleVertexCount;
        x = (float) Math.cos(angle) * r;
        vertexData[i] = x + offSetX;
    }

    for (int i = 3; i < 404; i += 2) {
        double angle = Math.PI * 2 * i / circleVertexCount;
        y = (float) Math.sin(angle) * r;
        vertexData[i] = y + offSetY;
    }

    FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(vertexData.length);
    vertexBuffer.put(vertexData);
    vertexBuffer.flip();

    vao = glGenVertexArrays();
    glBindVertexArray(vao);

    vbo = glGenBuffers();
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER,vertexBuffer, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

}

public void loop() {
    glClear(GL_COLOR_BUFFER_BIT); 

    glBindVertexArray(vao);
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexData.length / 2);

    glDisableVertexAttribArray(0);
    glBindVertexArray(0);
}

public static void main(String[] args) {
    new Circles();
}

private void adjustVertexData() {
    float newData[] = new float[vertexData.length];
    System.arraycopy(vertexData, 0, newData, 0, vertexData.length);

    if(Keyboard.isKeyDown(Keyboard.KEY_W)) {
        fXOffset += 0.05f;
    } else if(Keyboard.isKeyDown(Keyboard.KEY_S)) {
        fXOffset -= 0.05f;
    }

    for(int i = 0; i < vertexData.length; i += 2) {
        newData[i] += fXOffset;
   }

    FloatBuffer newDataBuffer = BufferUtils.createFloatBuffer(newData.length);
    newDataBuffer.put(newData);
    newDataBuffer.flip();

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferSubData(GL_ARRAY_BUFFER, 0, newDataBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}

300 Vertex Count(This is my main problem) LWJGL Oval Figure

400 Vertex Count - I removed this image, it's bugged out, should be a tiny sliver cut out from the right, like a secant

500 Vertex Count Circle - 500 Vertices

Each 100, it removes more and more of the circle, and so on.

N1ghtk1n9
  • 89
  • 3
  • 12

1 Answers1

1

One of your problems is this:

for (int i = 2; i < 400; i += 2) {
    double angle = theta * i / circleVertexCount;
    x = (float) Math.cos(angle) * r;
    vertexData[i] = x + offSetX;
}

for (int i = 3; i < 404; i += 2) {
    double angle = Math.PI * 2 * i / circleVertexCount;
    y = (float) Math.sin(angle) * r;
    vertexData[i] = y + offSetY;
}

You are using a different value for angle for the x and y position of each vertex.

You could try this instead:

for (int i = 0; i <= circleVertexCount; i++) {
    double angle = i * theta / circleVertexCount;
    x = (float) Math.cos(angle) * r;
    y = (float) Math.sin(angle) * r;
    vertexData[i * 2] = x + offSetX;
    vertexData[i * 2 + 1] = y + offSetY;
}

The reason part of your circle was being cut out at higher vertex counts was the i < 400 in your for loops, so I have changed it to i <= circleVertexCount.

Another problem is that your window is not square, and you are not using a shader (or the deprecated built in matrices) to correct this. This means that one unit up looks a different length than one unit right, resulting in an oval instead of a circle. To fix this you could multiply your vertex x position by your display height divided by your display width, preferably in a shader.

Alex - GlassEditor.com
  • 14,957
  • 5
  • 49
  • 49
  • Do I need shaders for this? I didn't think I would since this program is simple – N1ghtk1n9 May 30 '14 at 15:53
  • Also, could you give me a quick example on how I would do this in a shader? I know how to do uniforms(if I needed to for width and height, or just hardcode in the shader) – N1ghtk1n9 May 30 '14 at 15:58
  • You don't need them for this, but they will make your life alot easier in the long run. If you don't want to use them just change the line that sets x to `x = (float) Math.cos(angle) * r * HEIGHT / WIDTH;` – Alex - GlassEditor.com May 30 '14 at 16:00
  • That actually answers another question of mine too. I tried to draw a square and it ended up being a rectangle(because the . If I stored the values in an array(in the program), how would I transfer the array values to the shader, and then make the positions to make it a square(as in: pos * HEIGHT / WIDTH)? – N1ghtk1n9 May 30 '14 at 18:01
  • @N1ghtk1n9 I would set the width and height as a uniform in my vertex shader, then divide the position of the vertex by it. If your not sure how to write and setup a shader, there is a good tutorial [here](http://arcsynthesis.org/gltut/). – Alex - GlassEditor.com May 30 '14 at 18:34
  • Like I would do: gl_Position = position * HEIGHT / WIDTH , where position is like: layout(location = 0) in vec4 position, or something along those lines. Would the position array be automatically transferred from the glVertexAttribPointer() into the vertex shader? – N1ghtk1n9 May 30 '14 at 18:43
  • 1
    You could do `gl_Position = vec4(position.x * HEIGHT / WIDTH, position.y, 0, 1);`, although I would rather do `gl_Position = vec4(position * 2 / window, 0, 1);` assuming position and window are both vec2s. The second option maps one unit to one pixel, so you would need to make your radius larger to see the circle. – Alex - GlassEditor.com May 30 '14 at 18:53
  • 1
    Yes `layout(location = 0) in vec2 position;` should work for you, and you can move your call to `glEnableVertexAttribArray(0);` to after `glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);` if you remove the disable call, the vao takes care of that. – Alex - GlassEditor.com May 30 '14 at 19:01
  • The above is assuming your using version 330 shaders. – Alex - GlassEditor.com May 30 '14 at 19:16
  • If I did the ...in vec4 position; would I have do glVertexAttribPointer(0, 4, …)? Also, when you said if you remove the disable call, did you mean glDisableVertexAttribArray(0)? – N1ghtk1n9 May 30 '14 at 20:00
  • Yes I meant `glDisableVertexAttribArray(0)`, and no I believe that `in vec4 position` will cause the values you don't send to be filled with 0, except for the last (w) which becomes 1, so you would not need `glVertexAttribPointer(0, 4, …)`. You might want to try it though I could be wrong. – Alex - GlassEditor.com May 30 '14 at 20:15
  • I made it so it's: `x = (float) Math.cos(angle) * r * HEIGHT / WIDTH;` and it still is making an oval. Any ideas? – N1ghtk1n9 Jun 02 '14 at 14:42