使用OpenGL ES的开源Cover Flow,据说有好几个上架程序中都有使用,见http://www.chaosinmotion.com/flowcover.m。
-
21
Aug 10
0 comments -
17
Jul 10在一些情况下,我们需要不通过App Store发布程序,比如:
- 发布前的测试
- 企业内部自用软件,不需要发布到App Store
非正规的做法当然是“越狱”,但是更为正式的做法是使用Ad-Hoc。至于怎样创建Ad-Hoc provision文件,不在本文讨论的范围内。本文讨论的是怎样安装Ad-hoc发布的程序。通常的做法是:
- 开发者将Xcode编译的Ad-Hoc程序.app文件压缩后与.mobileprovision一起传给用户。
- 用户拖动.mobileprovision文件到iTunes下的资料库 → 应用程序中
- 将压缩的.app文件解压,然后将整个.app文件夹拖动到iTunes下的资料库 → 应用程序中
通常这对于Mac用户没有什么问题,但有时Windows用户会遇到一些问题。所以更好的做法是将.app制作成.ipa与.mobileprovision文件一同寄给用户。下面是制作ipa的步骤:
mkdir Payload cp -rp MyApplication.app Payload/ zip -r MyApplication.ipa iTunesArtwork Payload
需要注意的是这里使用的是zip命令而不是Find中“Compress”选项,因为它会添加一些额外的内容。另外iTunesArtwork是一个512×512的png文件(注意无后缀),它将在iTunes中增加一个图标,所以这并不是必需的。
-
25
Mar 10今天的主题是我一度谈之色变的。概念上讲,它是3D编程中最为困难的部分。
首先,你应该理解 3D 几何和笛卡尔坐标系他。你还应该理解由顶点构成的三角形组成的OpenGL虚拟世界的物体,各顶点定义了三维空间的特定点,你还应理解怎样使用这些信息在 iPhone上使用OpenGL ES进行绘制。如果你不理解这些概念,我建议你回头再看看我的前六篇文章。
为在交互式程序如游戏中使用这些虚拟世界中的物体,必须要有一种方法来改变物体间的相对位置以及物体与观察者之间的相对位置。要有一种方法不但可以移动,而且可以旋转和改变物体的大小。
还必须要有一种方法将虚拟的三维坐标转换成电脑屏幕的二维坐标。所有这些都是通过所谓变换来实现的。实现变换的内部机制是就是矩阵。
尽管你不需要懂得太多有关矩阵和矩阵的数学知识就可以实现许多OpenGL的功能,但对这些观念的基本理解有很大的帮助。
读文章 »
-
9
Mar 10大家都知道,OpenGL ES对纹理的尺寸有限制,就是长和宽都必须是2的整数次幂。(实际上OpenGL都有此限制,但有一些扩展可以解决此问题)。因此处理方案有两种:
- 将纹理尺寸限制为2的整数次幂。比如,我有一个480×320的背景图案,我可以用Photoshop将画布设置为512×512,在纹理映射时只使用480×320部分。当然我也可以将多个图案合成在一个纹理中,在纹理映射时根据图案的位置进行映射。
- 仍然使用正常的图像尺寸,但在使用时进行转换。下面是源代码:
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// 首先调整纹理的长和宽为2的整数次幂
if( (_width != 1) && (_width & (_width - 1)) )
{
i = 1;
while((sizeToFit ? 2 * i : i) < _width)
i *= 2;
_width = i;
}
if( (_height != 1) && (_height & (_height - 1)) )
{
i = 1;
while((sizeToFit ? 2 * i : i) < _height)
i *= 2;
_height = i;
}
// 如果调整后的图像尺寸大于最大纹理尺寸(1024),那么需要缩小
while((_width > kMaxTextureSize) || (_height > kMaxTextureSize))
{
_width /= 2;
_height /= 2;
transform = CGAffineTransformScale(transform, 0.5, 0.5);
imageSize.x *= 0.5;
imageSize.y *= 0.5;
} -
3
Mar 10 -
-
14
Jan 10我在从零开始学习OpenGL ES之四 – 光效 一文中使用了一个普通GLfloat数组。由于它没有使用任何非OpenGL定义的数据结构,所以是最为普通和方便的方式。
但在此我使用在第一部分中定义的Vertex3D, Vector3D和 Color3D数据结构重写了 setupView:方法。并不是这种方法“更好”,但是它是一种不同的方式。当我第一次学习OpenGL时,我发现使用顶点,颜色和三角形的术语比可变长度浮点数组更容易理解。如果你和我一样,那么你会发现这个版本更容易理解。
除了使用自定义数据结构外,我还减少了环境光元素的数量并将光源向右移动了一点。然后使用Vector3DMakeWithStartAndEndPoints()将移动的光源指向二十面体。这样做使得光效更为生动一点。
-(void)setupView:(GLView*)view { const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0; GLfloat size; glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0); CGRect rect = view.bounds; glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar); glViewport(0, 0, rect.size.width, rect.size.height); glMatrixMode(GL_MODELVIEW); // Enable lighting glEnable(GL_LIGHTING); // Turn the first light on glEnable(GL_LIGHT0); // Define the ambient component of the first light static const Color3D light0Ambient[] = {{0.05, 0.05, 0.05, 1.0}}; glLightfv(GL_LIGHT0, GL_AMBIENT, (const GLfloat *)light0Ambient); // Define the diffuse component of the first light static const Color3D light0Diffuse[] = {{0.4, 0.4, 0.4, 1.0}}; glLightfv(GL_LIGHT0, GL_DIFFUSE, (const GLfloat *)light0Diffuse); // Define the specular component and shininess of the first light static const Color3D light0Specular[] = {{0.7, 0.7, 0.7, 1.0}}; glLightfv(GL_LIGHT0, GL_SPECULAR, (const GLfloat *)light0Specular); glLightf(GL_LIGHT0, GL_SHININESS, 0.4); // Define the position of the first light // const GLfloat light0Position[] = {10.0, 10.0, 10.0}; static const Vertex3D light0Position[] = {{10.0, 10.0, 10.0}}; glLightfv(GL_LIGHT0, GL_POSITION, (const GLfloat *)light0Position); // Calculate light vector so it points at the object static const Vertex3D objectPoint[] = {{0.0, 0.0, -3.0}}; const Vertex3D lightVector = Vector3DMakeWithStartAndEndPoints(light0Position[0], objectPoint[0]); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat *)&lightVector); // Define a cutoff angle. This defines a 50° field of vision, since the cutoff // is number of degrees to each side of an imaginary line drawn from the light's // position along the vector supplied in GL_SPOT_DIRECTION above glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 25.0); glLoadIdentity(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); }你可以随意调整光的属性,增加额外的光源或二十面体,体验一下这些调整会为场景带来什么样的变化。这些东西是很难体验出来的,所以不要指望一晚上就理解了所有东西。
-
11
Jan 10在OpenGL ES中另一种为多边形定义颜色创建材质的方法是将纹理映射到多边形。这是一种很实用的方法,它可以产生很漂亮的外观并节省大量的处理器时间。比如说,你想在游戏中造一个砖墙。你当然可以创建一个具有几千个顶点的复杂物体来定义每块砖以及砖之间的泥灰。
或者你可以创建一个由两个三角形构成的方块(四个顶点),然后将砖的照片映射上去。简单的几何体通过纹理映射的方法比使用材质的复杂几何体的渲染快得多。
-
9
Jan 10在 上一篇文章,我们讨论了光效的设定以及光效的各种属性。我们还讨论了光的三要素:散射光, 环境光 和 高光。如果你还不是完全清楚,那么我们来复习一下,在定义材质时大量的用到这些要素。
作为本文的起点,我们使用了此文中球体绘制 的项目文件。我们不再使用二十面体而是转向球体是因为球体是展示光和材质不同要素之间相互作用的最佳形状。
-
8
Jan 10(注:本文是改写的)
在写第四部分文章时,当我使用了 glLightfv() 和 glLightf()两种版本时,我突然意识到我还从来没有解释过OpenGL的命名规则。这部分应该属于第一部分,随OpenGL数据类型一起介绍。
在OpenGL中,没有使用任何参数并在函数尾不具有数据类型代号的函数只有一个:
GL_ENUM error = glGetError();另外,只具有一个参数(GL_ENUM)而且不具有函数尾数据类型代号的函数有:
glEnable(GL_COLOR_ARRAY);大部分OpenGL函数都是适用于不止一种数据类型。这在普通版OpenGL中尤为明显,大部分函数都有至少半打变种,允许你传递诸如 GLshort, GLbyte, GLint, GLfloat, GLDouble,或 GLfixed值或参考。在OpenGL ES中,函数调用的变种和数据类型少得多。然而,OpenGL ES仍然遵循同样的命名规则,所以最好还是要理解这些数据类型代号的含义。
函数名后的第一或者第二个字母代表了数据类型。下面是说明:
- b GLbyte
- s GLshort
- i GLint
- f GLfloat
- ub GLubyte
- us GLushort
- ui GLuint
所以 glFoof()需要传递一个glFloat,而 glFoos()则需要一个 GLshort。
注意: 在常规 OpenGL中,后缀中可能还包括数字。这些数字代表需要的数据类型的数量。例如,函数glVertex3f()使用三个GLfloat。由于此命名模式大部分用于直接模式,而OpenGL ES并不支持,所以在OpenGL ES中你不会常见到这种命名规则,然而有些函数还是遵循这种规则的,例如, glColor3f()。保持后缀中的数字可以使这两类API最大限度地兼容。
再回头看看第四部分,有时函数提供更通用的功能,如glLightf()。你可以调用此函数设置指定光的不同属性。例如,你可以设定点光源的截止角或者光源在3D空间的位置。点光源截止角需要一个值,但光源位置需要三个值。
对于这类函数,通过在函数尾加上一个 v 来表示。如果你想要传递常规数据类型给OpenGL,那么你不要使用此后缀,而是直接传递数据类型值。但是,如果你想要传递不止一个OpenGL原生数据类型( 即第一部分列表中的数据类型),那么你需要将这些值放入数组中并将数组开始的指针传递给OpenGL。当你像这样传递参考值给 OpenGL 时,你想要在函数后加上v后缀。
所以,回到第四部分的例子,当我们设置点光源的截止角时,我们使用了没有 -v的版本:
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);而当我们传递光源位置时,它需要三个GLfloats值,所以我们使用有v的版本:
const GLfloat light0Position[] = {0.0, 10.0, 10.0, 0.0}; glLightfv(GL_LIGHT0, GL_POSITION, light0Position);





