6
$\begingroup$

I am trying to translate an old (2013) bit of code from Apple from objective C to Swift with some modifications I need for my simulation.

The code I am translating can be found here

To make translation easier I have broken the simulation into parts. The part I am working on now (and am stuck on) is thus: I simply need to draw your general full screen texture coords shader however I need it to be broken up into a grid. If I have a grid scale factor 1 then each pixel on the screen will get a triangle and that will make up the mesh. However if I put in 10 then there will be a triangle every 10 pixels. Essentially this is the resolution of my simulation.

My problem is these images (the numbers indicate the scale factor of the pond): enter image description here For some reason rather then drawing a full screen texture coord drawing it draws this weirdness (Some of these honestly belong in a modern art museum). I really have no clue where to look in my code to find this issue, my guess is it is the indices.
You would see the individual triangles on the top of the 1st and second image but I killed the resolution so it wasn't difficult to upload to SO.

So first off here is how I define all of the arrays that make up this simulation:

var rSimWidth:Int = 0
var rSimHeight:Int = 0
var mesh:[GLfloat] = []
var tex:[GLfloat] = []
var ind:[Indicie] = []

var realWidth:Int = 0
var realHeight:Int = 0

//In this case width = 568, height = 320, mpp varies look at top of picture
init(width: Int, height: Int, mpp: Int)
{
    rSimWidth = width / mpp
    rSimHeight = height / mpp
    rSimWidth += 1; rSimHeight += 1
    realWidth = width
    realHeight = height

    mesh = [GLfloat](count: rSimWidth * rSimHeight * 2, repeatedValue: 0)
    tex = [GLfloat](count: rSimWidth * rSimHeight * 2, repeatedValue: 0)
    ind = [Indicie](count: (rSimHeight-1)*(rSimWidth*2+2), repeatedValue: 0)

    print("Screen is (\(width) x \(height))\tPond is (\(rSimWidth) x \(rSimHeight))\tScreenSA: \(width * height)\tPond sa: \(rSimWidth * rSimHeight)\tMP: \(mpp) \((rSimWidth * rSimHeight) * mpp)")
}

Then I fill up the indices. I had difficulties with this because of the data type. I believe for indices I am supposed to use GLushort however on my system the maximum value is 65,535 . This value was quickly overflowed by the indice generation so I had to switch it to "Int". There is a typedef "Indicie" so I can change the type of data in the indices easily. What I find odd is when I ramped up the simulation resolution in the apple code I never had an overflow issue.

    var index:Int = 0
    for i in 0..<rSimHeight - 1
    {
        for j in 0..<rSimWidth
        {
            if (i%2==0)//X is even
            {
                if (j == 0)
                {
                    //DEGENRATE TRIANGLE
                    ind[index] = Indicie(i*rSimWidth + j)
                    index += 1
                }

                ind[index] = Indicie(i * rSimWidth + j)
                index += 1
                ind[index] = Indicie((i + 1) * rSimWidth + j)
                index += 1
                //(114 + 1) * 569 + 101
                //

                if (j == rSimWidth - 1)
                {
                    //DEGENERATE TRIANGLE
                    ind[index] = Indicie((i+1)*rSimWidth + j)
                    index += 1
                }
            }
            else
            {
                if (j == 0)
                {
                    //DEGENRATE TRIANGLE
                    ind[index] = Indicie((i+1)*rSimWidth + j)
                    index += 1
                }

                ind[index] = Indicie((i + 1) * rSimWidth + j)
                index += 1
                ind[index] = Indicie(i * rSimWidth + j)
                index += 1

                if (j == rSimWidth - 1)
                {
                    //DEGENRATE TRIANGLE
                    ind[index] = Indicie(i*rSimWidth + j)
                    index += 1
                }
            }
        }
    }

In case you wish to see the position and tc code

  for yy in 0..<rSimHeight
    {let y = GLfloat(yy);
        for xx in 0..<rSimWidth
        {let x = GLfloat(xx);
            let index = (yy*rSimWidth + xx) * 2
            tex[index] = x / GLfloat(rSimWidth - 1)
            tex[index + 1] = y / GLfloat(rSimHeight - 1)

            mesh[index] = tex[index] * GLfloat(realWidth)
            mesh[index + 1] = tex[index + 1] * GLfloat(realHeight)
        }
    }

Here is the drawing code

     glUseProgram(shade.progId)


    let posLoc = GLuint(glGetAttribLocation(shade.progId, "pos"))
    let texLoc = GLuint(glGetAttribLocation(shade.progId, "tc"))


    glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
    glBufferData(GLenum(GL_ARRAY_BUFFER), sim.tex.count * sizeof(GLfloat), sim.tex, GLenum(GL_DYNAMIC_DRAW));
    glVertexAttribPointer(texLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 2, BUFFER_OFFSET(0))
    glEnableVertexAttribArray(texLoc)

    glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO)
    glVertexAttribPointer(posLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 2, BUFFER_OFFSET(0))
    glEnableVertexAttribArray(posLoc)

    let uniOrtho = glGetUniformLocation(shade.progId, "matrix")
    glUniformMatrix4fv(uniOrtho, 1, GLboolean(GL_FALSE), &orthographicMatrix)


    glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO)


    glDrawElements(GLenum(GL_TRIANGLE_STRIP), GLsizei(sim.ind.count), GLenum(GL_UNSIGNED_SHORT), nil)

    glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
    glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
    glDisableVertexAttribArray(posLoc)
    glDisableVertexAttribArray(texLoc)

I really have 0 clues as to why something THIS weird is drawing rather then something that makes sense. Any suggestions of what it might be or tips are appreciated!

