PDA

View Full Version : Buffers and attribute pointers for drawing a triangle



Cubby208
12-25-2015, 09:07 PM
So I have a program i am trying to make in OpenGL es 2.0. My goal is to have as many capsules going on the screen at the same time without loosing framerate, so like if I could get 2000 going I would be a happy camper. Unfortunately even though I have this going well when I try to push the particle amount up to like 200 the fps starts going down like crazy. I have diagnosed that this is because of my cpu drawing code making buffers etc.

My second problem is that unfortunately OpenGL es 2.0 does not support lines with thickness, so I have had to build a rectangle for each particle. Thankfully though it does support point size, saving TONS of rendering power.

Basically each particle has a (BTW this data is stored and retrieved from a class):
-Current position
-Previous Position
-Color
-Size (width of capsule)

And is drawn as a capsule based on the two endpoints. The two positions are drawn as dots and go on the end of the capsule. And inside of the space between them is drawn two triangles forming a rectangle.

I have this drawing code going already I just need it WAYY more efficient!

Here is how I am doing things now:

Every frame:
1. Draw Lines
A. Create two arrays one containing color and size
B. Create all of the rectangles and put each vertex in order in a buffer
C. Use Line shader
D. Bind buffer 0
E. Build buffers for vertex, color, and size
F. Pass in projection matrix
G. glDraw the lines
2. Draw dots
A. Create three arrays containing vertex, color, and size
B. Use point shader
C. Bind buffer 0
D. Build buffers for vertex, color, and size
E. Pass in projection matrix
F. glDraw the dots

Something needs to become waaayyyy more efficient. Can you suggest any ways to do this. One thought is reusing the same buffers.

I just wish their was some way to reuse the color and size buffers and arrays even though the rectangles have way more points then the dots do. And probably to reuse the buffers instead of recreating them every time. Also using a triangle strip instead of just triangles. Unfortunately I do not know how to do either, also these ideas might be the only ones.

Anyway if you want to delve into the code here it is
How I make the 2 triangles forming a rectangle, this happens for every single particle.

