Showing posts with label OpenGL-ES. Show all posts
Showing posts with label OpenGL-ES. Show all posts

Friday, January 29, 2010

OpenGL Transformation


Geometric data such as vertex positions and normal vectors are transformed via Vertex Operation andPrimitive Assembly operation in OpenGL pipeline before raterization process.
OpenGL vertex transformation
OpenGL vertex transformation

Object Coordinates

It is the local coordinate system of objects and is initial position and orientation of objects before any transform is applied. In order to transform objects, use glRotatef(), glTranslatef(), glScalef().

Eye Coordinates

It is yielded by multiplying GL_MODELVIEW matrix and object coordinates. Objects are transformed from object space to eye space using GL_MODELVIEW matrix in OpenGL. GL_MODELVIEWmatrix is a combination of Model and View matrices (Mview * Mmodel). Model transform is to convert from object space to world space. And, View transform is to convert from world space to eye space.
OpenGL eye coordinates
Note that there is no separate camera (view) matrix in OpenGL. Therefore, in order to simulate transforming the camera or view, the scene (3D objects and lights) must be transformed with the inverse of the view transformation. In other words, OpenGL defines that the camera is always located at (0, 0, 0) and facing to -Z axis in the eye space coordinates, and cannot be transformed. See more details of GL_MODELVIEW matrix in ModelView Matrix.
Normal vectors are also transformed from object coordinates to eye coordinates for lighting calculation. Note that normals are transformed in different way as vertices do. It is mutiplying the tranpose of the inverse of GL_MODELVIEW matrix by a normal vector. See more details in Normal Vector Transformation.
normal vector transformation

Clip Coordinates

It is after applying eye coordinates into GL_PROJECTION matrix. Objects are clipped out from the viewing volume (frustum). Frustum is used to determine how objects are projected onto screen (perspective or orthogonal) and which objects or portions of objects are clipped out of the final image. See more details of GL_PROJECTION matrix in Projection Matrix.
OpenGL clip coordinates

Normalized Device Coordinates (NDC)

It is yielded by dividing the clip coordinates by w. It is called perspective division. It is more like window (screen) coordinates, but has not been translated and scaled to screen pixels yet. The range of values is now normalized from -1 to 1 in all 3 axes.
OpenGL Normalized Device Coordinates

Window Coordinates (Screen Coordinates)

It is yielded by applying normalized device coordinates (NDC) to viewport transformation. The NDC are scaled and translated in order to fit into the rendering screen. The window coordinates finally are passed to the raterization process of OpenGL pipeline to become a fragment. glViewport()command is used to define the rectangle of the rendering area where the final image is mapped. And, glDepthRange() is used to determine the z value of the window coordinates. The window coordinates are computed with the given parameters of the above 2 functions;
glViewport(x, y, w, h);
glDepthRange(n, f);
OpenGL Window Coordinates
The viewport transform formula is simply acquired by the linear relationship between NDC and the window coordinates;


OpenGL Transformation Matrix
OpenGL Transform Matrix
OpenGL Transform Matrix
OpenGL uses 4 x 4 matrix for transformations. Notice that 16 elements in the matrix are stored as 1D array in column-major order. You need to transpose this matrix if you want to convert it to the standard convention, row-major format.
OpenGL has 4 different types of matrices; GL_MODELVIEW,GL_PROJECTIONGL_TEXTURE, and GL_COLOR. You can switch the current type by using glMatrixMode() in your code. For example, in order to select GL_MODELVIEW matrix, use glMatrixMode(GL_MODELVIEW).

Model-View Matrix (GL_MODELVIEW)

GL_MODELVIEW matrix combines viewing matrix and modeling matrix into one matrix. In order to transform the view (camera), you need to move whole scene with the inverse transformation.gluLookAt() is particularly used to set viewing transform.
Columns of OpenGL ModelView matrix
4 columns of GL_MODELVIEW matrix
The 3 matrix elements of the rightmost column (m12,m13m14) are for the translation transformation,glTranslatef(). The element m15 is the homogeneous coordinate. It is specially used for projective transformation.
3 elements sets, (m0m1m2), (m4m5m6) and (m8,m9m10) are for Euclidean and affine transformation, such as rotation glRotatef() or scaling glScalef(). Note that these 3 sets are actually representing 3 orthogonal axes;
  • (m0m1m2)   : +X axis, left vector, (1, 0, 0) by default
  • (m4m5m6)   : +Y axis, up vector, (0, 1, 0) by default
  • (m8m9m10) : +Z axis, forward vector, (0, 0, 1) by default
