且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Skybox OpenGL ES iPhone和iPad

更新时间:2023-11-10 13:49:34

因为我非常了解OpenGL ES,所以我参加了一个演示项目,完成了你描述的大部分内容。只要性能足够好,具体的意图是以OpenGL ES下最简单的方式完成所有工作。

Since I know OpenGL ES quite well, I had a go at a demo project, doing much of what you describe. The specific intention was to do everything in the simplest way available under OpenGL ES as long as the performance was good enough.

从Apple提供的OpenGL模板开始,我有用一个评论很多的实现文件编写了一个新类122行,将PNG图像作为纹理加载。我已经修改了示例视图控制器以根据需要绘制天空盒,并使用正常的iPhone惯性滚动版本来响应触摸,这意味着编写少于200行(也是注释)代码。

Starting from the OpenGL template that Apple supply, I have written one new class with a heavily commented implementation file 122 lines long that loads PNG images as textures. I've modified the sample view controller to draw a skybox as required and to respond to touches with a version of the normal iPhone inertial scrolling, which has meant writing less than 200 lines of (also commented) code.

要做到这一点,我需要知道:

To achieve this I needed to know:


  • CoreGraphics意味着从PNG获取像素数据

  • 如何设置PROJECTION堆栈以获得具有正确宽高比的透视投影

  • 如何操纵MODELVIEW堆栈以确保双轴旋转(第一人称射击游戏或Google街景风格)场景根据成员变量并确保我定义的立方体几何体与近剪裁平面不明显相交

  • 如何指定顶点位置和纹理坐标到OpenGL

  • 如何指定三角形OpenGL应该在顶点之间构造

  • 如何相应地设置OpenGL纹理参数只提供一个级别的纹理的细节

  • 如何跟踪触摸以操纵指示旋转的成员变量,包括一些惯性旋转的机制

  • the CoreGraphics means for getting pixel data from a PNG
  • how to set up the PROJECTION stack to get a perspective projection with the correct aspect ratio
  • how to manipulate the MODELVIEW stack to ensure two-axis rotation (first person shooter or Google StreetView style) of the scene according to member variables and to ensure that the cube geometry I defined doesn't visibly intersect the near clip plane
  • how to specify vertex locations and texture coordinates to OpenGL
  • how to specify the triangles OpenGL should construct between vertices
  • how to set the OpenGL texture parameters accordingly to supply only one level of detail for the texture
  • how to track a touch to manipulate the member variables dictating rotation, including a tiny bit of mechanics to give an inertial rotation

当然,遵守普通的视图控制器生命周期指令。纹理在viewDidLoad上加载并在viewDidUnload上释放,例如,以确保此视图控制器可以很好地处理潜在的内存警告。

Of course, the normal view controller lifecycle instructions are obeyed. Textures are loaded on viewDidLoad and released on viewDidUnload, for example, to ensure that this view controller plays nicely with potential memory warnings.

主要观察结果是,除了知道Objective-C信令机制,大部分都是C的东西。您主要使用C数组和引用来为OpenGL和CoreGraphics进行C函数调用。因此,自己编写代码的先决条件是在C语言中感到高兴,而不仅仅是Objective-C。

The main observations are that, beyond knowing the Objective-C signalling mechanisms, most of this is C stuff. You're primarily using C arrays and references to make C function calls, both for OpenGL and CoreGraphics. So a prerequisite for coding this yourself is being happy in C, not just Objective-C.

CoreGraphics的东西有点乏味但它只是阅读文档来计算了解每种类型的事物与下一种事物的关系 - 没有一个真的令人困惑。只需要了解您需要PNG数据的数据提供程序,您可以从该数据提供程序创建一个图像,然后使用您自己分配的内存创建一个位图上下文,将图像绘制到上下文中然后释放所有内容除了你自己分配的结果留给结果。该结果可以直接上传到OpenGL。这是一个相对较短的样板文件,但是OpenGL没有PNG的概念,而且CoreGraphics没有方便的方法将内容推入OpenGL。

The CoreGraphics stuff is a bit tedious but it's all just reading the docs to figure out how each type of thing relates to the next — none of it is really confusing. Just get into your head that you need a data provider for the PNG data, you can create an image from that data provider and then create a bitmap context with memory that you've allocated yourself, draw the image into the context and then release everything except the memory you allocated yourself to be left with the result. That result can be directly uploaded to OpenGL. It's relatively short boilerplate stuff, but OpenGL has no concept of PNGs and CoreGraphics has no convenient methods of pushing things into OpenGL.

我认为纹理是合适的大小在磁盘上。出于实际目的,这意味着假设它们沿着每个边缘都是大小为2的幂。我的是512x512。

I've assumed that textures are a suitable size on disk. For practical purposes, that means assuming they're a power-of-two in size along each edge. Mine are 512x512.

OpenGL纹理管理的东西很简单;它只是阅读手册来了解纹理名称,名称分配,纹理参数和上传图像数据。更常见的事情更多的是了解正确的功能而不是管理直观的飞跃。

