Rendering Large Images

Introduction

In today graphics, a lot of images need big resolutions. In fact, resolutions can be so high that you can’t even think about rendering them in a single video buffer. You may also need to render parts of a same image onto different displays. HOOPS Luminate provides an easy way to split an image calculation in buckets of pixels that can be later reassembled into the whole image: the asymmetric camera (see Viewpoints).

Description

In this tutorial, we’ll render a large images made of 16 buckets of pixels using HOOPS Luminate asymmetric cameras. As usual, we start by setuping a simple scene: a collection of coloured boxes lit by a single spotlight.

Then, the rendering is split into 16 passes. Each pass renders 1/16th of the whole image using an asymmetric camera.

../../../_images/wf_RenderingLargeImages_buckets.jpg

The subdivision in buckets used to render the whole image.

The rendering then consists of a 4x4 loop:

// Computes the 16 image chunks.
for( int y = 0; y < 4; ++y )
{
    for( int x = 0; x < 4; ++x )
    {
        while( ( RFK::TutorialApplication::GetTime() - last_time ) < 1000.0f ) {}
        last_time = RFK::TutorialApplication::GetTime();

        float tfov = tanf( fov );
        float tfovleft = tfov - x * 2.f * tfov / 4.f;
        float tfovright = -tfov + ( x + 1 ) * 2.f * tfov / 4.f;

        float tfovbottom = ratio * ( tfov - ( 3 - y ) * 2.f * tfov / 4.f );
        float tfovtop = ratio * ( -tfov + ( 4 - y ) * 2.f * tfov / 4.f );

        RC_TEST( iviewpoint->SetAsymmetricFrustumPerspective( atanf( tfovleft ), atanf( tfovright ),
                                                            atanf( tfovbottom ), atanf( tfovtop ),
                                                            iresmgr->GetState() ) );

        RFK::TutorialApplication::UpdateProgressBar( ( x + y * 4 + 1 ) / 16.f );
        RC_TEST( RFK::TutorialApplication::Invalidate() );

        // Blits the chunk pixels into the output image.
        RC_TEST( iimg2d->GetPixels() );
        unsigned char* pixels = iimg2d->GetLocalPixels();

        unsigned char* dst = output + 4 * ( ( 3 - y ) * h * ww + x * w );
        unsigned char* src = pixels;
        for( int line = 0; line < h; ++line )
        {
        memcpy( dst, src, 4 * w );
        dst += 4 * ww;
        src += 4 * w;
        }
    }
}

For each new bucket to render, the corresponding asymmetric camera is setup. After the bucket rendering, the rendered pixels are get back using a RED render image (see RED::IImage2D::SetRenderImage) and immediately blit into the final hi-res image.

Finally, the hi-res image is saved to the disk using the RED::ImageTools API.