• 从零开始学习OpenGL ES之一 – 基本概念

    (注:由于Simon Maurice的iPhone OpenGL ES的网站已经不存在了,所以我将翻译另一系列的OpenGL ES教程。我是通过Proxy访问的此教程,所以无法给出原文链接。另外所有的图片和源代码我放在本地,以防不测。原文的名称是“OpenGL ES from the Ground Up”。)

    我曾写过一些文章介绍iPhone OpenGL ES编程,但大部分针对的是已经至少懂得一些3D编程知识的人。

    作为起点,请下载我的OpenGL Xcode项目模板,而不要使用Apple提供的模板。你可以解压到下面位置安装此模板:

    /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application/

    已经有大量有关OpenGL的好教程和书籍。但是,却没有多少是关于OpenGL ES,而且没有(至少在我撰写此文时)是专门针对学习iPhone上3D编程的。因为大部分有关学习OpenGL的材料是从所谓“直接模式(direct mode)”开始的,而OpenGL ES并不支持此模式,对于没有3D背景知识的iPhone开发者而言,使用现有的书籍和教程是十分困难的。为满足一些开发者的要求,我决定撰写一个针对3D初学者的博文系列。这是此系列的第一篇文章。

    读文章 »

     
  • 存储OpenGL ES内容到相片簿中

    (注:本文改编自iPhone – saving OpenGL ES content to the Photo Album,懒得全文翻译了,只挑一下重点加上自己的语言描述一下)

     

    有许多程序都有将图片存入相片簿的功能。如果你使用了OpenGL ES,那么本文的方法适合你使用。简单步骤:

    1. 使用glReadPixels读取GL数据到字节数组中
    2. 使用UIImageWriteToSavedPhotosAlbum将UIImage存储到相片簿中

     

    但怎样将字节数组转换成UIImage比较困难。由于 [UIImage imageFromData:data]需要UIImage支持的文件格式,所以并不适用,因为从glReadPixels读取的字节数组中的数据是原始像素数据。可以使用CGImageCreate来创建一个CGImageRef,然后用[UIImage imageWithCGImage:imageRef]转换成UIImage。CGImageCreate要求CGDataProviderRef,可以通过CGDataProviderCreateWithData使用glReadPixels的数据来创建。整个过程的流程如下:

     

    glReadPixels -> CGDataProviderCreateWithData -> CGImageCreate -> [UIImage imageWithCGImage:] -> UIImageWriteToSavedPhotosAlbum

     

    但是还存在一个问题,OpenGL 使用标准笛卡尔坐标,即+Y朝上, -Y朝下。所以用glReadPixels获得的数组是上下颠倒的。可以使用位旋转技术进行修正。下面是代码(用在具有CAEAGLLayer的UIView中) :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
          -(UIImage *) glToUIImage {
       
              NSInteger myDataLength = 320 * 480 * 4;
               
              // allocate array and read pixels into it.
              GLubyte *buffer = (GLubyte *) malloc(myDataLength);
              glReadPixels(0, 0, 320, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
       
             // gl renders "upside down" so swap top to bottom into new array.
             // there's gotta be a better way, but this works.
             GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
     
             for(int y = 0; y <480; y++)
             {
                   for(int x = 0; x <320 * 4; x++)
                   {
                        buffer2[(479 - y) * 320 * 4 + x] = buffer[y * 4 * 320 + x];
                   }
             }
             
            // make data provider with data.
            CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
             
            // prep the ingredients
            int bitsPerComponent = 8;
            int bitsPerPixel = 32;
            int bytesPerRow = 4 * 320;
     
            CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
            CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
            CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
             
            // make the cgimage
            CGImageRef imageRef = CGImageCreate(320, 480, bitsPerComponent, bitsPerPixel,
                 bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
           
            // then make the uiimage from that
            UIImage *myImage = [UIImage imageWithCGImage:imageRef];
            return myImage;
       }
     
       -(void)captureToPhotoAlbum {
                UIImage *image = [self glToUIImage];
                UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);
        }
     
  • OpenGL ES粒子发生器

    译者注:此代码虽然有这样那样的问题,但仍然值得参考。

    IMG_0038

    我在360 iDev会议中汇总了粒子发生器的代码。由于我又要开始进行有收入的工作所以我必须将之处之高阁了,但我准备在这里分享给有兴趣者。

    IMG_0020

    首先,我要说我并不是一个OpenGL的专家,我撰写此文能够帮助我更好地学习OpenGL 和粒子系统,所以可以肯定还有很多地方需要改进。

    IMG_0038

    其次,此代码还有许多bug,并不适用于最终产品。最重要的一个bug是试图释放粒子时造成的死循环。粒子内存没有被释放,它不断被重用。有两个链接表,一个用于保存可见的粒子,另一个保存不再可见的粒子。当一个粒子生存期到达时,它将被从一个列表移动到另一个。当需要一个新的粒子时,就从列表中提取一个。此方法可以避免不断的内存分配和释放的开销 。但是,当粒子发射后,我需要一个选项来释放内存,现在它会造成死循环。

    IMG_0005

    第三,示例程序将所有的发生器放入一个数组中。当你轻触屏幕时,当前发生器会停止发射,下一个发生器开始启动。当最后一个发生器结束时,第一个发生器循环启动。此时,会遇到pthread锁竞争问题,两个线程会等待另一个线程,引起程序锁住。由于我并非手工建立线程,所以跟踪此问题可能有相当的难度。

    IMG_0004

    可在Google Code project 下载。如果你不想使用subversion,你也可以直接下载zip文件Particles_03_06_2008.

     
  • OpenGL ES 03 – 变换

    今天我们将在屏幕上同时显示三角形和正方形,并且移动它们。移动一个物体,我们称之为转移.

     

    读文章 »

     
  • OpenGL ES 02 – 绘制基本图形2 – 正方形

    严格地说,正方形不是OpenGL ES的基元,但是它们确实是很基本的,而且渲染正方形像渲染三角形一样容易。本教程中,我们将把绘制三角形基元的代码转变成正方形的代码。我们仍将采用静态渲染,但我们会很简单地介绍一下变换(如移动)。当然,一旦我们绘制了正方形,我们就可以绘制正方体,然后甚至是带纹理映射的正方体……

     

    读文章 »

     
  • OpenGL ES 01 – 绘制基本图形1 – 三角形

    基元是构成复杂物体的基本绘图元素。OpenGL ES 中可以使用的基元有点,线和三角形。我想这些是不需要解释的了。

     

    首先,我们先看看一些代码,然后讨论一下这些代码的作用,你可以利用这些代码编写你自己的代码。

     

    读文章 »

     
  • OpenGL ES系列之0 – 建立Xcode项目

    为iPhone建立一个OpenGL ES的Xcode项目是很容易的事,特别是在苹果公司的SDK发布时引入了模板的概念后。我们所需要做的只是在适当的地方快速而简单的加入代码。这就是我们今天的主题。

    读文章 »