Extra note: I am so sorry but Swift likes to think it is special so it ditched c style for loops. Basically for all of these loops think

for (var i = <value before ..>; i < <value after dot>; <happens automatically>)

EDIT: Here is the matrix code

var orthographicMatrix:[GLfloat] = []

    func buildMatrix()
    {
        orthographicMatrix = glkitmatrixtoarray(GLKMatrix4MakeOrtho(0, GLfloat(width), 0, GLfloat(height), -100, 100))
        //Storage.upScaleFactor
    }
    func glkitmatrixtoarray(mat: GLKMatrix4) -> [GLfloat]
    {
        var buildme:[GLfloat] = []
        buildme.append(mat.m.0)
        buildme.append(mat.m.1)
        buildme.append(mat.m.2)
        buildme.append(mat.m.3)
        buildme.append(mat.m.4)
        buildme.append(mat.m.5)
        buildme.append(mat.m.6)
        buildme.append(mat.m.7)
        buildme.append(mat.m.8)
        buildme.append(mat.m.9)
        buildme.append(mat.m.10)
        buildme.append(mat.m.11)
        buildme.append(mat.m.12)
        buildme.append(mat.m.13)
        buildme.append(mat.m.14)
        buildme.append(mat.m.15)
        return buildme

    }

Now the issue is not the abstract art but that the rectangle only goes half way nomater the scale factor. Notice the jagged edge enter image description here

In apples frame debugger you can see the outline of all the triangles that it draws it looks like this: enter image description here Could it be this line that is causing all the trouble let index = (yy*rSimWidth + xx) * 2

A test: I tried the code out by passing 3, 3, and 1 into the initialize function. This should in theory make a 3x3 pixel square, however it just made a mess. Here is all the data on the CPU, and here (according to frame capture take as grain of salt) is how the gpu understands it. enter image description here

$\endgroup$
  • $\begingroup$ Have you tried setting stride to 0in your glVertexAttribPointer calls? Having skim read your code it looks mostly ok :) $\endgroup$ – PaulHK Sep 1 '16 at 6:23
  • $\begingroup$ That worked for some reason. Unfortunately the rectangle only fills half the screen nomatter the scale factor. $\endgroup$ – J.Doe Sep 1 '16 at 6:37
  • $\begingroup$ Your stride should be 0, usually that is only used when you have interleaved buffers (Pos&Tex in the same VBO). For your half-screen thing I would need to see your orthographic matrix. $\endgroup$ – PaulHK Sep 1 '16 at 6:46
  • $\begingroup$ @PaulHK Added to post, I use apples function for that and then put it into a float array. The width and height values are the same ones passed into the initialization of the ripple simulation. $\endgroup$ – J.Doe Sep 1 '16 at 6:48
  • $\begingroup$ Can't see anywhere which would cause only half the screen to be visible, it could be a bad glViewPort setup ? $\endgroup$ – PaulHK Sep 1 '16 at 6:56
4
+300
$\begingroup$

I think you are not constructing the index buffer correctly. Firstly you only need 1 degenerate vertex to terminate each triangle-strip row.

You also should not need any special handling for odd/even rows. You can emit a single triangle-strip per loop.

Your index loop should look something like :

var index:Int = 0
for i in 0..<rSimHeight - 1
{
    for j in 0..<rSimWidth
    {
        ind[index++] = Indicie(i*rSimWidth + j);        // current row
        ind[index++] = Indicie((i+1)*rSimWidth + j);    // row below
    }
    ind[index] = ind[index-1];      // degenerate vertex / row termination
    index++;
}

This also means your index count is defined like:

int triStripRows = rSimHeight - 1;
int indicesPerRow = (rSimWidth * 2) + 1
int totalIndices = indicesPerRow * triStripRows;

Edit : After seeing the vertex dump you added to your question I can see there is another problem with the index buffer format. Every odd item in the vertex list is vertice 0. This looks like index buffer is created using 32bit indexes but is being interpreted by opengl as 16bits. So it will read the lower 16bits then upper 16bits of each index. This can be fixed by either changing Indicie data type to 16bit (short) or telling opengl the index buffer is really 32 bits by using GL_UNSIGNED_INT instead of GL_UNSIGNED_SHORT in glDrawElements.

$\endgroup$
  • $\begingroup$ Your code causes the same issue however it is significantly more efficent so thanks!, I have updated the post with some new diagrams that might help. $\endgroup$ – J.Doe Sep 1 '16 at 8:44
  • $\begingroup$ It kind of looks like its being drawn as a triangle fan, but not quite. Is it possible you can make a small grid (say 9 points, so rSimXXX = 3) and then manually inspect/dump the index buffer ? $\endgroup$ – PaulHK Sep 1 '16 at 8:59
  • $\begingroup$ Sure, i added a section to the bottom of the post. Let me know if you need/want more data. $\endgroup$ – J.Doe Sep 1 '16 at 9:40
  • $\begingroup$ Ok, things are starting to make sense, it looks like you have 0's interleaved for every other element, which explains all the spiky triangles going to one corner. I suspect your Indicie(..) objects are 32bits, but in the glDrawElements call you tell opengl the index buffer is 16bits (unsigned shorts). You can either change the glDrawElements to accept 32bit integers (change GL_UNSIGNED_SHORT -> GL_UNSIGNED_INT) or change your Indicie object to be 16bit (I guess int->short but I am not familiar with swift). $\endgroup$ – PaulHK Sep 1 '16 at 9:42
  • $\begingroup$ I also editted my example above to remove the redundant end-of-row if(...) $\endgroup$ – PaulHK Sep 1 '16 at 9:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.