We can directly construct GL_MODELVIEW matrix from angles or lookat vector without using OpenGL transform functions. Here are some useful codes to build GL_MODELVIEW matrix:
  • Angles to Axes
  • Lookat to Axes
Note that OpenGL performs matrices multiplications in reverse order if multiple transforms are applied to a vertex. For example, If a vertex is transformed by MA first, and transformed by MBsecond, then OpenGL performs MB x MA first before multiplying the vertex. So, the last transform comes first and the first transform occurs last in your code.
// Note that the object will be translated first then rotated
glRotatef(angle, 1, 0, 0);   // rotate object angle degree around X-axis
glTranslatef(x, y, z);       // move object to (x, y, z)
drawObject();

Projection Matrix (GL_PROJECTION)

GL_PROJECTION matrix is used to define the frustum. This frustum determines which objects or portions of objects will be clipped out. Also, it determines how the 3D scene is projected onto the screen. (Please see more details how to construct the projection matrix.)
OpenGL provides 2 functions for GL_PROJECTION transformation. glFrustum() is to produce a perspective projection, and glOrtho() is to produce a orthographic (parallel) projection. Both functions require 6 parameters to specify 6 clipping planes; leftrightbottomtopnear and farplanes. 8 vertices of the viewing frustum are shown in the following image.
OpenGL Perspective Frustum
OpenGL Perspective Viewing Frustum
The vertices of the far (back) plane can be simply calculated by the ratio of similar triangles, for example, the left of the far plane is;
OpenGL Orthographic Frustum
OpenGL Orthographic Frustum
For orthographic projection, this ratio will be 1, so the leftright,bottom and top values of the far plane will be same as on the near plane.
You may also use gluPerspective() and gluOrtho2D() functions with less number of parameters. gluPerspective() requires only 4 parameters; vertical field of view (FOV), the aspect ratio of width to height and the distances to near and far clipping planes. The equivalent conversion from gluPerspective() to glFrustum() is described in the following code.
// This creates a symmetric frustum.
// It converts to 6 params (l, r, b, t, n, f) for glFrustum()
// from given 4 params (fovy, aspect, near, far)
void makeFrustum(double fovY, double aspectRatio, double front, double back)
{
    const double DEG2RAD = 3.14159265 / 180;

    double tangent = tan(fovY/2 * DEG2RAD);   // tangent of half fovY
    double height = front * tangent;          // half height of near plane
    double width = height * aspectRatio;      // half width of near plane

    // params: left, right, bottom, top, near, far
    glFrustum(-width, width, -height, height, front, back);
}

An example of an asymmetric frustum
However, you have to use glFrustum() directly if you need to create a non-symmetrical viewing volume. For example, if you want to render a wide scene into 2 adjoining screens, you can break down the frustum into 2 asymmetric frustums (left and right). Then, render the scene with each frustum.

Texture Matrix (GL_TEXTURE)

Texture coordinates (strq) are multiplied by GL_TEXTURE matrix before any texture mapping. By default it is the identity, so texture will be mapped to objects exactly where you assigned the texture coordinates. By modifying GL_TEXTURE, you can slide, rotate, stretch, and shrink the texture.
// rotate texture around X-axis
glMatrixMode(GL_TEXTURE);
glRotatef(angle, 1, 0, 0);

Color Matrix (GL_COLOR)

The color components (rgba) are multiplied by GL_COLOR matrix. It can be used for color space conversion and color component swaping. GL_COLOR matrix is not commonly used and is requiredGL_ARB_imaging extension.

Other Matrix Routines

