MULTIMEDIA

iPhone 3D Programming : Adding Depth and Realism - Filling the Wireframe with Triangles

1/4/2011 4:15:21 PM
In this section we’ll walk through the steps required to render parametric surfaces with triangles rather than lines. First we need to enhance the ISurface interface to support the generation of indices for triangles rather than lines. Open Interfaces.hpp, and make the changes shown in bold in Example 1.
Example 1. Enhanced ISurface interface
struct ISurface {
virtual int GetVertexCount() const = 0;
virtual int GetLineIndexCount() const = 0;
virtual int GetTriangleIndexCount() const = 0;
virtual void GenerateVertices(vector<float>& vertices) const = 0;
virtual void GenerateLineIndices(vector<unsigned short>& indices) const = 0;
virtual void
GenerateTriangleIndices(vector<unsigned short>& indices) const = 0;
virtual ~ISurface() {}
};



You’ll also need to open ParametricSurface.hpp and make the complementary changes to the class declaration of ParametricSurface shown in Example 2.

Example 2. Enhanced ParametricSurface interface
class ParametricSurface : public ISurface {
public:
int GetVertexCount() const;
int GetLineIndexCount() const;
int GetTriangleIndexCount() const;
void GenerateVertices(vector<float>& vertices) const;
void GenerateLineIndices(vector<unsigned short>& indices) const;
void GenerateTriangleIndices(vector<unsigned short>& indices) const;

Next open ParametericSurface.cpp, and add the implementation of GetTriangleIndexCount and GenerateTriangleIndices per Example 3.

Example 3. ParametricSurface::GenerateTriangleIndices
int ParametricSurface::GetTriangleIndexCount() const
{
return 6 * m_slices.x * m_slices.y;
}

void
ParametricSurface::GenerateTriangleIndices(vector<unsigned short>& indices) const
{
indices.resize(GetTriangleIndexCount());
vector<unsigned short>::iterator index = indices.begin();
for (int j = 0, vertex = 0; j < m_slices.y; j++) {
for (int i = 0; i < m_slices.x; i++) {
int next = (i + 1) % m_divisions.x;
*index++ = vertex + i;
*index++ = vertex + next;
*index++ = vertex + i + m_divisions.x;
*index++ = vertex + next;
*index++ = vertex + next + m_divisions.x;
*index++ = vertex + i + m_divisions.x;
}
vertex += m_divisions.x;
}
}



Example 3 is computing indices for two triangles, as shown in Figure 1.

Figure 1. Generating triangle indices for a parametric surface


Now we need to modify the rendering engine so that it calls these new methods when generating VBOs, as in Example 4. The modified lines are shown in bold. Make these changes to both RenderingEngine.ES1.cpp and RenderingEngine.ES2.cpp.

Example 4. RenderingEngine Modifications for triangles
void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
{
vector<ISurface*>::const_iterator surface;
for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {

// Create the VBO for the vertices.
vector<float> vertices;
(*surface)->GenerateVertices(vertices);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER,
vertices.size() * sizeof(vertices[0]),
&vertices[0],
GL_STATIC_DRAW);

// Create a new VBO for the indices if needed.
int indexCount = (*surface)->GetTriangleIndexCount();
GLuint indexBuffer;
if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
indexBuffer = m_drawables[0].IndexBuffer;
} else {
vector<GLushort> indices(indexCount);
(*surface)->GenerateTriangleIndices(indices);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indexCount * sizeof(GLushort),
&indices[0],
GL_STATIC_DRAW);
}

Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
m_drawables.push_back(drawable);
}

...

}


