Saturday, May 2, 2009

setupView: from Part IV Rewritten

I wrote the Part 4 of the OpenGL ES From the Ground Up series using plain arrays of GLfloats. That is the most common way of doing it that you will see out in the wild as it's the most portable, since it doesn't use any data structures not defined within OpenGL itself.

I took the opportunity to rewrite the setupView: method to use the Vertex3D, Vector3D, and Color3D structs we defined back in Part 1. Neither approach is "better", but I thought it might be interesting to see it done a little different way. When I was first learning OpenGL, I found it easier to think in terms of Vertices, Colors, and Triangles, rather than all the various-length arrays of floats. If you're like I was, then you may find this version easier to read and understand.

In addition to use our custom data structures, I also reduced the amount of the ambient light component and moved the light over to the right. I then used the Vector3DMakeWithStartAndEndPoints() to point the moved light at the icosahedron. By moving the light over and having it strike the object at an angle, the effect is a little more dramatic.

const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
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);

// Enable lighting

// Turn the first light on

// 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);

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

You should feel free to play with the light attributes, add additional lights or icosahedrons, and generally just play around to get a feel for how changes will effect your scene. This stuff is conceptually hard to grok, so don't expect it to come overnight (and if it does, count yourself lucky).


Jeremy W. said...

One thing has been niggling at me since Part 1: what guarantees the struct members are laid out contiguously in memory, as I believe is always the case with an array? I know they will be laid out sequentially in memory, but they could have unnamed internal and terminal padding containing who knows what values.

I suppose any sane compiler would not introduce any padding, since all members have the same type (itself presumably a multiple of the word size), but at the same time, I wonder whether declaring the structs with __attribute__((__packed__)) might better express the intention to use them as arrays with named indices.

Jeff LaMarche said...


I'm no compiler expert, but in general practice, if you create a struct with four floats, it's going to be exactly the same size as using malloc(sizeof(float) * 4). You can get into some weird issues with bitfields and booleans, or if you're using unions, but straight structs with full-byte datatypes are generally safe to use in this manner.

Compilers aren't going to add anything to a struct. They might memory to an objects, but not a struct. A lot of things would fail to work if creating a four-object array wasn't the same as a four-object struct (assuming same datatype) wasn't the same as doing malloc(sizeof(datatype) * 4).

As long as you're using datatypes that are full-byte in size, you should be safe. All the OpenGL datatypes are - even the BOOL takes a full eight bits, so everything lines up nicely.

I know there are some exceptions to this. There were some optimization flags under the PPC architecture, IIRC, that would cause everything to get lined up on 4-byte boundaries. That wouldn't affect these structures, but if you had a struct with both Glint and GLfloat members, it might have caused a problem. If you look in OpenGLCommon.h, I don't think you'll see any structs that mix datatypes of that use partial-byte datatypes.

Jeff LaMarche said...

A little more on the topic:

Padding is only inserted when a structure member is followed by a member with a larger alignment requirement or at the end of the structure.and

C and C++ do not allow the compiler to reorder structure members to save space, other languages might. It is also possible to tell most C and C++ compilers to "pack" the members of a structure to a certain level of alignment, e.g. "pack(2)" means align data members larger than a byte to a two-byte boundary so that any padding members are at most one byte long.So, in cases like ours where all the members are the same datatype, it's not an issue unless we specifically tell it to pack the struct.

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

antywong said...

The rounded shape of speedy 30 features textile fake louis vuitton lining and leather trimmings with shiny Louis Vuitton Monogram ldylle Romance Encre golden brass. Sized at 11.8" x 8.3" x 6.7", the large capacity Hermes Original Python Birkin 30 Grey of this bag is enough for handbags review daily essentials; you can put bags wholesale everything into this city bag. It also fits for Hermes Clemence Jypsiere 34 Purple every occasion and perfectly goes with any outfits mfakng100910.

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels