Login Register

Another optimization...

Hi Dojoers,

It seems optimization is my friend in this project with Dojo... This time I would like to share my idea about what I did (mainly optimization both design and implementation) for couple days. As remainder, I am doing the gfx library enhancement, where real time processing is needed hence a fast and robust implementation plays cruical part in here...

This idea is inspired from programming language called Haskell. This cute programming language is kind of late processing, where any calculation/procession will not be called unless it is needed for example, you say:

foo1::Int = 1 + 2; <- at this point, it is not calculated
foo2::Int = 3 + 4; <- not touched at all
foo3::Int = foo1; <- foo1 is calculated then put into here...

This feature snapped the idea and I applied it into two different areas in my library, in world transformation and view transformation optimization...

Let me explain the background first, note that in the 3d graphic environment (especially OpenGL) environment needs to be drawn whenever view state changes (for example camera view changed or object transformation is moved or a new object is created and put into scene)

Now lets see the old ways to draw/render the environment:

// Main rendering process.
draw: function(/*Scene*/ scene, /*RenderObject*/ list) {
    // Clear color and depth buffer either in client or server side.
    this._renderer.clear(this._renderer.COLOR_BUFFER_BIT | this._renderer.DEPTH_BUFFER_BIT);
    
    // set up our viewing parameters
    this._renderer.matrixMode(this._renderer.PROJECTION);
    this._renderer.loadIdentity();
    this._renderer.gluPerspective(45, 1, 0.1, 1000);

    this._renderer.matrixMode(this._renderer.MODELVIEW);
    this._renderer.loadIdentity();
    this._renderer.gluLookAt(1, 1, 10, 1, 1, 1, 0, 1, 0);
    
    // Draw the object
    // Apply world transformation
    this._renderer.translate(0, 1, 0);
    this._renderer.rotate(10, 0, 1, 0);
    this._renderer.scale(1, 1, 1);
    
    // Draw triangles
    this._renderer.drawElements(gl.TRIANGLES, indices.length, indices);
    
    // Show the processed buffer. Note this uses double buffering
    // technique. 
    this._renderer.swapBuffers();
}

Ah forgot to mention, OpenGL uses matrix for calculation structure such as translation, rotation or scaling... The implementations behind gluPerspective, gluLookAt, translate, rotate and scale are heavy duty multiplications and divisions (If you do not believe me, I could give you the design of the OpenGL implementation) and see that those functions are calculated everytime drawing process is initiated...

// set up our viewing parameters
this._renderer.matrixMode(this._renderer.PROJECTION);
this._renderer.loadIdentity();
this._renderer.gluPerspective(45, 1, 0.1, 1000);

this._renderer.matrixMode(this._renderer.MODELVIEW);
this._renderer.loadIdentity();
this._renderer.gluLookAt(1, 1, 10, 1, 1, 1, 0, 1, 0);

// Draw the object
// Apply world transformation
this._renderer.translate(0, 1, 0);
this._renderer.rotate(10, 0, 1, 0);
this._renderer.scale(1, 1, 1);

Would it be nice if there is a way to calculate it once and just copy the calculation result into OpenGL straight away as long as it is not changed... Luckyly, OpenGL support a way to do that (Phew!) So what I did is basically change this partition code into more complex algorithm...

this._renderer.matrixMode(this._renderer.MODELVIEW);
this._renderer.loadIdentity();
this._renderer.gluLookAt(1, 1, 10, 1, 1, 1, 0, 1, 0);

See that, whenever the view is changed then it is necessary to calculate (in function _calculate) it... Then the _execute function will load the calculated matrix by using loadMatrix (Thanks OpenGL!!!)

// Helper function to execute camera transformation. Firstly, it will check
// whether the camera is updated or not... If it is updated then calculate the
// matrix for synchronization.
apply: function() {
    if (this._isUpdated)
    {
        // Do the calculation.
        this._calculate();
        // Set back the status.
        this._isUpdated = false;
    }
    
    // Execute the code.
    this._execute();
},
    
// Execute specific transformation by given properties.
_execute: function() {
    this._renderer.matrixMode(this._renderer.MODELVIEW);
    this._renderer.loadMatrix(this._modelViewMatrix);
},
    
// Calculate transformation so that they become synchronized each other. This method is kind
// of pull data technique and it need to be implemented for each specific engine.
_calculate: function() {
    // Insane calculation as OpenGL specified...
},

This function is very effective and boosting the performance a lot, note that there are so many factors to change the environment state but it is kind of low chance to have all calculated everytime... so by using this design, it could save a lot of computation hence increasing performance a lot...

I would like to design next optimization which is event to control when the right time to render the environment of 3d graphic... Note that, I described about the view states that cause environment needs to be drawn... It would be nice if there is a way to draw the envornment whenever view state is changed than periodic drawing.

That is what I have been doing in couple weeks... Trying to set up high performance infrastructure for the gfx library... Of course, you guys may know better ways to do please put comment... I would really appreciate it... Even though just comments or suggestions.... Thanks!