4

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

J.Doe
  • 1,445
  • 12
  • 23
  • Have you tried setting stride to 0in your glVertexAttribPointer calls? Having skim read your code it looks mostly ok :) – PaulHK Sep 01 '16 at 06:23
  • That worked for some reason. Unfortunately the rectangle only fills half the screen nomatter the scale factor. – J.Doe Sep 01 '16 at 06:37
  • 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. – PaulHK Sep 01 '16 at 06:46
  • @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. – J.Doe Sep 01 '16 at 06:48
  • Can't see anywhere which would cause only half the screen to be visible, it could be a bad glViewPort setup ? – PaulHK Sep 01 '16 at 06:56
  • @paulhk I think it is that the triangles don't exist or aren't being drawn after the half way point. Sometimes it will have like triangles jetting out at the edge of the rectangle – J.Doe Sep 01 '16 at 06:58
  • @PaulHK I added a picture – J.Doe Sep 01 '16 at 07:07
  • I would suspect something is wrong with your indice buffer. It looks like there is a giant single triangle spanning your whole image (i can see a slanting near horizontal edge along the top amongst the saw tooth pattern). Your indice count for a grid of triangle strips should be ((W2) + 1) (H-1) * 2 indices. You only need 1 degenerate vertice per triangle strip emitted. Maybe enabling wireframe rendering will better help visualise this. – PaulHK Sep 01 '16 at 07:17

1 Answers1

3

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.

PaulHK
  • 2,322
  • 10
  • 11
  • 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. – J.Doe Sep 01 '16 at 08:44
  • 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 ? – PaulHK Sep 01 '16 at 08:59
  • Sure, i added a section to the bottom of the post. Let me know if you need/want more data. – J.Doe Sep 01 '16 at 09:40
  • 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). – PaulHK Sep 01 '16 at 09:42
  • I also editted my example above to remove the redundant end-of-row if(...) – PaulHK Sep 01 '16 at 09:44
  • OK so if I use glshorts then my draw call should have Glenum(gl_unsigned_short) however if I am using Ints (32 I think) then it's glenum (gl_unsigned_int)? – J.Doe Sep 01 '16 at 09:50
  • Yes, I'm almost certain from your last image this is the cause of the problem. If you interpret a buffer full of 32bit ints as 16bit shorts, you will read the upper/lower halves of the 32bit indexes per 16bit index, which in your case will be index 0 every odd index. – PaulHK Sep 01 '16 at 09:57
  • Yes you are most certainly right! It is working quite well now! If you could please add the bit about matching up the indicie data type with the gldraw call then I will award you the bounty when SO allows me to. Thankyou so much! – J.Doe Sep 01 '16 at 09:58
  • Brilliant, happy to help – PaulHK Sep 01 '16 at 10:02
  • @J.Doe it's entirely your choice, but if you avoid awarding the bounty until nearer the end of the bounty period, then your question will continue to be promoted on the front page, which means more people will see it. This may mean more voting on both your question and on PaulHK's answer... – trichoplax is on Codidact now Sep 02 '16 at 12:35
  • I've just been waiting for the 24 hours before bounty to expire. But now that you say that I'll hold off a bit so that perhaps he can get more votes. – J.Doe Sep 02 '16 at 16:34