iPhone OS 3.0一个引入注目的新特性是push notifications(推送通知),它允许向已安装相关应用程序的各设备直接发送消息。苹果在新闻提示或IM应用中展示了此特性,它也十分完美地适合于我们的服务器监视服务程序Server Density。
-
29
Jan 10
0 comments -
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); -
7
Jan 10继续我们的iPhone OpenGL ES之旅,我们将讨论光效。目前,我们没有加入任何光效。幸运的是,OpenGL在没有设置光效的情况下仍然可以看见东西。 它只是提供一种十分单调的整体光让我们看到物体。但是如果不定义光效,物体看上去都很单调,就像你在第二部分程序中看到的那样。
-
6
Jan 10游戏都需要一个声音引擎,一般来说,有三种类型:
- 播放音效。音效一般是比较简短的声音文件。
- 播放背景音乐。
- 乐器,音效模拟。
本文介绍一个简单跨平台的音效引擎,主要针对第一种类型。实际上,也可以适用于第二种类型,但由于背景音乐文件较大,占用内存较大,所以本文介绍的方法并不是最为有效率的(特别是对于像iPhone之类内存较为紧张的平台,但仍然可用)。可以在本引擎的基础上加以改进,比如采用“流”(streaming)技术。而第三种类型,可能涉及到DSP(数字处理技术),比较复杂,另外在不同平台有一些不同的技术,如Windows下的VST/VSTi,Mac OSX下的AU等,不在本文的讨论范围。
本文介绍的音效引擎是基于OpenAL的,并且是我在许多项目中使用的引擎的简化部分(去除错误处理及乐器模拟部分)。
有关OpenAL的使用,网上有许多教程,比如:OpenAL编程教程等。iPhone上的OpenAL使用,本网站也有几篇文章。所以这里不再赘述。
本引擎的目的,是简化声音播放接口。最简单的情况下可以仅仅使用两条语句,就播放一段音效。而繁复的OpenAL初始化功能等都由引擎自动完成。下例展示了怎样播放一段音效的最为典型的调用:
1
2
3audio::CSound sound("sound.wav");
sound.play();本引擎由三个类和一个公共函数构成。audio::CEngine是引擎的核心部分,它是一个单例类(Singleton),负责直接与OpenAL接口,用户无需与其打交道。audio::CBuffer类对应于OpenAL中的缓存,通过audio::openAudioData函数打开音效文件,创建内部缓存,用户也无需直接使用。audio::CSound是用户直接使用的类,它提供了诸如play(),stop(),setVolume()和setPosition()几个接口函数。如需扩展功能,添加一些其他功能,可以直接加在此类中,并在audio::CEngine中实现。
以上三个类可以直接使用在不同平台中。与平台相关的代码,都在audio::openAudioData()中。它的作用是打开不同的声音文件。对于Windows,我使用了一个开源项目库libsndfile,用来打开诸如wav,caf,aiff,flac,ogg等常用音效文件(注意:mp3并未包括其中。由于使用mp3的软件需要支付一定许可证费用,本人也不喜欢使用)。而对于Mac OSX(iPhone),则使用了core audio。这里大家可能会有一个疑问,既然libsndfile也是跨平台的,为什么在iPhone上不使用它呢?确实,libsndfile支持Windows,Linux,Mac OSX,Sun Solaris等平台,而iPhone并不支持ogg等格式,使用libsndfile不正好填补这个空白?是的,我也是这样想的,但是,有两点原因初始我暂时没有使用它:
- 没有现成的iPhone库。由于libsndfile需要使用makefile由GCC编译(我曾试过使用Xcode编译,没有成功),我也不是这方面的专家。但是,libsndfile在Mac OSX下编译没有问题,所以只需稍作修改,在为iPhone进行编译也不是没有可能的事情。
- 由于其许可证的限制。libsndfile是基于LGPL的,它要求使用者采用动态连接库,而众所周知,iPhone(官方)是不支持动态链接的。如果使用静态链接,则需要随软件发布源代码或目标代码。其实,这也不是无法克服的,LGPL只要求发布与libsnd相关的目标代码,所以对你的软件并无影响。对吗?
本文给出了Windows下和iPhone下的应用。在Windows下使用需要下载OpenAL SDK和libsndfile。为方便编译好的libsndfile随示例程序给出给出。(你需要修改一下VS 项目文件中的有关OpenAL的头文件和库文件路径,另外,在OpenAL include目录中创建一个OpenAL目录,并将.h复制到其下,这样我就不需要修改#include语句了。)
示例程序audiolib下载。(项目在test目录下)
-
1
Jan 10现在你已经知道OpenGL是怎样绘图的了,让我们回头谈谈一个很重要的概念:OpenGL视口(viewport)。 许多人对3D编程还很陌生,那些使用过像Maya, Blender, 或 Lightwave之类3D图形程序的人都试图在OpenGL虚拟世界中找到“摄像机”。但OpenGL并不存在这样的东西。它所有的是在3D空间中定义可见的物体。虚拟世界是没有边界的,但计算机不可能处理无限的空间,所以OpenGL需要我们定义一个可以被观察者看到的空间。
如果我们从大部分3D程序具有的摄像机对象的角度出发来考虑,视口端点的中心就是摄像机。也就是观察者站的位置。它是一个观察虚拟世界的虚拟窗口。观察者可见的空间有一定限制。她看不见她身后的东西。她也看不见视角之外的东西。而且她还不能看见太远的东西。可以认为视口是通过“观察者可见”参数所确定的形状。很简单,对吗?
不幸的是,并非如此。要解释原因,我们首先需要讨论的是在OpenGL ES中具有的两种不同的视口类型:正交和透视。
-
31
Dec 09还有许多理论知识需要讨论,但与其花许多时间在复杂的数学公式或难以理解的概念上,还不如让我们开始熟悉OpenGL ES的基本绘图功能。
-
30
Dec 09(注:由于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初学者的博文系列。这是此系列的第一篇文章。






