SDL Application‎ > ‎

Exp.5 3D Stereogram


This kind of images are quite amazing , since you won't be able to see the real pattern at first sight.
Nowadays , the merchandises of 3D concept  are very popular , such as 3D LCD TV , 3D Movies ,
and Nintendo 3DS.
Although I don't like them since all of them will just wear out people's eyes , however I would like
to know how do they did that amazing 3D effects.

Actually , the principle behinds this is quite simple : Let left eye see the left sight and right eye
see the right one.     Nothing more.

Those amazing 3D Stereogram were made by computer program.    If you wanna make your
own stereogram program , then check this out.



 /*
    An Example Of 3D Stereogram
    About this program:
      1. The pattern of 3d Stereogram be defined in "Raw3D.txt"
      2. Do not change the pattern format in "Raw3D.txt"
      3. The background pattern copies from "bgpic.gif" which can be replaced by yours
      4. The baseWidth value can be controlled by arrow keys
      5. The pattern with depth 6 will move back and forth.

    by bdragon 2011.July
*/
#include "SDL.h"
#include "tools.h"

class _3D_Image {
public:
    bool bReDraw;
    int baseWidth;
    unsigned short maxWidth , maxHeight , maxDepth;
    unsigned short leftEye[640] , rightEye[640];
    short left , right , checkNo;

    short tempValue , tempMark ,tempDir;
    unsigned char rawData[15][20];
    SDL_Surface *bgPic;
    SDL_Rect bgPicRect , srcRect , dstRect , txtRect;
    _3D_Image();
};

This part declares the components that I need for 3D Stereogram.
The most critical components are in bold and red color.



 void fnDrawScreen(SDL_Surface * screen , _3D_Image & i3d ) {

    for(int i=0 ; i<2000 ; i++) {
        i3d.bgPicRect.x = rand()%660-20 ;
        i3d.bgPicRect.y = rand()%500-20 ;
        SDL_BlitSurface( i3d.bgPic , NULL , screen , &i3d.bgPicRect );
    }
    i3d.tempMark=1;
    for(int j=0 ; j<i3d.maxHeight ; j+=32) {
        for(int i=0 ; i<i3d.maxWidth ; i++) {
            i3d.leftEye[i] = i3d.checkNo;
            i3d.rightEye[i] = i3d.checkNo;
            if( i + i3d.baseWidth < i3d.maxWidth ) i3d.leftEye[i] = i + i3d.baseWidth;
            if( i >= i3d.baseWidth ) i3d.rightEye[i] = i - i3d.baseWidth;
        }
        for(int k=0 ; k<=i3d.maxDepth ; k++) {
            for(int i=0 ; i<i3d.maxWidth ; i++) {
                i3d.left  = i - i3d.baseWidth/2 + k;
                i3d.right = i + i3d.baseWidth/2 - k;
                if( i3d.rawData[j/32][i/32] - 48 == k && i3d.left >= 0 && i3d.right < i3d.maxWidth ) {
                    if(k==6) {
                        if(i3d.tempMark) {
                            if( i3d.tempDir) i3d.tempValue-=1;
                            if(!i3d.tempDir) i3d.tempValue+=1;
                            if(i3d.tempValue<-10) i3d.tempDir=0;
                            if(i3d.tempValue> 10) i3d.tempDir=1;
                            i3d.tempMark=0;
                        }
                        if(i3d.left-3<i3d.maxWidth) i3d.left+=i3d.tempValue;
                        if(i3d.right-3>0) i3d.right -= i3d.tempValue;
                    }
                    if(i3d.leftEye[i3d.left] != i3d.checkNo) i3d.rightEye[i3d.leftEye[i3d.left]] = i3d.checkNo;
                    i3d.leftEye[i3d.left] = i3d.right;
                    if(i3d.rightEye[i3d.right] != i3d.checkNo) i3d.leftEye[i3d.rightEye[i3d.right]] = i3d.checkNo;
                    i3d.rightEye[i3d.right] = i3d.left;

                }
            }
        } // for(int k=0 ; k<i3d.maxDepth ; k++) { END
        for(int i=0 ; i<i3d.maxWidth ; i++) {
            if(i3d.leftEye[i] != i3d.checkNo) {
                i3d.srcRect.x = i;
                i3d.srcRect.y = j;
                i3d.srcRect.w = 1;
                i3d.srcRect.h = 32;
                i3d.dstRect.x = i3d.leftEye[i];
                if( i3d.dstRect.x > 638 ) i3d.dstRect.x = 638 ;
                i3d.dstRect.y = j;
                i3d.dstRect.w = 1;
                i3d.dstRect.h = 32;
                SDL_BlitSurface( screen , &i3d.srcRect , screen , &i3d.dstRect );
            }
        }
    } // for(int j=0 ; j<i3d.maxHeight ; j+=32) { END
    SDL_Flip(screen);
} // void fnDrawScreen() { END