The OpenGL texture management stuff is easy enough; it's just reading the manual to learn about texture names, name allocation, texture parameters and uploading image data. More routine stuff that is more about knowing the right functions than managing an intuitive leap.

为了向OpenGL提供几何体,我刚刚完整地写出了数组。我想你需要一点空间思维才能做到这一点,但是在纸上画出一个三维立方体并对角落进行编号将是一个很大的帮助。有三个相关的数组:

For supplying the geometry to OpenGL I've just written out the arrays in full. I guess you need a bit of a spatial mind to do it, but sketching out a 3d cube on paper and numbering the corners would be a big help. There are three relevant arrays:


  • 顶点位置

  • 每个顶点的纹理坐标location

  • 引用定义几何的顶点位置的索引列表

在我的代码中我使用了24个顶点,将立方体的每个面都视为逻辑上离散的东西(因此,六个面,每个面都有四个顶点)。为简单起见,我仅使用三角形定义了几何体。当你开始时,将这些东西提供给OpenGL实际上非常烦人;发生错误通常意味着你的程序在OpenGL驱动程序内部崩溃,而不会给你一个关于你做错了什么的提示。***一次建立一下。

In my code I've used 24 vertices, treating each face of the cube as a logically discrete thing (so, six faces, each with four vertices). I've defined the geometry using triangles only, for simplicity. Supplying this stuff to OpenGL is actually quite annoying when you're starting; making an error generally means your program crashes deep inside the OpenGL driver without giving you a hint as to what you did wrong. It's probably best to build up a bit at a time.

就能够托管OpenGL内容的UIView而言,我或多或少地使用了香草的东西Apple直接在OpenGL模板中提供。我做的一个更改是明确禁用任何尝试使用OpenGL ES 2.x. 1.x对于这项任务来说已经绰绰有余了,所以我们首先通过不提供两个备选渲染路径来获得简单性,其次因为ES 2.x路径会复杂得多。 ES 2.x是具有像素和顶点着色器的完全可编程管道,但在ES域中,固定管道被完全移除。因此,如果你想要一个,那么你必须提供自己的普通矩阵堆栈的替代品,你必须编写顶点和片段着色器来做'带纹理的三角形'等。

In terms of a UIView capable of hosting OpenGL content, I've more or less used the vanilla stuff Apple directly supply in the OpenGL template. The one change I made was explicitly to disable any attempted use of OpenGL ES 2.x. 1.x is more than sufficient for this task, so we gain simplicity firstly by not providing two alternative rendering paths and secondly because the ES 2.x path would be a lot more complicated. ES 2.x is the fully programmable pipeline with pixel and vertex shaders, but in ES land the fixed pipeline is completely removed. So if you want one then you have to supply your own substitutes for the normal matrix stacks, you have to write vertex and fragment shaders to do 'a triangle with a texture', etc.

触摸跟踪并不是特别复杂,或多或少只是要求我了解视锥体的工作原理以及Cocoa Touch中的触摸效果。一旦你完成了其他所有事情,这一点应该很容易。

The touch tracking isn't particularly complicated, more or less just requiring me to understand how the view frustum works and how touches are delivered in Cocoa Touch. Once you've done everything else, this bit should be quite easy.

值得注意的是,我必须实现的数学非常简单。只是触摸跟踪,真的。假设你想要一个Google Maps类型的视图意味着我可以完全依赖OpenGL的内置旋转功能。我没有明确处理矩阵。

Notably, the maths I had to implement was extremely simple. Just the touch tracking, really. Assuming you wanted a Google Maps-type view meant that I could rely entirely on OpenGL's built-in ability to rotate things, for example. At no point do I explicitly handle a matrix.

因此,你需要多长时间才能写出来取决于你对C和CoreGraphics的信心,以及你有多开心有时在黑暗中编码。因为我知道我在做什么,所以整个过程花了两三个小时。

So, how long it would take you to write depends on your own confidence with C and with CoreGraphics, and how happy you are sometimes coding in the dark. Because I know what I'm doing, the whole thing took two or three hours.

我会尝试找一个上传项目的地方,这样你就可以拥有一个看它。我认为翻阅它并看看它看起来多么陌生是有帮助的。这可能会让你很好地了解你是否可以在项目的时间框架内实现满足所有需求的东西。

I'll try to find somewhere to upload the project so that you can have a look at it. I think it'd be helpful to leaf through it and see how alien it looks. That'll probably give you a good idea about whether you could implement something that meets all of your needs within the time frame of your project.

我离开了视图控制器只有一个视图,这是OpenGL视图。但是,正常的iPhone合成规则适用,在您的项目中,您可以轻松地将常规控件放在最前面。您可以在 mediafire 上获取我的小实现。 ***帖子长度限制阻止我在这里放置大段代码,但如果您有任何具体问题,请随时询问。

I've left the view controller as having exactly one view, which is the OpenGL view. However, the normal iPhone compositing rules apply and in your project you can easily put normal controls on top. You can grab my little implementation at mediafire. *** post length limits prevent me from putting big snippets of code here, but please feel free to ask if you have any specific questions.