glPushMatrix() : 
push the current matrix into the current matrix stack.
glPopMatrix() : 
pop the current matrix from the current matrix stack.
glLoadIdentity() : 
set the current matrix to the identity matrix.
glLoadMatrix{fd}(m) : 
replace the current matrix with the matrix m.
glLoadTransposeMatrix{fd}(m) : 
replace the current matrix with the row-major ordered matrix m.
glMultMatrix{fd}(m) : 
multiply the current matrix by the matrix m, and update the result to the current matrix.
glMultTransposeMatrix{fd}(m) : 
multiply the current matrix by the row-major ordered matrix m, and update the result to the current matrix.
glGetFloatv(GL_MODELVIEW_MATRIX, m) : 
return 16 values of GL_MODELVIEW matrix to m

Wednesday, January 27, 2010

Explaination of Win32 Project under VisualStudio

To create a new Win32 project

  1. On the File menu, click New, and then click Project....
  2. In the Project Types pane, select Win32 in the Visual C++ node, and then select Win32 Project in the Templates pane.
    Type a name for the project, such as win32app. You can accept the default location, type a location, or browse to a directory where you want to save the project.
  3. On the Win32 Application Wizard, select Next.
  4. On the Win32 Application Wizard, under Application type select Windows application. Under Additional options select Empty project. Leave the remaining options as they are. Click Finish to create the project.
  5. Add a C++ file to the project by selecting Add New Item... from the Project menu. In the Add New Item dialog box, select C++ File (.cpp). Type a name for the file, such as GT_HelloWorldWin32.cpp, and click Add.

To start a Win32 applications

  1. As you know, every C and C++ application must have a main function. This function is the starting point for the application. Similarly, in a Win32 application, every application must have a WinMain function. The syntax for WinMain is as follows:



    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow);
    
    For an explanation of the parameters and return value of this function, see WinMain Function.


  2. In addition to WinMain, each Win32 application must also have a second function which is usually called WndProc, which stands for window procedure. The syntax for WndProc is as follows:

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    The purpose of this function is to handle any messages that your application receives from the operating system. When does your application receive messages from the operating system? All the time! For example, imagine that we have created a dialog box that has an OK button. When the user clicks that button, the operating system sends our application a message, which lets us know that a user pressed this button. The WndProc function is responsible for responding to that event. In our example, the appropriate response might be to close the dialog box.
     
    EXTRA READ
      More Information on  Window Procedures

    • Window Procedures Every window has an associated window procedure — a function that processes all messages sent or posted to all windows of the class. All aspects of a window's appearance and behavior depend on the window procedure's response to these messages. 
    • Each window is a member of a particular window class. The window class determines the default window procedure that an individual window uses to process its messages.
       

