OpenGL ES From the Ground Up, Part 1: Basic Concepts

FRIDAY, APRIL 17, 2009

OpenGL ES From the Ground Up, Part 1: Basic Concepts

I've done a number of postings on programming OpenGL ES for the iPhone, but most of the posts I've done have been targeted at people who already know at least a little bit about 3D programming.

If you haven't already done so, grab a copy of my Empty OpenGL Xcode project template. We'll use  this template as a starting point rather than Apple's provided one. You can install it by copying the unzipped folder to this location:
/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application/
There are a number of good tutorials and books on OpenGL. Unfortunately, there aren't very many on OpenGL ES, and none (at least as I write this) that are specifically designed for learning 3D programming on the iPhone. Because most available material for learning OpenGL starts out teaching using what's called  direct mode, which is part of the functionality of OpenGL that's not in OpenGL ES, it can be really hard for an iPhone dev with no 3D background to get up and running using existing books and tutorials. I've had a number of people request it, so I've decided to start a series of blog posts designed for the absolute 3D beginner. This is the first in that series. If you've read and understood my previous OpenGL postings, you will probably find this series to be a little too basic.

OpenGL Datatypes


The first thing we'll talk about are OpenGL's datatypes. Because OpenGL is a cross-platform API, and the size of datatypes can vary depending on the programming language being used as well as the underlying processor (64-bit vs. 32-bit vs 16-bit), OpenGL declares its own custom datatypes. When passing values into OpenGL, you should always use these OpenGL datatypes to make sure that you are passing values of the right size or precision. Failure to do so could cause unexpected results or slowdowns caused by data conversion at runtime. Every implementation of OpenGL, regardless of platform or language, declares the standard OpenGL datatypes in such a way that they will be the same size on every platform, making porting OpenGL code from one platform to another easier.