func calculateSquare(pp1: point, pp2: point, size: CGFloat) -> [GLfloat]
{

let p1 = pp1
var p2 = pp2
var s1 = point()
var s2 = point()
let center = CGPointMake((p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0)


var angle:CGFloat = 0
if ((p1.x == p2.x) && (p1.y == p2.y))
{
//They are ontop of eachother
angle = CGFloat(M_PI) / 2.0
p2.x += 0.0001
p2.y += 0.0001
}
else
{
if(p1.x == p2.x)
{
//UH OH x axis is equal
if (p1.y < p2.y)
{
//RESULT: p1 is lower so should be first
s1 = p1
s2 = p2
}
else
{
//RESULT: p2 is lower and should be first
s1 = p2
s2 = p1
}
}
else
{
//We could be all good
if (p1.y == p2.y)
{
//Uh oh y axis is equal
if (p1.x < p2.x)
{
//RESULT: p1 is left so should be first
s1 = p1
s2 = p2
}
else
{
//RESULT: p2 is to the right so should be first
s1 = p2
s2 = p1
}
}
else
{
//Feuf everything is ok
if ((p1.x < p2.x) && (p1.y < p2.y)) //First point is left and below
{
//P1 should be first
s1 = p1
s2 = p2
}
else //First point is right and top
{
//P2 should be first
s1 = p2
s2 = p1
}
}

}
angle = angle2p(s1, p2: s2)
}
if (angle < 0)
{
angle += CGFloat(M_PI) * 2.0
}

let yh = size / 2.0
let distance = dist(p1, p2: p2)
let xh = distance / 2.0

let tl = rotateVector(CGPointMake(-xh, yh), angle: angle) + center
let tr = rotateVector(CGPointMake(xh, yh), angle: angle) + center
let bl = rotateVector(CGPointMake(-xh, -yh), angle: angle) + center
let br = rotateVector(CGPointMake(xh, -yh), angle: angle) + center

let c1:[GLfloat] = [GLfloat(bl.x), GLfloat(bl.y), 0]
let c2:[GLfloat] = [GLfloat(tl.x), GLfloat(tl.y), 0]
let c3:[GLfloat] = [GLfloat(br.x), GLfloat(br.y), 0]
let c4:[GLfloat] = [GLfloat(tr.x), GLfloat(tr.y), 0]
let part1 = c1 + c2 + c3
let part2 = c2 + c3 + c4
return part1 + part2
}
func rotateVector(vector: CGPoint, angle: CGFloat) -> CGPoint
{
let cosa = cos(angle)
let sina = sin(angle)

return CGPointMake(vector.x * cosa - vector.y * sina, vector.x * sina + vector.y * cosa)
}


Every frame drawing

func draw()
{
buildParticleArrays()
glUseProgram(lineShader)
glEnableVertexAttribArray(0)
buildLineStripBuffer()
drawLineStrip()
destroyLineStripBuffer()

glUseProgram(pointShader)
glEnableVertexAttribArray(0)
n_buildBuffers()
n_drawDots()
n_destroyBuffers()
}


Building the arrays (notice I have edited the code and both the arrays for points and triangles are built here now)

func buildParticleArrays()
{
lineStrip = []
lineStripColors = []
lineStripsize = []
s_vertes = []
s_color = []
s_size = []
for cparticle in particles
{
let pp = cparticle.lastPosition
let np = cparticle.position
if (cparticle.frozen == true)
{
addPoint(cparticle.position, color: cparticle.color, size: cparticle.size)
}
else
{
let s = cparticle.size / 2.0

//Add point merely adds the data in array format
addPoint(cparticle.position, color: cparticle.color, size: cparticle.size)
addPoint(cparticle.lastPosition, color: cparticle.color, size: cparticle.size)

lineStrip += calculateSquare(pp, pp2: np, size: s)


for var i = 0; i < 6; i++
{
let rgb = hsvtorgb(cparticle.color)
lineStripColors.append(GLfloat(rgb.r))
lineStripColors.append(GLfloat(rgb.g))
lineStripColors.append(GLfloat(rgb.b))
lineStripColors.append(GLfloat(rgb.a))
lineStripsize.append(GLfloat(cparticle.size))
}
}



}
}


The code to pass and draw the rectangles

func buildLineStripBuffer()
{
//Make our line strip buffer
glGenBuffers(1, &lvb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lvb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * lineStrip.count, lineStrip, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lvbl = GLuint(glGetAttribLocation(lineShader, "vertex"))
glEnableVertexAttribArray(lvbl)
glVertexAttribPointer(lvbl, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))


//Make our line strip buffer
glGenBuffers(1, &lcb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lcb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * lineStripColors.count, lineStripColors, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lcbl = GLuint(glGetAttribLocation(lineShader, "color"))
glEnableVertexAttribArray(lcbl)
glVertexAttribPointer(lcbl, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))

//Make our line strip buffer
glGenBuffers(1, &lsb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lsb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * lineStripsize.count, lineStripsize, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lsbl = GLuint(glGetAttribLocation(lineShader, "size"))
glEnableVertexAttribArray(lsbl)
glVertexAttribPointer(lsbl, 1, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))


}

func drawLineStrip()
{
let loc3 = glGetUniformLocation(lineShader, "orthoMatrix")
if (loc3 != -1)
{
glUniformMatrix4fv(loc3, 1, GLboolean(GL_FALSE), &matrix)
}

glDrawArrays(GLenum(GL_TRIANGLES), 0, GLsizei(lineStripsize.count))
}

func destroyLineStripBuffer()
{
glDeleteBuffers(1, &lsb)
glDeleteBuffers(1, &lcb)
glDeleteBuffers(1, &lsb)
}

And similarly I draw the dots

func n_buildBuffers()
{
//Make our line strip buffer
glGenBuffers(1, &lvb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lvb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * s_vertes.count, s_vertes, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lvbl = GLuint(glGetAttribLocation(pointShader, "vertex"))
glEnableVertexAttribArray(lvbl)
glVertexAttribPointer(lvbl, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))



//Make our line strip buffer
glGenBuffers(1, &lcb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lcb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * s_color.count, s_color, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lcbl = GLuint(glGetAttribLocation(pointShader, "color"))
glEnableVertexAttribArray(lcbl)
glVertexAttribPointer(lcbl, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))

//Make our line strip buffer
glGenBuffers(1, &lsb)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), lsb)
glBufferData(GLenum(GL_ARRAY_BUFFER), sizeof(GLfloat) * s_size.count, s_size, GLenum(GL_STATIC_DRAW))

//Attach it to shader
lsbl = GLuint(glGetAttribLocation(pointShader, "size"))
glEnableVertexAttribArray(lsbl)
glVertexAttribPointer(lsbl, 1, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))


}
func n_drawDots()
{
let loc3 = glGetUniformLocation(lineShader, "orthoMatrix")
if (loc3 != -1)
{
glUniformMatrix4fv(loc3, 1, GLboolean(GL_FALSE), &matrix)
}

glDrawArrays(GLenum(GL_POINTS), 0, GLsizei(s_size.count))
}
func n_destroyBuffers()
{
glDeleteBuffers(1, &lsb)
glDeleteBuffers(1, &lcb)
glDeleteBuffers(1, &lsb)
}


Also I had another thought. Perhaps is their a way I could get the calculations for the rectangle to happen on the GPU?