The core part of this program.   
This program will load the data into rawData[15][20] by read a txt file "Raw3D.txt".
You can modify the data in Raw3D.txt to get the 3D Pattern that you want.    And its format should be (y,x)=(15,20).
Since the screen width x height = 640 x 480
So 640 / 20 = 480 / 15 = 32

k==6 means , when it processes 3D Depth=6 , I will let the program perform a special task.
I wanna some patten with 3D Depth=6 to go back and forth.
So , when you run the program , you should see the number "3" go back and forth by time.

The blue one says , if the dot be occupied by someone else , then release it first before set the value.


 int main(int argc, char *argv[]) {

    // SDL System Initialize
    SDL_Event event;
    SDL_Surface *screen;
    atexit(SDL_Quit);
    if( SDL_Init(SDL_INIT_VIDEO) < 0 ) exit(1);
    SDL_WM_SetCaption("Example 3D Stereogram 2011 by bdragon", NULL);
    screen = SDL_SetVideoMode( 640 , 480 , 32 , SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_ANYFORMAT);
    _3D_Image i3d;

    TTF_Init(); // Initilize SDL_ttf
    fontA12 = TTF_OpenFont("arial.ttf",12); // Open a font & set the font size
   
    fnDrawScreen(screen , i3d);

    bool bRun = 1;

    while(bRun) {
        fnDrawScreen(screen , i3d);
        SDL_Delay( 100 );
        while( SDL_PollEvent( &event ) ){
            switch( event.type ){
                case SDL_KEYDOWN:
                    switch( event.key.keysym.sym ){
                        case SDLK_UP:
                            i3d.baseWidth+=2;
                            break;
                        case SDLK_DOWN:
                            i3d.baseWidth-=2;
                            break;
                        case SDLK_LEFT:
                            i3d.baseWidth-=2;
                            break;
                        case SDLK_RIGHT:
                            i3d.baseWidth+=2;
                            break;
                        case SDLK_ESCAPE:
                            bRun = 0 ;
                            break;
                        default:
                            break;
                        } // switch( event.key.keysym.sym ){ END
                break; // case SDL_KEYDOWN: END
                case SDL_QUIT: // Close Window Event
                    bRun = 0;
                break;
                default:
                    break;
            } // switch( event.type ){ END
        } // while( SDLK_PollEvent( &event ) ){ END
    }; // while(bRun) { END

return 0;
}
The main program flow.
Since the depth of object in the 3D Stereogram is controlled by baseWidth , so I let it be able to be controlled by
arrow key.    So the user can change the depth by adjust the baseWidth.     This function is just like the one on
Nitendo 3DS , the user can adjust the vision depth manually.


By the way , these 3D Images can hurt people's eyes seriously , just be careful don't play with them too long time.



Copyright © 2009 bdragon All rights reserved.
bdragong@gmail.com
ċ
Bdragon Ho,
Aug 2, 2011, 8:42 PM
Comments