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