RSS

Category Archives: C++

Light Scattering

Light Scattering

When we introduced Programmable Pipeline support to Vortex Engine, we claimed that better visual effects could now be introduced into the renderer. With the introduction of Render-to-Texture functionality into Vortex 2.0, coupled with the power of Shaders, we can now make good on our promise.

Light Scattering (also known as “God Rays”) is a prime example of what can be achieved with Shaders and Render-to-Texture capabilities.

In the following image, a room consisting of an art gallery with tall pillars is depicted. We want to convey the effect of sun light coming from outside, illuminating the inner nave. Enter Light Scattering:

A Light Scattering algorithm is used for improving the visual experience. The scene is rendered using Vortex 2.0. Room courtesy of RealityFrontier. (Click to Enlarge)

 

It can be seen in the picture above how the the effect, although subtle, brings more life to the rendered scene. There is still much room to improve the visual results, though, particularily with the results of Kenny Mitchel’s article on GPU Gems 3.

There is also room for optimization. Currently, the scene is rendered in realtime at an average of 187 frames per second, producing 1024×1024 images on a NVIDIA GeForce GTX465. Moving the algorithm to mobile devices, although easy from a coding perspective, might require extra work to achieve a high frame rate on the embedded GPU.

Here are three more captures from different angles.

(Click to Enlarge)

 

(Click to Enlarge)

(Click to Enlarge)

 

 
Leave a comment

Posted by on February 6, 2012 in C++, OpenGL, Vortex-Engine

 

Vortex adds Render-to-Texture capabilities

I’m very glad to announce Vortex now supports render-to-texture capabilities by means of Framebuffer Objects : )

Vortex Render-to-Texture support: a knight is rendered on a texture that is then mapped on a cube. All rendering is done on the GPU, avoiding expensive copies to RAM.

 
Leave a comment

Posted by on January 30, 2012 in C++, OpenGL, Vortex-Engine

 

Implementing sqrt

I was reading some post about interview questions of 2011 and came across one that stated “find the square root of a number”.

Assuming we can’t use the sqrtf function of the standard C math library, let’s see how we can calculate the square root of a number x.

Given n, we know that its square root is a number x that holds:

\sqrt{n} = x

Let’s work on this equation a little. Raise both sides to the second power:

n = x^2

Move to the left of the equality:

0 = x^2 - n

If we found the roots of this last equation somehow, we would have found the square root of n. We can do this by using the Newton-Raphson iteration.

The Newton-Raphson iteration states that we can find the root of an equation using the following formula iteratively:

