2. Rendering the Dome, Clouds, and TextFor 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 Holodeckstruct 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 Holodeckvoid 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 Holodeckvoid 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(); }
|