objarni's picture

A step towards GL3

I'm a traditional OpenGL developer in the sense that I keep using immediate mode because I think it is so intuitive and easy-to-use.

I know this mode of GL operation is deprecated (maybe even removed?) with GL3, hence I am trying to "take the leap" and start using vertex array, vertex buffer objects and so on.

So I thought: can't I use the best of both worlds? Why not have a "vertex array builder" object that operates much like traditional immediate mode, and then creates/draws the vertex array for me?

My thoughts then went on to "should I create VAs or VBOs or even generate source code to draw VAs and so on"? Since I do know how VAs work already, I think this is a good start to build this "builder object".

I will begin with support for vertex position, color, normals and texture coordinate. That is the "bread and butter" of OpenGL, and I can expand on that when I need to.

Some pseudocode to show what I mean:

// code to build a multi coloured triangle vertex array
VABuilder builder = new VABuilder();
builder.Color(1,0,0);
builder.Vertex(0,0,0); // a red vertex
builder.Vertex(100,0,0); // this vertex will be red too
builder.Color(0,0,1);
builder.Vertex(100,100,0); // blue
[some data format I have not yet decided on] va = builder.GetVertexArray();
[ - " - ] ca = builder.GetColorArray();

Comments

Comment viewing options

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

You can take a look at glim: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Numb...
It tries to do similar thing in C++.

objarni's picture

Thanks!

triton's picture

OGRE engine also has a similar interface.

http://www.ogre3d.org/wiki/index.php/ManualObject

objarni's picture

OK I've written av 0.01 version of this, featuring double-arrays and vertices/colors only.

// MIT License
// Olof Bjarnason
using System.Collections.Generic;
namespace OBTKLib
{
    public class VABuilder
    {
        double red = 1, green = 1, blue = 1;
        List<double> vertices = new List<double>();
        List<double> colors = new List<double>();
 
        public double[] GetVertexArray()
        {
            return vertices.ToArray();
        }
 
        public void AddVertex(double x, double y, double z)
        {
            vertices.AddRange(new double[] { x, y, z });
            colors.AddRange(new double[] { red, green, blue });
        }
 
        public double[] GetColorArray()
        {
            return colors.ToArray();
        }
 
        public void SetColor(double red, double green, double blue)
        {
            this.red = red;
            this.green = green;
            this.blue = blue;
        }
    }
}

Some example code:

var builder = new VABuilder();
builder.SetColor(0.5, 0, 1); // TODO: add alpha and Color overloads
builder.AddVertex(0, 0, 0); // TODO: add vector3 overload
builder.AddVertex(100, 0, 0);
builder.SetColor(0, 0, 0); // TODO: maybe change to property instead of Set-method
builder.AddVertex(100,100,0);
double[] vertex_array = builder.GetVertexArray(); // TODO: add float/int/short overloads
double[] color_array = builder.GetColorArray(); // TODO: add float/byte overloads
objarni's picture

Which data format of vertex arrays do you guys use for best speed/quality compromise..? I would guess short ints are "good enough" quailtywise for smaller models, while being half the size of floats, and one forth the size of doubles! In theory they should be 4x faster right? Even more obvious for normals/colors/texcoords, they really do not need to be floats/doubles, no need for such high precision.

I'm thinking of making VABuilder have one "nice, comfy" mode (doubles) and one "fast, not so comfy" mode (short ints). Maybe even split into two separate builder. Generic type T to define what data format to use..? Don't know, since might want different formats for positions/colors/texcoords/normals.

Comments? I know "measure, measure, measure" is the "answer to everything" when it comes to performance, but what is your experience?

objarni's picture

.. and I just remembered VAs do not play nice with .NET! :(

http://www.opentk.com/node/296

Have to learn VBOs. Fortunately, this is well documentet in OpenTK! :)

the Fiddler's picture

Changing from VAs to VBOs means changing just two lines of code:

  • You call GL.BufferData() to upload the data, instead of keeping it in yourself.
  • You modify the last parameter of GL.Vertex/Normal/*Pointer()
    to be a 0-based offset inside a single vertex, instead of a pointer to the actual data.

That's all, actually. Bonus points if you go all the way and replace GL.Vertex/Normal/ColorPointer() with GL.VertexAttribPointer() and a simple vertex shader.

Sounds hairy at first, but the strength of the GL3 approach will become apparent once you actually implement it. True, there is an initial explosion in setup code (you need to generate objects, upload data, run a shader) but guess what: you only need to write the setup code once. The final result is both cleaner and faster than immediate mode.

Edit: once you actually go the VBO route, you'll see that there's little need for emulating immediate. Check this out:

struct Vertex { public Vector3 Position; public Color4 Color; }
 
var data = new List<Vertex>();
data.Add(new Vertex() { Position = { 0, 0, 0 }, Color = { 0, 1, 0, 0 } });
data.Add(new Vertex() { Position = { 1, 0, 0 }, Color = { 0, 1, 0, 0 } });
data.Add(new Vertex() { Position = { 1, 0, 1 }, Color = { 0, 1, 0, 0 } });
data.Add(new Vertex() { Position = { 0, 0, 1 }, Color = { 0, 1, 0, 0 } });
 
GL.BufferData(..., data.ToArray());

My abstraction looks similar to this:

// Setup code
var device = new GraphicsDevice(Context);
 
var sky_program = new ShaderProgram(device)
{
    new VertexShader(Resources.SkyVS),
    new FragmentShader(Resources.SkyFS)
};
shader.SetUniform("ProjectionMatrix", ref Camera.Projection);
shader.SetUniform("SunPosition", Sun.Position);
 
var sky_vertices = new VertexBuffer<VertexPositionTexture>(device);
model_vertices.SetData(...);
 
var sky_elements = new ElementBufferShort(device, ElementType.Triangle);
model_elements .SetData(...);
 
var sky_texture = new CompressedTexture2D(device, Resources.SkyTexture);
var cloud_texture = new CompressedTexture2D(device, Resources.CloudTexture);
 
// Render code
shader.SetUniform("ModelviewMatrix", ref Camera.Modelview);
device.Render(shader, sky_vertices, sky_elements, sky_texture, cloud_texture);
 
// Clean-up code
device.Dispose();
objarni's picture

Thanks, but shaders is too much right now. I'll be glad to get VBOs working ;)

the Fiddler's picture

Np.

I edited my post while you were posting, yet again. :)

objarni's picture

Yeah VBOs look nice and not that much harder than VAs. Conceptually, they are just VAs "owned" by GL right?