To add functionality to WinMain

  1. First, create inside the WinMain function a window class structure of type WNDCLASSEX. This structure contains information about your window, such as the application's icon, the background color of the window, the name to display in the title bar, the name of the window procedure function, and so on. A typical WNDCLASSEX structure follows:



    WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
    For an explanation of the fields of this structure, see WNDCLASSEX.



  2. Now that you have created your window class, you must register it. Use the RegisterClassEx function, and pass the window class structure as an argument:



    if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    



  3. Now that you have registered your class, it is time to create a window. Use the CreateWindow function as follows:



    static TCHAR szWindowClass[] = _T("win32app");
    static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
    // The parameters to CreateWindow explained:
    // szWindowClass: the name of the application
    // szTitle: the text that appears in the title bar
    // WS_OVERLAPPEDWINDOW: the type of window to create
    // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
    // 500, 100: initial size (width, length)
    // NULL: the parent of this window
    // NULL: this application dows not have a menu bar
    // hInstance: the first parameter from WinMain
    // NULL: not used in this application
    HWND hWnd = CreateWindow(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        500, 100,
        NULL,
        NULL,
        hInstance,
        NULL
    );
    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Win32 Guided Tour"),
            NULL);
    
        return 1;
    }
    
    This function returns an HWND, which is a handle to a window. For more information, see Windows Data Types.



  4. Now that we have created the window, we can display it to the screen using the following code:



    // The parameters to ShowWindow explained:
    // hWnd: the value returned from CreateWindow
    // nCmdShow: the fourth parameter from WinMain
    ShowWindow(hWnd,
        nCmdShow);
    UpdateWindow(hWnd);
    
    So far, this window will not display much, because we have not yet implemented the WndProc function.



  5. The final step of WinMain is the message loop. The purpose of this loop is to listen for messages that the operating system sends. When the application receives a message, the message is dispatched to the WndProc function to handle it. The message loop resembles this:



    MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    
    For more information about the structures and functions that is used in the message loop, see MSG, GetMessage, TranslateMessage, and DispatchMessage.
    The steps that you have just completed are common to most Win32 applications. For include directives and global variable declarations required in this application,
    At this point, your WinMain function should resemble this:

    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL,
                _T("Call to RegisterClassEx failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        hInst = hInstance; // Store instance handle in our global variable
    
        // The parameters to CreateWindow explained:
        // szWindowClass: the name of the application
        // szTitle: the text that appears in the title bar
        // WS_OVERLAPPEDWINDOW: the type of window to create
        // CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
        // 500, 100: initial size (width, length)
        // NULL: the parent of this window
        // NULL: this application dows not have a menu bar
        // hInstance: the first parameter from WinMain
        // NULL: not used in this application
        HWND hWnd = CreateWindow(
            szWindowClass,
            szTitle,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            500, 100,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        if (!hWnd)
        {
            MessageBox(NULL,
                _T("Call to CreateWindow failed!"),
                _T("Win32 Guided Tour"),
                NULL);
    
            return 1;
        }
    
        // The parameters to ShowWindow explained:
        // hWnd: the value returned from CreateWindow
        // nCmdShow: the fourth parameter from WinMain
        ShowWindow(hWnd,
            nCmdShow);
        UpdateWindow(hWnd);
    
        // Main message loop:
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    


To add functionality to WndProc

  1. The purpose of the WndProc function is to handle messages that your application receives. You usually implement this by using a switch function.
    The first message we will handle is the WM_PAINT message. Your application receives this message when a portion of your application's window must be updated. When a window is first created, the whole window must be updated, and this message is passed to indicate this.
    The first thing that you should do when you handle a WM_PAINT message is call BeginPaint, and the last thing that you should do is call EndPaint. In between these two function calls you handle all the logic to lay out the text, buttons, and other controls for your window. For this application, we display the string "Hello, World!" inside the window. To display text, use the TextOut function, as shown here:

    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");
    
    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
    
        // Here your application is laid out.
        // For this introduction, we just print out "Hello, World!"
        // in the top left corner.
        TextOut(hdc,
            5, 5,
            greeting, _tcslen(greeting));
        // End application-specific layout section.
    
        EndPaint(hWnd, &ps);
        break;
    }
    



  2. Your application will typically handle many other messages, such as WM_CREATE and WM_DESTROY. A simple but complete WndProc function follows:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR greeting[] = _T("Hello, World!");
    
        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
    
            // Here your application is laid out.
            // For this introduction, we just print out "Hello, World!"
            // in the top left corner.
            TextOut(hdc,
                5, 5,
                greeting, _tcslen(greeting));
            // End application specific layout section.
    
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
            break;
        }
    
        return 0;
    }
    



Monday, December 7, 2009

New Release of Qt 4.6

NOKIA HAS UPDATED its Qt development framework to work on Symbian and include support for multi-touch and gestures as well boosting its graphics capabilities.

In addition to extending to Symbian, Qt 4.6 also adds Windows 7, Snow Leopard and the upcoming Maemo 6 to the list of supported platforms, although Maemo 5 support is still in the pipeline.

There's also the addition of a new graphics effects like opacity, drop shadows, glow and filtering and support for multi-touch and gestures to enable popular features like flicking and kinetic scrolling.

According to Nokia this all comes with even less of a performance hit thanks to an optimised Qt Graphicsview rendering algorithm and a new OpenGL paint engine.

Also thrown in is new WebKit support and 2D vector graphic support using OpenVG.

"Qt 4.6 marks an exciting time for developers, regardless of their target form factor or platform," said Sebastian Nyström, vice president of Application Services and Frameworks at Nokia.

"Developers can easily create visually appealing and web-connected applications for desktops or devices, including targeting the hundreds of millions of Symbian and Maemo-based devices."

Coinciding with launch of Qt 4.6 is the release of Qt Creator 1.3, the cross-platform Qt development IDE, which jointly form the Qt SDK.