Here are the OpenGL ES datatypes:
  • GLenum: An unsigned integer used for GL-specific enumerations. Most commonly used to tell OpenGL the type of data stored in an array passed by pointer (e.g. GL_FLOAT) to indicate that the array is made up of GLfloats.
  • GLboolean: Used to hold a single boolean values. OpenGL ES also declares its own true and false values (GL_TRUE and GL_FALSE) to avoid platform and language differences. When passing booleans into OpenGL, use these rather than YES or NO (though it won't hurt if you accidentally use YES orTRUE since they are actually defined the same. But, it's good form to use the GL-defined values.
  • GLbitfield: These are four-byte integers used to pack multiple boolean values (up to 32) into a single variable using bitwise operators. We'll discuss this more the first time we use a bitfield variable, but you can read up on the basic idea over at wikipedia
  • GLbyte: A signed, one-byte integer capable of holding a value from -128 to 127
  • GLshort: A signed two-byte integer capable of holding a value between −32,768 to 32,767
  • GLint: A signed four-byte integer capable of holding a value between −2,147,483,648 and 2,147,483,647
  • GLsizei: A signed, four-byte integer used to represent the size (in bytes) of data, similar to size_t in C.
  • GLubyte: An unsigned, one-byte integer capable of holding a value between 0 and 255.
  • GLushort: An unsigned, two-byte integer capable of holding a value between 0 and 65,535
  • GLuint: An unsigned, four-byte integer capable of holding a value between 0 and 4,294,967,295
  • GLfloat: A four-byte precision IEEE 754-1985 floating point variable.
  • GLclampf: This is also a four-byte precision floating point variable, but when OpenGL uses GLclampf, it is indicating that the value of this particular variable should always be between 0.0 and 1.0.
  • GLvoid: A void value used to indicate that a function has no return value, or takes no arguments.
  • GLfixedFixed point numbers are a way of storing real numbers using integers. This was a common optimization in 3D systems used because most computer processors are much faster at doing math with integers than with floating-point variables. Because the iPhone has vector processors that OpenGL uses to do fast floating-point math, we will not be discussing fixed-point arithmetic or the GLfixed datatype.
  • GLclampx: Another fixed-point variable, used to represent real numbers between 0.0 and 1.0 using fixed-point arithmetic. Like GLfixed, we won't be using or discussing this datatype.

OpenGL ES (at least the version used on the iPhone) does not support any 8-byte (64-bit) datatypes such as  long or  double. OpenGL does have these larger datatypes, but given the screen size of most embedded devices, and the types of applications you are likely to be writing for them, the decision was made to exclude them from OpenGL ES under the assumption that there would be little need for them, and that their use could have a detrimental effect on performance.

The Point or Vertex


The atomic unit in 3D graphics is called the  point or  vertex. These represent a single spot in three dimensional space and are used to build more complex objects. Polygons are built out of these points, and objects are built out of multiple polygons. Although regular OpenGL supports many types of polygons, OpenGL ES only supports the use of three-sided polygon, (aka triangles).

If you remember back to high-school geometry, you probably remember something called  Cartesian Coordinates. The basic idea is that you select an arbitrary point in space and call it the  origin. You can then designate any point in space by referencing the origin and using three numbers, one for each of the three dimensions, which are represented by three imaginary lines running through the origin. The imaginary line running from left to right is called the x-axis. Traveling along the x-axis, as you go to the right along the x axis, the value gets higher and as you go to the left, they get lower. Left of the origin are negative x values, and to the right are positive x values. The other two axes work exactly the same way. Going up along the y axis, the value of y increases, and going down, it decreases. Values above the origin have a positive y value, and those below the origin have a negative y value. With z, as objects move away from the viewer, the value gets lower, and as they move toward the viewer (or continue behind the viewer), values get higher. Points that are in front of the origin have a positive z value, and those that are behind the origin have a negative z value. The following illustration might make help those words make a little more sense:
cartesian.png

Note: Core Graphics, which is another framework for doing graphics on the iPhone uses a slightly different coordinate system in that the y axis decreases as it goes up from the origin, and increases as it goes down.


The value that increases or decreases along these axes are in an arbitrary scale - they don't represent any real measurement, like feet, inches, or meters. You can select any scale that makes sense for your own programs. If you want to design a game where each unit is a foot, you can do that. if you want to make each unit a micron, you can do that as well. OpenGL doesn't care what they represent to the end user, it just thinks of them as units, and make sure they are all equal distances.

Since any object's location in three-dimensional space can be represented by three values, an object's position is generally represented in OpenGL by the use of three  GLfloat variables, usually using an array of three floats, where the first item in the array (index 0) is the x position, the second (index 1) is the y position, and the third (index 2) is the z position. Here's a very simple example of creating a vertex for use in OpenGL ES:

    GLfloat vertex[3];
    vertex[0] = 10.0;       // x
    vertex[1] = 23.75;      // y
    vertex[2] = -12.532;    // z


In OpenGL ES, you generally submit all the vertices that make up some or all of the objects in your scene as a  vertex array. A vertex array is simply an array of values (usually  GLfloats) that contains the vertex data for some or all of the objects in the world. We'll see how that process works in the next post in this series, but the thing to remember about vertex arrays is that their size is based on the number of vertices being submitted multiplied by either three (for drawing in three-dimensional space) or two (for drawing in two-dimensional space). So, a vertex array that holds six triangles in three-dimensional space would consist of an array of 54  GLfloats, because each triangle has three vertices, and each vertex has three coordinates and 6 x 3 x 3 = 54.

Dealing with all these  GLfloats can be a pain, however, because you're constantly having to multiply things in your head and try to think of these arrays in terms of the vertices and polygons that they represent. Fortunately, there's an easier way. We can define a data structure to hold a single vertex, like this: 

typedef struct {
    GLfloat x;
    GLfloat y;
    GLfloat z;
} Vertex3D;

By doing this, our code becomes much more readable:

Vertex3D vertex;
vertex.x = 10.0;
vertex.y = 23.75;
vertex.z = -12.532;

Now, because our  Vertex3D struct is comprised of three  GLfloats, passing a pointer to a  Vertex3D is exactly the same as passing a pointer to an array of three GLfloats. There's no difference to the computer; both have the same size and the same number of bytes in the same order as OpenGL expects them. Grouping the data into these data structures just makes it easier for us as the programmer to visualize and deal with the data. If you download my Xcode template from the beginning of this article, this data structure and the supporting functions I'm going to be discussing next have already been defined in the file named OpenGLCommon.h. There is also an inline function for creating single vertices:

static inline Vertex3D Vertex3DMake(CGFloat inX, CGFloat inY, CGFloat inZ)
{
    Vertex3D ret;
    ret.x = inX;
    ret.y = inY;
    ret.z = inZ;
    return ret;
}


If you remember back to geometry (or maybe you don't, which is okay), the distance between two points on a plane is calculated using this formula: 

distance formula.png


We can implement this formula to calculate the straight-line distance between any two points in three-dimensional space with this simple inline function:

static inline GLfloat Vertex3DCalculateDistanceBetweenVertices (Vertex3D first, Vertex3D second)
{
    GLfloat deltaX = second.x - first.x;
    GLfloat deltaY = second.y - first.y;
    GLfloat deltaZ = second.z - first.z;
    return sqrtf(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ );
};


Triangles


Since OpenGL ES only supports triangles, we can also create a data structure to group three vertices into a single triangle object.

typedef struct {
    Vertex3D v1;
    Vertex3D v2;
    Vertex3D v3;
} Triangle3D;


Again, a single  Triangle3D is exactly the same as an array of nine  GLfloats, it's just easier for us to deal with it in our code because we can build objects out of vertices and triangles rather than out of arrays of  GLfloats.

There are a few more things you need to know about triangles, however. In OpenGL, there is a concept known as  winding, which just means that the order in which the vertices are drawn matters. Unlike objects in the real world, polygons in OpenGL do not generally have two sides to them. They have one side, which is considered the  front face, and a triangle can only be seen if its front face if facing the viewer. While it is possible to configure OpenGL to treat polygons as two-sided, by default, triangles have only one visible side. By knowing which is the front or visible side of the polygon, OpenGL is able to do half the amount of calculations per polygon that it would have to do if both sides were visible. 

Although there are times when a polygon will stand on its own, and you might very well want the back drawn, usually a triangle is part of a larger object, and one side of the polygon will be facing the inside of the object and will never be seen. The side that isn't drawn is called a  backface, and OpenGL determines which is the front face to be drawn and which is the backface by looking at the drawing order of the vertices. The front face is the one that would be drawn by following the vertices in counter-clockwise order (by default, it can be changed). Since OpenGL can determine easily which triangles are visible to the user, it can use a process called  Backface Culling to avoid doing work for polygons that aren't facing the front of the viewport and, therefore, can't be seen. We'll discuss the viewport in the next posting, but you can think of it as the virtual camera, or virtual window looking into the OpenGL world.

winding.png


In the illustration above, the cyan triangle on the left is a backface and won't be drawn because the order that the vertices would be drawn in relation to the viewer is clockwise. On the other hand, the triangle on the right is a frontface that will be drawn because the order of the vertices is counter-clockwise in relation to the viewer.

In the next posting in this series, we'll look at setting up the virtual world in OpenGL and do some simple drawing using  Vertex3D and  Triangle3D. In the post after that, we'll look at  transformations which are a way of using linear algebra to move objects around in the virtual world.



现代信息检索是指在当今信息社会中进行信息搜索和检索的一种方法和技术。信息检索的关键目标是根据用户的需求,在大量的信息资源中准确地找到相关信息。 信息检索的过程包含以下几个关键概念和技术: 1. 查询理解:该步骤旨在理解用户的信息需求,确定用户想要检索的内容。这可能涉及到一系列的技术,例如自然语言处理和语义分析,以便准确理解用户查询的含义和目的。 2. 信息检索模型:信息检索系统使用特定的模型来评估和排名与用户查询相关的文档或信息资源。常用的模型包括向量空间模型、布尔模型和概率模型等。这些模型根据查询项和文档的相关性计算得分,以便将最相关的文档呈现给用户。 3. 检索评估:评估系统在准确性和效率方面的性能是信息检索中的重要步骤。这涉及到针对特定任务和基准数据集进行评估实验,以了解系统的检索准确性、召回率和效率等方面的表现。 4. 搜索引擎技术:搜索引擎是现代信息检索的核心技术。搜索引擎通过采集、整理和索引互联网上的信息资源,并通过关键词匹配和排名算法等技术来满足用户的信息需求。 5. 信息可视化:为了帮助用户更好地理解和导航检索结果,信息可视化技术被广泛应用。这包括展示和呈现信息的方式,比如搜索结果的聚类、标签云、图表和交互式界面等。 现代信息检索的概念和技术正在不断发展和演进。随着互联网的迅速发展和数据爆炸的持续增长,信息检索面临着越来越多的挑战。同时,人工智能和大数据分析等新兴技术的应用也为信息检索带来了更多的创新和可能性。信息检索的发展将继续推动我们实现更高效、准确和个性化的信息搜索和检索体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值