2012年7月18日 星期三

opengles with iphone using color coding for picking object

正常來說在opengl是需要有兩的frame buffer
然後把color的資訊放在back buffer,不要swap過去,
如此user就不會看到。

但是在iphone上使用glkview我卻一直做不出來
原本想要用
http://mickyd.wordpress.com/2012/05/20/creating-render-to-texture-secondary-framebuffer-objects-on-ios-using-opengl-es-2/

glGenFramebuffers
glBindFramebuffer



來達成效果,但是卻始終不成功。

之後便改用
http://stackoverflow.com/questions/7861316/ios-5-glkview-how-to-access-pixel-rgb-data-for-colour-based-vertex-picking

只是我在draw in rect多加一個flag,只有在要snapshot的時候,才畫出color,
結果終於成功......


有用的參考資料:
http://stackoverflow.com/questions/9746602/getting-default-frame-buffer-id-from-glkview-glkit
http://stackoverflow.com/questions/6774197/opengl-es-2-0-object-picking-on-ios
http://stackoverflow.com/questions/7861316/ios-5-glkview-how-to-access-pixel-rgb-data-for-colour-based-vertex-picking
http://mickyd.wordpress.com/2012/05/20/creating-render-to-texture-secondary-framebuffer-objects-on-ios-using-opengl-es-2/
http://developer.apple.com/library/ios/#documentation/GLkit/Reference/GLKView_ClassReference/Reference/Reference.html
http://stackoverflow.com/questions/10958081/ios-render-to-and-read-from-depthbuffer-for-offscreen-processing

glDepthFunc


from:
http://blog.csdn.net/shuaihj/article/details/7230780

OpenGL函数思考-glDepthFunc

函数原型:

       void glDepthFunc(GLenum func)

参数说明:

      func:指定“目标像素与当前像素在z方向上值大小比较”的函数,符合该函数关系的目标像素才进行绘制,否则对目标像素不予绘制。可取以下值:

      GL_NEVER:永不绘制
      GL_LESS:如果目标像素z值<当前像素z值,则绘制目标像素
      GL_EQUAL:如果目标像素z值=当前像素z值,则绘制目标像素
      GL_LEQUAL:如果目标像素z值<=当前像素z值,则绘制目标像素
      GL_GREATER :如果目标像素z值>当前像素z值,则绘制目标像素
      GL_NOTEQUAL:如果目标像素z值<>当前像素z值,则绘制目标像素
      GL_GEQUAL:如果目标像素z值>=当前像素z值,则绘制目标像素\
      GL_ALWAYS:总是绘制
函数说明:

       通过目标像素与当前像素在z方向上值大小的比较是否满足参数指定的条件,来决定在深度(z方向)上是否绘制该目标像素。该函数只有启用“深度测试”时才有效,参考glEnable(GL_DEPTH_TEST)和glDisable(GL_DEPTH_TEST)

2012年7月17日 星期二

Picking Tutorial

from:http://www.lighthouse3d.com/opengl/picking/index.php?color1


Color Coding


The Red Book describes an interesting approach to picking based on color coding. This is a very simple approach that can be used instead of using the OpenGL API described in the previous sections.
The color coding scheme does not require any perspective changes and therefore it is simpler in theory. Just define a rendering function where the relevant objects (pickable and occluders) are assigned each a different color. When the user clicks the mouse over the scene, render the scene on the back buffer, read back the selected pixel from the back buffer and check its color. The process is completely transparent to the user because the buffers are not swapped, so the color coding rendering is never seen.
For instance, consider the following scene with 4 snowmen. What you're seeing is the result of the normal rendering function.

The next figure shows the result produced in the back buffer by the color coding rendering function. As you can see each snowman has a different color.

