Litefora's picture

Using VBO´s

Hey guys,

im new to the opengl world and need some help. Please be considerate of that my english isnt the best.
I need to use the VBO´s cause i wanna draw Vector3d-array wich is changed during the programm runs.
Every programm cycle adds a new Vector3d to the array.

The problem i have is, that the framerate decreases hard with every programm cycle even if im using
the vbo`s, and i wanna know what im doing wrong?!

The current code doesnt show`s up any differences in performance between the intermediate mode
and the vbo`s.

This function generates my buffer handle for using the vbo:

        public void GenVBOWoundTube()
        {
            GL.GenBuffers(1, out this.myBufferHandle);
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, this.myBufferHandle);
 
            GL.BufferData<Vector3d>(BufferTarget.ArrayBuffer,
                                          new IntPtr(this.tubeVBO.Count * Vector3d.SizeInBytes),
                                          this.tubeVBO.ToArray(),
                                          BufferUsageHint.DynamicDraw);
        }

The following one draws the array:

        public void DrawWoundTube()
        {
            GL.Enable(EnableCap.CullFace);
            if (this.OnOffVBO == true)
            {
                this.GenVBOWoundTube();
 
                // Use vertex buffer for drawing the wound tube.
                GL.Color3(Color.Red);
 
                GL.EnableClientState(ArrayCap.VertexArray);
 
                GL.BindBuffer(BufferTarget.ArrayBuffer, this.myBufferHandle);
 
                GL.VertexPointer(3, VertexPointerType.Double, 0, 0);
 
                if (this.tubeVBO.Count != 0)
                    GL.DrawArrays(BeginMode.Quads, 0, this.tubeVBO.Count);
 
                GL.DisableClientState(ArrayCap.VertexArray);
 
                GL.DeleteBuffers(1, ref this.myBufferHandle);
            }
            else
            {
                // Use intermediate mode for drawing the wound tube.
                GL.MatrixMode(MatrixMode.Modelview);
 
                GL.Color3(Color.Red);
                GL.Begin(BeginMode.Quads);
 
                for (int i = 0; i < this.tubeVBO.Count; i++)
                {
                    GL.Vertex3(this.tubeVBO[i]);
                }
 
                GL.End();
            }
        }

Just if you`ll need it to understand the code the following function is cyclic called and adds an amount of vector3d`s to the
Vector3d-list wich is converted into an array with the .ToArray() - function:

        private void ComputeWoundTube(int layer)
        {
            // Variable for the rotation of cross section.
            double rotAngle = 0;
 
            // Vector list for tube cross section.
            List<Vector3d> radiusFullTube = new List<Vector3d>();
            for (double i = 0; i < 16; i++)
            {
                double alpha = (( i / 16) * (Math.PI) * 2);
 
                radiusFullTube.Add(new Vector3d()
                {
                    X = 0,
                    Y = (((this.seeSawMeasures.RadiusTube) / scale_factor) * Math.Sin(alpha)) + (this.seeSawMeasures.RadiusTube / scale_factor),
                    Z = ((this.seeSawMeasures.RadiusTube) / scale_factor) * Math.Cos(alpha)
                });
            }
 
            # region compute rot angle
 
            // Compute rotation angle for cross section.
            // Left side.
            if (layer == 1)
                rotAngle = 90;
            // Top side.
            if (layer == 3)
                rotAngle = 0;
            // Right side.
            if (layer == 5)
                rotAngle = 270;
            // Bot side
            if (layer == 7)
                rotAngle = 180;
            // Bot left.
            if (layer == 0)
                rotAngle = 180 - (double)(this.iter * (90.0 / this.pointsPerRadius));
            // Top left.
            if (layer == 2)
                rotAngle = 90 - (double)(this.iter * (90.0 / this.pointsPerRadius));
            // Top right.
            if (layer == 4)
                rotAngle = -(double)(this.iter * (90.0 / this.pointsPerRadius));
            // Bot right.
            if (layer == 6)
                rotAngle = 270 - (double)(this.iter * (90.0 / this.pointsPerRadius));
 
            # endregion
 
            # region rotate and translate cross section
 
            // Compute rotation matrix rows (rotation around z-axis).
            Vector3d row1 = new Vector3d((Math.Cos((rotAngle * (Math.PI / 180)))), (-(Math.Sin((rotAngle * (Math.PI / 180))))), 0);
            Vector3d row2 = new Vector3d((Math.Sin((rotAngle * (Math.PI / 180)))), (Math.Cos((rotAngle * (Math.PI / 180)))), 0);
            Vector3d row3 = new Vector3d(0, 0, 1);
 
            // Rotate the cross section of the tube.
            List<Vector3d> tempRot = new List<Vector3d>();
            for (int i = 0; i < radiusFullTube.Count; i++)
            {
                tempRot.Add(new Vector3d()
                {
                    X = ((row1.X * (radiusFullTube[i].X)) + (row1.Y * (radiusFullTube[i].Y)) + (row1.Z * (radiusFullTube[i].Z))),
                    Y = ((row2.X * (radiusFullTube[i].X)) + (row2.Y * (radiusFullTube[i].Y)) + (row2.Z * (radiusFullTube[i].Z))),
                    Z = ((row3.X * (radiusFullTube[i].X)) + (row3.Y * (radiusFullTube[i].Y)) + (row3.Z * (radiusFullTube[i].Z)))
                });
            }
 
            // Translate rotated cross section to current contact point position.
            List<Vector3d> tempRotTrans = new List<Vector3d>();
            for (int i = 0; i < tempRot.Count; i++)
            {
                tempRotTrans.Add(new Vector3d()
                {
                    X = tempRot[i].X + this.tubePoints[this.tubePoints.Count - 1].X,
                    Y = tempRot[i].Y + this.tubePoints[this.tubePoints.Count - 1].Y,
                    Z = tempRot[i].Z + this.tubePoints[this.tubePoints.Count - 1].Z
                });
            }
 
            # endregion
 
            # region add cross section
 
            // Add new tube cross section.
            this.tubeDrawingPoints.Add(new List<Vector3d>());
            for (int i = 0; i < tempRotTrans.Count; i++)
            {
                this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 1].Add(new Vector3d()
                {
                    X = tempRotTrans[i].X,
                    Y = tempRotTrans[i].Y,
                    Z = tempRotTrans[i].Z
                });
            }
 
            // Vertexlist for the vbo.
            if (this.tubeDrawingPoints.Count >= 2)
            {
                for (int j = 0; j < this.tubeDrawingPoints[1].Count - 1; j++)
                {
                    this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 2][j]));
                    this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 1][j]));
                    this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 1][j + 1]));
                    this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 2][j + 1]));
                }
 
                this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 2][this.tubeDrawingPoints[1].Count - 1]));
                this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 1][this.tubeDrawingPoints[1].Count - 1]));
                this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 1][0]));
                this.tubeVBO.Add(new Vector3d(this.tubeDrawingPoints[this.tubeDrawingPoints.Count - 2][0]));
            }
 
            # endregion
        }

All in all the programm runs as expected, but im not satisfied with the performance!!
What im doing wrong?!

Greetings,

Litefora


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
winterhell's picture

If you have BufferUsageHint.DynamicDraw then you should update the buffer instead of destroying and creating new one.
Replace List<Vector3d> radiusFullTube with double[]radiusFullTube=new double[ 16 * 3] //because 16 entries * 3 components of the vector
Same for the other lists.
then when filling them out

radiusFullTube[i*3 + 0 ] =X;
radiusFullTube[i*3 + 1 ] =Y;
radiusFullTube[i*3 + 2 ] =Z;

Also you may not need Double precision for the actual rendering, so you can save half of the bandwidth.

If you are not sure, you can test
a) generating the buffer once and rendering every frame the same buffer
b) only calculating the arrays, but not updating the vertex buffer and no rendering
c) calculating + updating, no rendering

This is going to reveal where your bottleneck is.

Litefora's picture

Okay ill try your hints and give feedback afterwards. Thanks a lot!