x_{n+1} = x_n - \frac{f(x)}{f'(x)}

Where f’(x) is the derivative of function f(x). We will approximate the derivative using the definition of derivative at a point (we could also note that the derivative could be trivially calculated; this method is more general).

f'(x) = \frac{f(x+h) - f(x)}{h}

The error of the Newton-Raphson iteration is given by:

|x_{n+1} - x_n|

Starting with a hardcoded seed value, we will perform this iteration in a loop until the error is less than a given value. I have chosen to iterate until the error is less than 1×10^(-10): 0.00000000001.

Let us see what a tentative “pythonesque” pseudocode for this loop could be:

def sqrt(n):
    f = function(x*x - n)
    x = 1 # seed
    xant = 0
    do:
        f1 = (f.eval(x+h) - f.eval(x)) / h
        xant = x
        x = x - f.eval(x)/f1
    while abs(x - xant) > err;
    return x

Assuming we have a symbolic function type, that loop does not seem too difficult. In order to code this in C, since the equation is always the same, I will hardcode it as a plain function.

typedef double real; // change to float for single precision

real f(real x, real n)
{
    return x*x - n;
}

real sqrt(real n)
{
    real err = 0.00000000001f;
    real h = 0.01f;

    real x = 1.0f; // seed
    real xant = 0.0f;

    do
    {
        xant = x;
        real df = (f(x+h, n) - f(x, n))/h;
        x = x - f(x, n)/df;
    }
    while (abs(x - xant) > err);

    return x;
}

Here are the results of running our custom square root function, compared to the standard version provided with the C programming language:

[ale@syaoran sqrt]$ ./sqrt 1.0
Custom sqrt of: 1 = 1
libm sqrt of: 1 = 1

[ale@syaoran sqrt]$ ./sqrt 2.0
Custom sqrt of: 2 = 1.41421
libm sqrt of: 2 = 1.41421

[ale@syaoran sqrt]$ ./sqrt 4.0
Custom sqrt of: 4 = 2
libm sqrt of: 4 = 2

[ale@syaoran sqrt]$ ./sqrt 16.0
Custom sqrt of: 16 = 4
libm sqrt of: 16 = 4

[ale@syaoran sqrt]$ ./sqrt 32.0
Custom sqrt of: 32 = 5.65685
libm sqrt of: 32 = 5.65685

[ale@syaoran sqrt]$ ./sqrt 100.0
Custom sqrt of: 100 = 10
libm sqrt of: 100 = 10

[ale@syaoran sqrt]$ ./sqrt 1000000.0
Custom sqrt of: 1e+06 = 1000
libm sqrt of: 1e+06 = 1000
 
Leave a comment

Posted by on January 23, 2012 in C, C++, Math

 

A short detour along the way…

I wanted to improve the Stencil Shadow Volumes code a little bit and enable it for the Programmable Pipeline in Vortex, however, I had to take a small detour to fix an issue related to mobile device support.

It turns out that OpenGL ES, the 3D library that Vortex uses to render its graphics on mobile devices, does not support rendering indexed geometry for indices larger than 16 bits. Keep this in mind when developing for mobile devices such as the iPhone or iPad.

I can completely understand the reasoning behind this decision. 32-bit indices could be considered too much data to submit to the GPU in a mobile device. Furthermore, they are not strictly necessary, as they could be replaced (if needed) by splitting the geometry into two groups defined by 16-bit indices.

The solution I devised, which is now part of Vortex 2.0, is to allow the user to specify the data size for the indices when defining the geometry. This provides the flexibility to use 32, 16 or 8 bit indices. You can even have several geometric objects with different index sizes in a scene.

The advantage of leveraging this mechanism is that now it is very easy to fine-tune the number of bytes used for index representation for improving performance. For example, using 16-bit indices instead of 32-bit indices would make no difference for representing models composed of less than 65536 vertices, while requiring a copy of just half the number of bytes to the GPU.

In the extreme case of 8-bit indices we would be constrained to only 256 vertices, but we would be sending only one fourth of the data to the GPU.

This was mostly plumbing work, so no new picture this time. Stay tuned for more updates!

 
Leave a comment

Posted by on January 2, 2012 in C++, iOS, OpenGL, Vortex-Engine

 

Stencil Shadow Volumes

Stencil Shadow Volumes

I’ve built Stencil Shadow Volumes into the Vortex Engine.

Shadows are a very interesting feature to implement in an renderer, as they provide important visual cues that help depict the relationship between objects in a scene. Notice in the following image how the shadow tells our brains that the Knight is standing on the floor (as opposed to hovering over it).

A Knight, lit by a green light, casts a shadow on a tiled floor.

The implementation is at this point no more than a prototype and requires significant more testing, however, since the visual results are very appealing, I wanted to share some of the images.

I personally have a bias towards using Shadows Volumes instead of Shadow Maps; I think the former algoritm leaves out much of the guesswork that Shadow Maps require. Furthermore, Shadow Volumes are not subject to some of the limitations of Shadow Maps, such as the map’s resolution.

Another point for Shadow Volumes is the fact that they provide a natural way to implement “soft shadows”: shadows that are not completely black but rather transparent. The following image corresponds to the same scene but with two minor changes: the light has been changed to white and the floor texture is different. Notice how we can see the floor texture englobed in the Knight’s translucent shadow.

The same knight, lit by a white light this time, casts a soft shadow on an industrial floor. Notice the shadow "translucency".

I hope we can have Shadow Volumes available for both rendering pipelines as part of Vortex 2.0.

Edit: Thanks to Gabriel G. for noting the term “soft shadows” was being used incorrectly.

 
Leave a comment

Posted by on December 26, 2011 in C++, OpenGL, Vortex-Engine

 

An Angel with Generated Normals

An Angel with Generated Normals

Sometimes the 3D models we have to display provide no information other than vertex data for the triangles they define.

This might be enough to approximate the shape of the object, but having no normal data, we are severely limited if we want to apply realistic lighting on the object’s surface. Without lighting and textures, it’s very hard to depict the 3D shape of objects.

Angel without Normals

An Angel Model lit but with no Normal Data.

To help solve this problem, Vortex now provides a simple Normal generation algorithm that “deduces” smooth per-vertex normals from the geometric configuration of the 3D model. The results are nothing short of astonishing.

Angel with Generated Normals

The same Angel Model lit after Normal data was generated automatically by Vortex.

Normal generation does come at a cost, however. The 3D model depicted in the figures above is composed of 237,018 vertices shared among 474,048 triangles.

In order to produce smooth normals, the generation algorithm must study the triangle adjacency for every vertex and produce exactly one normal for every one.

On the machine the algorithm was developed, a Core 2 Duo @ 2.66 GHz with 4GB of RAM and for the Angel model, this process takes about 841.334 seconds, that is about 14 minutes!

The good news is that given a model, its Normals only need to be generated once. Once the application has the normal data, it can cache it and reuse it every time the model is to be added to a scene, avoiding the computation time altogether.

This gives the developer the opportunity to generate all Normal data offline and then having it attached to the model at runtime.

The Angel model was downloaded from: http://www.cc.gatech.edu/projects/large_models/angel.html

 
Leave a comment

Posted by on November 7, 2011 in C++, Vortex-Engine

 

Improving Vortex’s Smart Pointers

In out last post, we talked about the shift we are currently making in Vortex, moving towards reference-counted resource management.

In this context, one of the problems we mentioned was the fact that due to the fact that C++ does not provide out-of-the-box type covariance/contravariance like C#, we ended up with some rather uncomfortable constructs for dealing with polymorphic data types.

Now, one of the great features of C++ is that the language is super-extensible. You can literally change the way many things work in C++ and, it turns out that after some research and experimentation (and a little C++ magic too), we found a way to implement C# covariance/contravariance for our custom smart pointers!

The latest improvements enable the following features:

  1. Implicit casts from a smart pointer (to an instance) of a derived class to a smart pointer of a base class.
  2. Static casts from a smart pointer (to an instance) of a base class to a smart pointer of a derived class.
  3. Compile-time errors from attempting invalid casts.

The following code fragments illustrate these points. These are taken directly from out test suite, with minor adaptations to simplify readability.

Fragment #1: Implicit cast from derived instances to base class instances:

ref_ptr<TransformNode> xformNode(new TransformNode());
ref_ptr<Node> node = xformNode; // Valid: implicit cast

Fragment #2: Static cast from a base class instance to a derived class instance. Note we called our static cast operator “ptr_cast”.

ref_ptr<Node> node(new TransformNode()); // Storing as a "more general" pointer
ref_ptr<TransformNode> pxformNode = ptr_cast<TransformNode>(node); // Valid: explicit cast.

Fragment #3: Finally, the following code is invalid, and will trigger a compile-time error:

ref_ptr<SimpleSceneGraph> sg(new SimpleSceneGraph());
ref_ptr<Node> node = ptr_cast<Node>(sg); // Illegal conversion: types are not related

We are very happy with the result and are looking forward to continue migrating the Vortex codebase to our new smart pointers. Programming with Vortex just got a whole lot easier and safer.

 
Leave a comment

Posted by on October 25, 2011 in C++, Vortex-Engine

 

Towards Reference-Counted Resource Management in Vortex

Now that we have advanced support for a dual rendering pipeline in Vortex, we are now shifting our attention into a completely different topic. This time we are looking into overhauling the engine’s inner resource management.

To this purpose, we are conducting experiments shifting resource and scene management from raw pointers to smart pointers. The idea of using smart pointers is to enable each resource to be automatically deleted once it is no longer referenced by any component or object. This is not to be confused with Garbage Collection. The main difference consists in that smart pointers allow us to simplify memory management without sacrificing deterministic object destruction and without incurring into the memory and CPU overhead of having the Garbage Collector kicking in to rearrange the application’s Heap at any time.

So far, this has proven a very interesting experience. We’ve bumped with some unexpected issues along the way, but we’ve also run into a couple of nice surprises. Among the problems encountered, there’s the fact that since C++ does not support out-of-the-box covariance/contravariance (in the sense C# does), exposing the polymorphic behavior of the scene objects became a little more involved that what it used to be when using raw pointers.

On the bright side, using smart pointers dramatically improves some of the roughest edges of the API. Just to pick a simple example, let’s consider image lifecycle management. Without smart pointers, Texture creation from images in Vortex might look like this:

void loadTexture()
{
  Vortex::Image* pimg = Vortex::Image::loadFromFile("./resources/texture.png");

  // Create Texture from image data...

  // loadImageFromFile transfers pointer ownership,
  // we must therefore not forget to delete the image:
  delete pimg;
}

Using Vortex’s smart pointers, however, we can forget about the explicit delete operation:

void loadTexture()
{
  ref_ptr<Vortex::Image> pimg = Vortex::Image::loadFromFile("./resources/texture.png");

  // Create Texture from image data...

  // Image object ownership is now managed by the
  // smart pointer. The pointer releases the data
  // upon exiting this scope (unless the pointer is copied)
}

ref_ptr<T> is the typename we’ve given to our in-house smart pointer implementation. These allow us to easily cast inside type hierarchies as well as dropping into the raw pointer when needed, allowing us to dodge the performance tax in performance-critical code.

So far the results seem promising. We will continue experimenting moving the rest of the codebase to smart pointers and hopefully we will be able to include this along with the dual rendering pipeline in the very next version of Vortex: Vortex 2.0.

 
Leave a comment

Posted by on October 20, 2011 in C++, Vortex-Engine

 

Dual Pipeline support in Vortex Engine

Dual Pipeline support in Vortex Engine

Continuing with the news related to the Vortex Engine, I’m glad to announce that the next version of Vortex will come with two separate rendering pipelines: a fixed rendering pipeline and a programmable rendering pipeline that supports custom shader programs.


Comparison of the Rendering Pipelines available in Vortex Engine. The image on the left represents the Fixed Pipeline. The image on the right represents the Programmable Pipeline (click to enlarge).


Supporting two pipelines enables the developer to use the most appropriate rendering pathway for the target device’s capabilities.

Newer video cards for Desktop computers and the latest mobile devices can be programmed for though the programmable pipeline, whereas older devices (such as the original iPhone and the iPhone 3G) can still be supported through the fixed pipeline.

Anyone in the field of Graphics will be able to tell that the fixed pipeline will not be able to provide the exact same visual capabilities as the programmable pipeline, however, it should be less resource intensive and thus more suitable for some older devices.

The programmable pipeline, on the other hand, will allow Vortex applications to leverage the hottest techniques in Computer Graphics such as Bump Mapping, Specular Mapping, Blur and Depth of Field (among others), dramatically improving the visual detail.

This list provides, at a glance, the criteria for selecting the appropriate Vortex rendering pipeline depending on the target device:

  • OpenGL 1.1 / OpenGL ES 1.1 devices -> Use Vortex’s Fixed Pipeline
  • OpenGL >= 2.0 / OpenGL ES 2.0 devices -> Choose between Vortex’s Fixed Pipeline and Vortex’s Programmable Pipeline (recommended).

Needless to say, we’re very excited about the possibilities that this brings to the table and are very eager to see to what extents can the Vortex Engine be now pushed.

In the picture above you can see a sample comparison between the lightning model of the fixed pipeline (hardware-accelerated Gouraud Shading) and the one that the programmable pipeline offers (hardware-accelerated Phong Shading with specular reflections in this case).

This is just the tip of the iceberg. Stay tuned for more updates on the Vortex Engine!

 
Leave a comment

Posted by on October 14, 2011 in C++, Vortex-Engine

 

Md2 Models and Vortex Scene Graphs

Md2 Models and Vortex Scene Graphs

Someone once said there is no building the engine without building a game. There is nothing like actually using your own tools in order to pinpoint the weak spots of the Engine.

Perilith Knight with the "knight skin".

Using Vortex to build different 3D applications, I’ve noticed that it may, at times, be a bit more verbose than one would expect from an Object Oriented C++ API.

One of the roughest edges in Vortex was Md2 model animation support. Until last week, integrating animated models into a Scene Graph was unnecessarily complicated. Fortunately, this is no longer the case. Adding an animated Md2 model to a Scene Graph is now as easy as adding any other node type.

Controlling animations and skins of Md2 Models programatically is now a breeze in Vortex.

Here are some captures from the famous Perilith Knight model. I may upload a YouTube video showing the smooth animation at some point.

 

Perilith Knight using the "evil skin".

Perilith Knight using the "ctf_r skin".

Stay tuned for more updates on the Vortex Engine!

 
Leave a comment

Posted by on October 3, 2011 in C++, Vortex-Engine