MULTIMEDIA

iPhone 3D Programming : Holodeck Sample (part 2) - Rendering the Dome, Clouds, and Text

3/25/2011 9:06:09 AM

2. Rendering the Dome, Clouds, and Text

For now let’s ignore the buttons and focus on rendering the basic elements of the 3D scene. See Example 3 for the rendering engine declaration and related types. Utility methods that carry over from previous samples, such as CreateTexture, are replaced with ellipses for brevity.

Example 3. RenderingEngine declaration for Holodeck
struct Drawable {
GLuint VertexBuffer;
GLuint IndexBuffer;
int IndexCount;
int VertexCount;
};

struct Drawables {
Drawable GeodesicDome;
Drawable SkySphere;
Drawable Quad;
};


struct Textures {
GLuint Sky;
GLuint Floor;
GLuint Button;
GLuint Triangle;
GLuint North;
GLuint South;
GLuint East;
GLuint West;
};

struct Renderbuffers {
GLuint Color;
GLuint Depth;
};

class RenderingEngine : public IRenderingEngine {
public:
RenderingEngine(IResourceManager* resourceManager);
void Initialize();
void Render(float theta, float phi, ButtonMask buttonFlags) const;
private:
void RenderText(GLuint texture, float theta, float scale) const;
Drawable CreateDrawable(const float* vertices, int vertexCount);
// ...
Drawables m_drawables;
Textures m_textures;
Renderbuffers m_renderbuffers;
IResourceManager* m_resourceManager;
};

Note that Example 3 declares two new private methods: RenderText for drawing compass direction labels and a new CreateDrawable method for creating the geodesic dome. Even though it declares eight different texture objects , it declares only three VBOs. The Quad VBO is re-used for the buttons, the floor, and the floating text.

Example 4 is fairly straightforward. It first creates the VBOs and texture objects and then initializes various OpenGL state.

Example 4. RenderingEngine initialization for Holodeck
#include "../Models/GeodesicDome.h"

...

void RenderingEngine::Initialize()
{
// Create vertex buffer objects.
m_drawables.GeodesicDome =
CreateDrawable(DomeVertices, DomeVertexCount);
m_drawables.SkySphere = CreateDrawable(Sphere(1));
m_drawables.Quad = CreateDrawable(Quad(64));

// Load up some textures.
m_textures.Floor = CreateTexture("Moss.pvr");
m_textures.Sky = CreateTexture("Sky.pvr");
m_textures.Button = CreateTexture("Button.png");
m_textures.Triangle = CreateTexture("Triangle.png");
m_textures.North = CreateTexture("North.png");
m_textures.South = CreateTexture("South.png");
m_textures.East = CreateTexture("East.png");
m_textures.West = CreateTexture("West.png");

// Extract width and height from the color buffer.
int width, height;
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_WIDTH_OES, &width);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
GL_RENDERBUFFER_HEIGHT_OES, &height);
glViewport(0, 0, width, height);

// Create a depth buffer that has the same size as the color buffer.
glGenRenderbuffersOES(1, &m_renderbuffers.Depth);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_renderbuffers.Depth);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES,
GL_DEPTH_COMPONENT16_OES, width, height);

// Create the framebuffer object.
GLuint framebuffer;
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES,
m_renderbuffers.Color);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
GL_DEPTH_ATTACHMENT_OES,
GL_RENDERBUFFER_OES,
m_renderbuffers.Depth);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_renderbuffers.Color);

// Set up various GL state.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Set the model-view transform.
glMatrixMode(GL_MODELVIEW);
glRotatef(90, 0, 0, 1);

// Set the projection transform.
float h = 4.0f * height / width;
glMatrixMode(GL_PROJECTION);
glFrustumf(-2, 2, -h / 2, h / 2, 5, 200);
glMatrixMode(GL_MODELVIEW);
}

Drawable RenderingEngine::CreateDrawable(const float* vertices,
int vertexCount)
{
// Each vertex has XYZ and ST, for a total of five floats.
const int FloatsPerVertex = 5;

// Create the VBO for the vertices.
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER,
vertexCount * FloatsPerVertex * sizeof(float),
vertices,
GL_STATIC_DRAW);

// Fill in the description structure and return it.
Drawable drawable = {0};
drawable.VertexBuffer = vertexBuffer;
drawable.VertexCount = vertexCount;
return drawable;
}



Let’s finally take a look at the all-important Render method; see Example 5.

Example 5. Render method for Holodeck
void RenderingEngine::Render(float theta, float phi, 
ButtonMask buttons) const
{
static float frameCounter = 0;
frameCounter++;

glPushMatrix();

glRotatef(phi, 1, 0, 0);
glRotatef(theta, 0, 1, 0);

glClear(GL_DEPTH_BUFFER_BIT);

glPushMatrix();
glScalef(100, 100, 100);
glRotatef(frameCounter * 2, 0, 1, 0);
glBindTexture(GL_TEXTURE_2D, m_textures.Sky);
RenderDrawable(m_drawables.SkySphere);
glPopMatrix();

glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, m_textures.Triangle);
glPushMatrix();
glTranslatef(0, 10, 0);
glScalef(90, 90, 90);
glColor4f(1, 1, 1, 0.75f);
RenderDrawable(m_drawables.GeodesicDome);
glColor4f(1, 1, 1, 1);
glPopMatrix();