void RenderingEngine::Render(const vector<Visual>& visuals) const
{
glClearColor(0.5, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

vector<Visual>::const_iterator visual = visuals.begin();
for (int visualIndex = 0;
visual != visuals.end();
++visual, ++visualIndex)
{

//...

// Draw the surface.
int stride = sizeof(vec3);
const Drawable& drawable = m_drawables[visualIndex];
glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
glVertexPointer(3, GL_FLOAT, stride, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
}
}



Getting back to the sample app, at this point the wireframe viewer has officially become ModelViewer; feel free to build it and try it. You may be disappointed—the result is horribly boring, as shown in Figure 2. Lighting to the rescue!

Figure 2. ModelViewer without lighting


Other  
  •  iPhone 3D Programming : Adding Depth and Realism - Creating and Using the Depth Buffer
  •  iPhone 3D Programming : Adding Depth and Realism - Examining the Depth Buffer
  •  iPhone 3D Programming : HelloCone with Fixed Function
  •  iPhone 3D Programming : Vector Beautification with C++
  •  jQuery 1.3 : An image carousel
  •  jQuery 1.3 : Headline rotator
  •  Silverlight : Print a Document
  •  Silverlight : Capture a Webcam
  •  Silverlight : Make Your Application Run out of the Browser
  •  Silverlight : Put Content into a 3D Perspective
  •  Silverlight : Response to Timer Events on the UI Thread
  •  Silverlight : Build a Download and Playback Progress Bar
  •  Silverlight : Play a Video
  •  C# 4.0 : Add a Static Constructor and Initialization
  •  C# 4.0 : Add a Constructor
  •  .NET Compact Framework : Font Selection
  •  .NET Compact Framework : Drawing Text
  •  Programming the Service Bus
  •  WCF Services : Generics
  •  WCF Services : Delegates and Data Contracts
  •  
    Top 10
    Programming .NET Security : Cryptography Explained (part 2)
    Windows 7: Optimizing Performance (part 3) - Using ReadyBoost to Enhance Performance
    Securing Windows Server 2008 in the Branch Office
    10 Biggest tech breakthroughs of the past 200 issues (Part 1)
    Install Windows Server 2008
    Produce an RSS Feed Dynamically in IIS
    Troubleshooting Common Disk Problems
    Building Android Apps : Detecting Browsers with WURFL
    Exchange Server 2010 : Administering Mailbox Content - Monitor and Restrict Communication (part 2) - Apply Common Monitoring and Restriction Scenarios
    IIS 7.0 : Securing Configuration - Restricting Access to Configuration
    Most View
    Security Fundamentals : Windows Authentication
    Algorithms for Compiler Design: THE ARRAY REFERENCE
    Building Your First Windows Phone 7 Application (part 3) - Writing Your First Windows Phone Code
    Exchange Server 2007 : Enable Antispam Configuration
    ASP.NET 4 : Getting More Advanced with the Entity Framework (part 1) - Querying with LINQ to Entities
    Beginning Android 3 : The Input Method Framework - Tailored to Your Needs
    Windows Phone 7 Development : Understanding Trial and Full Modes (part 1) - Using the IsTrial Method
    Windows Server 2008 : The Migration Planning Phase - Documenting the Process for Migration
    SharePoint 2010 : Performing an In-Place Upgrade of a SharePoint Environment
    Android Security : Services
    SQL Server 2008 : Developing with LINQ to SQL (part 1)
    Design and Deploy High Availability for Exchange 2007 : Create Bookmark Create Note or Tag Implement Standby Continuous Replication (SCR)
    Mobile Application Security : SymbianOS Security - Interprocess Communication
    Collaborating via Web-Based Communication Tools : Evaluating Web Conferencing Tools
    Optimizing for Vertical Search : Optimizing for Local Search (part 2)
    Building Android Apps : Controlling the Phone with JavaScript (part 3) - Accelerometer
    Programming .NET Security : Cryptographic Keys Explained
    Biggest tips guide ever! (Part 3) - Security
    WAP and Mobile HTML Security : Authentication on WAP/Mobile HTML Sites & Encryption
    SQL Azure : Building Two OData Consumer Applications (part 2) - Windows Mobile 7 Application