The required steps when the mouse is clicked are:
  • 1. Call the color coding rendering function
  • 2. Read the pixel where the mouse was clicked from the back buffer
  • 3. Process the color information to find out which item was clicked
  • 4. Do NOT swap buffers, otherwise the user will see the color coding
  • Bellow the normal rendering function is presented. It contains the code to render both the ground as well as the snowmen (contained in thedisplay list). 


        
    void draw() {
    
    // Draw ground
    	glColor3f(0.9f, 0.9f, 0.9f);
    	glBegin(GL_QUADS);
    		glVertex3f(-100.0f, 0.0f, -100.0f);
    		glVertex3f(-100.0f, 0.0f,  100.0f);
    		glVertex3f( 100.0f, 0.0f,  100.0f);
    		glVertex3f( 100.0f, 0.0f, -100.0f);
    	glEnd();
    
    // Draw 4 Snowmen
    
    	glColor3f(1.0f, 1.0f, 1.0f);
    
    	for(int i = 0; i < 2; i++)
    		for(int j = 0; j < 2; j++) {
    			glPushMatrix();
    			glTranslatef(i*3.0,0,-j * 3.0);
    			glColor3f(1.0f, 1.0f, 1.0f);
    			glCallList(snowman_display_list);
    			glPopMatrix();
    		}
    
    }
    
    


    The following function is for color coding rendering. As you can see the ground was left out since it is neither a pickable object, nor an occluding one. Also the code for the snowmen was altered 


        
    void drawPickingMode() {
    
    // Draw 4 SnowMen
    
    
    	glDisable(GL_DITHER);
    	for(int i = 0; i < 2; i++)
               for(int j = 0; j < 2; j++) {
    	 	glPushMatrix();
    		
    // A different color for each snowman
    
    		switch (i*2+j) {	
    			case 0: glColor3ub(255,0,0);break;
    			case 1: glColor3ub(0,255,0);break;
    			case 2: glColor3ub(0,0,255);break;
    			case 3: glColor3ub(250,0,250);break;
    		}
    
    		glTranslatef(i*3.0,0,-j * 3.0);
    		glCallList(snowman_display_list);
    		glPopMatrix();
    	   }
    	glEnable(GL_DITHER);
    }
    

    Cheking the Color

    Checking the color of the pixel where the mouse was clicked involves reading that same pixel from the back buffer. This can be accomplished using the following function: 
    void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);  Parameters:
    x,y : the bottom left corner
    width, length: the size of the area to be read
    format: The type of data to be read. In here it is assumed to GL_RGB.
    type: the data type of the elements of the pixel. In here we'll use GL_UNSIGNED_BYTE.
    pixels: An array where the pixels will be stored. This is the result of the function

    Both format and type have a lot of other possibilities, check the Red or Blue books for more information.
    Just as when using the OpenGL API it is necessary to invert the y coordinate. Reading the viewport information is therefore also required when using this approach. After getting the viewport info, it is possible to call glReadPixels as shown in the code bellow. The x and y parameters represent the cursor position. Width and height are both set to one since only a single pixel is being read. Afterwards it is just a matter of checking the values of the pixel. 
        
    void processPick ()
    {
    	GLint viewport[4];
    	GLubyte pixel[3];
    
    	glGetIntegerv(GL_VIEWPORT,viewport);
    
    	glReadPixels(cursorX,viewport[3]-cursorY,1,1,
    		GL_RGB,GL_UNSIGNED_BYTE,(void *)pixel);
    
    	printf("%d %d %d\n",pixel[0],pixel[1],pixel[2]);
    	if (pixel[0] == 255)
    	  printf ("You picked the 1st snowman on the 1st row");
    	else if (pixel[1] == 255)
    	  printf ("You picked the 1st snowman on the 2nd row");
    	else if (pixel[2] == 255)
    	  printf ("You picked the 2nd snowman on the 1st row");
    	else if (pixel[0] == 250)
    	  printf ("You picked the 2nd snowman on the 2nd row");
       	else
    	   printf("You didn't click a snowman!");
      printf ("\n");
       
    }
    
    

    To get this approach running without problems there are a few things that you should be aware. First set your colors using unsigned bytes as opposed to floats. When in RGB mode there are only 256 possible values for each component, so when you set a color using floats OpenGL will pick the nearest color possible. Secondly make sure your monitor is set to True Color. Otherwise the color presented on screen is only an approximation to the required color and therefore when reading back the pixels there is a possibility that the values wont match with the set values. Finally make sure you disable dithering, lighting and texturing for the color coded rendering function, since any of these operations may change the original color.
    If you really want to work with floats to set the color, or you can't guarantee that the monitor will be set to True Color then you can always to a test to check what the specified colors will look like when rendered.
    This approach requires that before your application starts you must render blocks of the requested colors and read them back using glReadPixelsto get the real rendered colors. Store those colors in an array and use them instead of the colors you specified when rendering.
    Be careful when choosing the colors though. If the values for each component are not set sufficiently apart then the may turn out to be the same color when rendered. For instance when setting the red component to 250, using unsigned bytes, with the monitor set to High Color instead of True Color, you actually get a red component of 255. This is because there are less possible values for each component when using only 16 bits to specify a color instead of 32 or 24. Check out the pixel packing values in the Red Book to find out about the possible combinations of bits for each component with 16 bits.

    2012年7月7日 星期六

    opengl(3)


    GL_REPLACE(使用测试条件中的设定值来代替当前模板值),
    GL_INCR(增加1,但如果已经是最大值,则保持不变),
    GL_INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始),
    GL_DECR(减少1,但如果已经是零,则保持不变),
    GL_DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值),
    GL_INVERT(按位取反)。



    // All drawing commands fail the stencil test, and are not
    // drawn, but increment the value in the stencil buffer. 
    //這個例子中,在畫的時候才會去比較stencil buffer,才會增加
    glStencilFunc(GL_NEVER, 0x0, 0x0);
    glStencilOp(GL_INCR, GL_INCR, GL_INCR);



    // Spiral pattern will create stencil pattern 
    // Draw the spiral pattern with white lines. We 
    // make the lines white to demonstrate that the
    // stencil function prevents them from being drawn
    glColor3f(1.0f, 1.0f, 1.0f); 
    glBegin(GL_LINE_STRIP);
    for(dAngle = 0; dAngle < 400.0; dAngle += 0.1){
    glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle)); 
    //畫的時候比較stencil buffer,依上面所設always fail加一,所以最後變成所有畫線的部份是一
    dRadius *= 1.002;
    }

    glEnd();





    2012年7月4日 星期三

    opengl(2)

    glRotatef(要旋轉幾度, x, y, z) -> x,y,z代表一個要選轉方向的向量,因此[0,1,1]&[0,2,2]是一樣的。

    2011年9月3日 星期六

    linux

    htons - Converts an unsigned short (16-bit) integer from host byte order to network byte order
    Big-endian和Little endian byte order。不同的處理器選擇了不同的byter order,也就是host byte order。但在異構網絡環境裡,這樣無法通信,因此必須採用統一的byte order,這就是network byte order。TCP/IP選用的是big-endian。


    FROM INTERNET

    http://libai.math.ncu.edu.tw/bcc16/pool/1.33.shtml
    用 C 語言窺探記憶體

    C 語言可以說是『最低階的高階語言』,它提供許多語法讓人有機會窺探電腦的具體狀況。以下提供程式原始碼,和作者寫此文件當時的執行狀況。這裡不是 C 語言教材,所以不說明 C 的語法,只是用它來示範。這些程式都是標準的 ANSI C 原始碼,可以用任何 C 編譯器製造可執行檔,在讀者自己的機器上做實驗。

    以下程式顯示三個變數 c, n 和 str 被配給的記憶體位址。

    /* Program A */
    #include <stdio.h>
    main() {
        int c, n;
        char str[12];
        printf("c is at %u\n", &amp;c);
        printf("n is at %u\n", &amp;n);
        printf("str is at %u\n", &amp;str);
    }

    在不同電腦上,甚至於在不同時間,執行這個程式,獲得的數據應當不同。我的手邊有兩部電腦可以用,一部的 CPU 是 Intel Pentium 並以 Linux 為作業系統(主機名是李白),另一部的 CPU 是 Sun UltraSparc 並以 Solaris 為作業系統 (主機名是王維),兩者都屬於 Unix 作業系統。以後,稱前者為 Intel,稱後者為 Sun。 Program A 的執行結果為

    Intel    Sun
    c is at 3221223228
    n is at 3221223224
    str is at 3221223200     c is at 4026530332
    n is at 4026530328
    str is at 4026530264

    不論 Intel 還是 PC,都看到:先宣告的變數,位址在後面。這就是 data segment 『從後面』排起的效果。以 Intel 為例,而且為了方便我們只寫記憶體位址的後三碼:

        c 配給的記憶體是 228, 229, 230, 231 共 4 bytes
        n 配給的記憶體是 224, 225, 226, 227 共 4 bytes
        str 配給的記憶體是 200, 201, 202, ..., 211 共 12 bytes

    現在可以補充兩件書本上沒有仔細說明的現象。

    第一,雖然 str[12] 需要存放 12 個 char 型態的數值,而每個 char 的資料含量是 1 byte,所以總共需要 12 bytes,但是 202..223 卻沒有用到,看來 Intel 浪費了 12 bytes。觀察 Sun,更過份,我們只要 12 bytes,但是電腦卻配給了 64 bytes。看來 Sun 浪費了 52 bytes。這種現象是因為電腦為了傳輸的效率,其實並非一次拿一個 byte 到 CPU 的 register 裡面,而是一次拿一個『存取字元』,稱為 word。而每個 word 通常是 2 bytes 或 4 bytes 或 8 bytes。因此,為了配合電路的設計以提昇效率,硬體設計者會選擇浪費一些記憶體空間。實際狀況如何,已經超出計概範圍,只是要讓讀者知道,在如今大型 CPU 上面寫程式,並不需要刻意節省記憶體。

    第二,讀者或許發現,似乎在同一部電腦上,甚至同一款作業系統與 CPU 的電腦上,怎麼每次執行 Program A 的結果都一樣?難道每次執行時,空閒記憶體的位址都一樣嗎?這也未免太巧了吧?其實這是因為現在的作業系統都是多人多工的系統,因此,像 Unix 這樣的系統,會分給每一個『同時』執行中的程式一個「虛擬」 (logical) 記憶體,使得每個程式都「感覺」自己是電腦中唯一的程式。這種「抽象」設計其實化簡了整個電腦的管理,只有真正的作業系統知道現在一共有幾個程式在執行,每個執行中的程式分給一個『執行元件』(process),一個 process 就好像一部完整的電腦:有自己的 CPU 和記憶體和周邊設備。而由作業系統分配各 process 實際分配到的 CPU 時間和記憶體空間。因此,前面看到的記憶體位址,其實是 process 內的虛擬位址,而不是硬體上的實際位址。


    /* Program C */
    #include <stdio.h>
    #define MB 1048576
    #define MAX 4096
    main() {
        int n=0;
        double *P[MAX];
        while (n &lt; MAX) {
            P[n] = (double*) malloc(MB);
            if (P[n] != NULL)
                printf("I got %4dMB of memory\n", ++n);
            else {
                fprintf(stderr, "Out of Memory\n");
                break;
            }
        }
    }

    以下是作者剛才執行的結果。這種結果並不表示 Sun 的功能比 Intel 差勁,實在是因為我們的『李白』安裝了比『王維』多得多的記憶體之故。 Program C 的執行結果如下 (... 是作者修改的,以免印出太多不重要的資料)。

    Intel    Sun

    ...
    I got 2930MB of memory
    I got 2931MB of memory
    I got 2932MB of memory
    Out of Memory

       

    ...
    I got   69MB of memory
    I got   70MB of memory
    I got   71MB of memory
    Out of Memory

    請注意 C 語言會知道作業系統已經沒有記憶體可以給了,但是 C 語言並不會自動輸出任何錯誤訊息。那一句 Out of Memory 是我們自己寫在程式裡面的錯誤訊息。

    Program E 的目的是實驗,如果程式想要將數值存進不容許這個 process 使用的記憶體,會發生 Segmentation Fault 訊息。

    /* Program E */
    #include <stdio.h>
    main() {
        char str[12];
        int n=0;
        printf("I claimed for 12 bytes of memory, but I try to assign "
            "str[n] for n=0...\n");
        while (1) {
            str[n]=0;
            printf("%5d", n++);
            if (!(n%16))
                putchar('\n');
        }
    }


    Program E 只宣告了 12 個字元給 str 序列,用來儲存 1-byte 整數資料。但是它卻無止境地指派數值 0 給 str[0], str[1], str[2], str[3], ...。 C 語言不會檢查其實 str[12] 已經超過 CPU 配給的範圍。但是程式也不一定立刻就會出錯。它可以一直執行到超出記憶體容許範圍,然後才會出錯。以下是執行 Program E 的結果 (... 是作者修改的,以免印出太多不重要的資料)。

    Intel    Sun

    ...
    2208 ... 2219 2220 2221 2222 2223
    2224 ... 2235 2236 2237 2238 2239
    2240 ... 2251 2252 2253 2254 2255
    Segmentation fault

       

    ...
    1520 ... 1531 1532 1533 1534 1535
    1536 ... 1547 1548 1549 1550 1551
    1552 ... 1563 1564 1565 1566 1567
    Segmentation fault

    雖然 Intel 比 Sun 多跑了一陣子,但是都跑不遠。在這個例子裡面,Segmentation fault 不是我們自己寫的錯誤訊息,是作業系統告訴我們的。

    現在我們試探電腦的記憶體設計屬於 Big-Endian 還是 Little-Endian。

    如果令 n 是 int 型態的變數,令 n 的值為 2562 + 2*256 + 3,則它的位元排列是

        00000000000000010000001000000011

    將這 32 bits 每 8 bits 組成一個 byte,共應分成四個字元:

        00000000 和 00000001 和 00000010 和 00000011

    若以無號整數解讀,這四個字元的值應該是

        0 和 1 和 2 和 3

    CPU 一定會配給連續四個記憶體給 n,但是這四個記憶體,卻有兩種放置四個 byte 的可能順序。如果我們一律按照記憶體位址從小到大的順序來講,則四個記憶體放置的字元可能是

        先 00000000 然後 00000001 然後 00000010 最後 00000011

    按照這種順序放置的電腦,稱為 Big-Endian (大頭派);也可能是

        先 00000011 然後 00000010 然後 00000001 最後 00000000

    按照這種順序放置的電腦,稱為 Little-Endian (小頭派)。

    為什麼叫『大頭』派?因為電腦把『大』的位數放在『前面』 (記憶體編號小的就是前面)。就好像我們寫十進制數字 123 的意思一百二十三 (100 + 20 + 3),也就是最大位--百位,寫在前面。因此,我們自己屬於『大頭派』。

    相反地,如果把『小』的位數放在『前面』,那就是『小頭』派了。如果有一個民族的文字,把 123 解釋成三百二十一 (1 + 20 + 300),那他們就是『小頭派』。阿拉伯文的文字書寫,是從右向左橫寫,但是遇到數字的時候,卻是跟我們一樣從左向右寫。如果阿拉伯人讀文字與數字的時候,都是從右向左讀,則他們會先讀到數字的最小位。在這個意義之下,阿拉伯人是『小頭派』。

    以下程式執行上述實驗。它印出變數 n 佔據的四個記憶體,以及它們分別的值 (以 0 到 255 的無號整數表示)。

    /* Program F */
    #include <stdio.h>
    main() {
        int n = 256*256+2*256+3;
        unsigned char *c;
        printf("n = %d\n", n);
        c = (unsigned char*) (void*) &amp;n;
        printf("n is allocated at\n%11u\t%11u\t%11u\t%11u\n", c, c+1, c+2, c+3);
        printf("%11u\t", *c++);
        printf("%11u\t", *c++);
        printf("%11u\t", *c++);
        printf("%11u\n", *c++);
    }

    執行的報表如下。

    Intel

    n = 66051
    n is allocated at
     3221223236      3221223237      3221223238      3221223239
              3               2               1               0

    Sun

    n = 66051
    n is allocated at
     4026530332      4026530333      4026530334      4026530335
              0               1               2               3

    我們看到,Intel 的 Pentium CPU 屬於小頭派, Sun 的 Sparc CPU 屬於大頭派。與 Intel 相容的 AMD CPU 也是小頭派,而大部分其他廠牌的 CPU 都是大頭派。 </stdio.h></stdio.h></stdio.h></stdio.h>