float textScale = 1.0 / 10.0 + sin(frameCounter / 10.0f) / 150.0;

RenderText(m_textures.East, 0, textScale);
RenderText(m_textures.West, 180, textScale);
RenderText(m_textures.South, 90, textScale);
RenderText(m_textures.North, -90, textScale);
glDisable(GL_BLEND);

glTranslatef(0, 10, -10);
glRotatef(90, 1, 0, 0);
glScalef(4, 4, 4);
glMatrixMode(GL_TEXTURE);
glScalef(4, 4, 1);
glBindTexture(GL_TEXTURE_2D, m_textures.Floor);
RenderDrawable(m_drawables.Quad);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

if (buttons) {
...
}
}

The RenderText method is fairly straightforward; see Example 6. Some glScalef trickery is used to stretch out the quad and flip it around.

Example 6. RenderText method for Holodeck
void RenderingEngine::RenderText(GLuint texture, float theta, 
float scale) const
{
glBindTexture(GL_TEXTURE_2D, texture);
glPushMatrix();
glRotatef(theta, 0, 1, 0);
glTranslatef(0, -2, -30);
glScalef(-2 * scale, -scale, scale);
RenderDrawable(m_drawables.Quad);
glPopMatrix();
}
Other  
  •  Building LOB Applications : Printing in a Silverlight LOB Application
  •  Building LOB Applications : Data Validation through Data Annotation
  •  Building LOB Applications : Implementing CRUD Operations in RIA Services
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Resources and Content (part 2) - Adding Resources to a Project
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Resources and Content (part 1)
  •  iPhone 3D Programming : Blending and Augmented Reality - Rendering Anti-Aliased Lines with Textures
  •  Programming with DirectX : Game Math - Bounding Geometry (part 2) - Bounding Spheres & Bounding Hierarchies
  •  Programming with DirectX : Game Math - Bounding Geometry (part 1) - Bounding Boxes
  •  Programming with DirectX : Game Math - Matrices
  •  iPhone 3D Programming : Anti-Aliasing Tricks with Offscreen FBOs (part 2) - Jittering
  •  iPhone 3D Programming : Anti-Aliasing Tricks with Offscreen FBOs (part 1) - A Super Simple Sample App for Supersampling
  •  Building LOB Applications : Navigating RIA LOB Data
  •  Building LOB Applications : Databinding in XAML
  •  Microsoft XNA Game Studio 3.0 : Program Bugs
  •  Microsoft XNA Game Studio 3.0 : Getting Player Input - Adding Vibration
  •  Microsoft XNA Game Studio 3.0 : Getting Player Input - Using the Keyboard
  •  iPhone 3D Programming : Blending and Augmented Reality - Stencil Alternatives for Older iPhones
  •  iPhone 3D Programming : Blending and Augmented Reality - Poor Man’s Reflection with the Stencil Buffer
  •  Microsoft XNA Game Studio 3.0 : Getting Player Input - Reading a Gamepad
  •  iPhone 3D Programming : Blending and Augmented Reality - Shifting Texture Color with Per-Vertex Color
  •  
    Video
    Top 10
    Windows Server 2003 : Domain Name System - Command-Line Utilities
    Microsoft .NET : Design Principles and Patterns - From Principles to Patterns (part 2)
    Microsoft .NET : Design Principles and Patterns - From Principles to Patterns (part 1)
    Brother MFC-J4510DW - An Innovative All-In-One A3 Printer
    Computer Planet I7 Extreme Gaming PC
    All We Need To Know About Green Computing (Part 4)
    All We Need To Know About Green Computing (Part 3)
    All We Need To Know About Green Computing (Part 2)
    All We Need To Know About Green Computing (Part 1)
    Master Black-White Copying
    Most View
    Microsoft Tries To Flatten Competition With Surface (Part 3) - Dropbox drops Public Folders, SSD Prices Way Down, AMD Adopts Arm for Armor
    SQL Server 2008 R2 : Dropping Indexes, Online Indexing Operations, Indexes on Views
    NZXT Source 210 Elite - Finest Cases For Frugal Gamers
    OLED Me Be the One
    Toshiba Tecra R850
    Windows 8's Unexpected Features (Part 1)
    Computing Yourself Fit (Part 4)
    Crucial Ballistix Tactical LP 16GB Kit
    100 Windows Speed-Up Tips (Part 1) - Clean up your hard drive & Defrag your computer
    Organize Windows With Virtual Desktops
    Developing Applications for the Cloud on the Microsoft Windows Azure Platform : DNS Names, Certificates, and SSL in the Surveys Application
    Improve Your Mac (Part 2) - Add Music To You Movies
    LG Optimus L3 E400 Review (Part 1)
    Roku 2 XS
    Get An Awesome Satnav For Free
    Windows 7 : Syncing with Network Files (part 2) - Dealing with Conflict
    KWA 150 SE – The Most Expensive Amplifier Of ModWright
    Kindle Fire - The Second Coming (Part 1)
    Essential Wedding Kit (Part 3) - Shoot-saving kit
    Web Security : Attacking AJAX - Checking for Cross-Domain Access, Reading Private Data via JSON Hijacking