quick_recipes (779892), страница 40
Текст из файла (страница 40)
We are going to hardcode thecoordinates so you can see them easily. However, the sphere is made upof too many points and triangles. We are going to write a loop to createit dynamically and keep the memory footprint to an acceptable level (it’seither that or we reduce the number of points in our sphere but then itstops looking good).We are also going to give different points different colors, so you cansee the triangles when you run the code.From a Symbian OS perspective, CCoeControl::Draw() tends tointerfere with the OpenGL ES API eglSwapBuffers, so the actual codesample introduces a scene rendering callback:class CMyMainControl : public CCoeControl{public:void RenderScene();protected: // sphere building utilitiesstatic void DrawSlice(TInt aYAngle);static void DrawRectangle(TInt aYAngle, TInt aZAngle);static void AddVertice(TInt aOffset, TInt aYAngle,TInt aZAngle);static GLfloat FindSine(TInt aAngle);static GLfloat FindCosine(TInt aAngle);224SYMBIAN C++ RECIPES};static const GLfloat sinesPer10 ={0, 0.17365f, 0.34202f, 0.5f, 0.64279f, 0.76604f,0.86603f, 0.93969f, 0.98481f, 1.0f};void CMyMainControl::RenderScene(){// the cube first.
6 sides. 2 triangles per side.// 3 vertices per triangles. 3 coordinates per vertex.GLubyte triangles [6 * 2 * 3 * 3] ={/* front */1,1,1, /**/ -1,1,1, /**/ -1,-1,1,1,1,1, /**/ -1,-1,1, /**/1,-1,1,/* right */1,-1,1, /**/ 1,-1,-1, /**/1,1,-1,1,-1,1, /**/ 1,1,-1, /**/ 1,1,1,/* back */-1,-1,-1, /**/ -1,1,-1, /**/ 1,1,-1,-1,-1,-1, /**/ 1,1,-1, /**/ 1,-1,-1,/* left */-1,1,1, /**/ -1,1,-1, /**/ -1,-1,-1,-1,1,1, /**/ -1,-1,-1, /**/ -1,-1,1,/* top */1,1,-1, /**/ -1,1,-1, /**/ -1,1,1,1,1,-1, /**/ -1,1,1, /**/ 1,1,1,/* bottom */-1,-1,1, /**/ -1,-1,-1, /**/ 1,-1,-1,-1,-1,1, /**/ 1,-1,-1, /**/ 1,-1,1};glClearColorx( 0, 0, 0, 255 );glClear( GL_COLOR_BUFFER_BIT );glEnableClientState( GL_VERTEX_ARRAY );glVertexPointer( 3, GL_BYTE, 0, triangles );glDrawArrays(GL_TRIANGLES, 0, 36);// Now, let’s make the sphere:// We are going to draw one rectangle at a time.GLfloat* sphereTriangles = User::Alloc(sizeof(GLfloat) * 12);// 4 vertices (see GL_TRIANGLE_STRIP).
3 coordinates each.if ( NULL != sphereTriangles ){glVertexPointer( 3, GL_FLOAT, 0, sphereTriangles);for (TInt yRotate = 0 ; yRotate < 180 ; yRotate += 10){DrawSlice(yRotate);}eglSwapBuffers( iEglDisplay, iEglSurface );3D GRAPHICS USING OPENGL ES}delete sphereTriangles;}void CMyMainControl::DrawSlice(TInt aYAngle){for (TInt zRotate = 0 ; zRotate < 360 ; zRotate += 10){DrawRectangle(aYAngle, zRotate);}}void CMyMainControl::DrawRectangle(TInt aYAngle, TInt aZAngle){AddVertice(0, aYAngle, aZAngle);AddVertice(3, aYAngle, aZAngle+10);AddVertice(6, aYAngle+10, aZAngle);AddVertice(9, aYAngle+10, aZAngle+10);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);}//We are going from our own spherical//coordinate system to a Cartesian onevoid CMyMainControl::AddVertice(TInt aOffset, TInt aYAngle,TInt aZAngle){GLfloat x,y,z;GLfloat ySine, yCosine, zSine, zCosine;ySine = FindSine(aYAngle);yCosine = FindCosine(aYAngle);zSine = FindSine(aZAngle);zCosine = FindCosine(aZAngle);x = zCosine * yCosine;y = zSine * yCosine + 2.0f;z = ySine;iSphereTriangles[aOffset] = x;iSphereTriangles[aOffset+1] = y;iSphereTriangles[aOffset+2] = z;}GLfloat CMyMainControl::FindCosine(TInt aAngle){aAngle += 90;if (aAngle>=360)aAngle-=360;return FindSine(aAngle);}GLfloat CMyMainControl::FindSine(TInt aAngle){TInt angle=aAngle;if (angle>=180)angle-=180; //Sin(X)=-Sin(X-180)if (angle>90)angle=180-angle; //Sin(X)=Sin(180-X)TInt index=angle/10;GLfloat result=sinesPer10[index];225226SYMBIAN C++ RECIPESif (aAngle>180)result=-result;return result;}The sphere vertex coordinate calculus algorithm is far from optimized.Caching some points would help the CPU make fewer floating-pointoperations.
However, it would not be difficult to modify it to display anysphere: position, size and resolution can be made generic.Once projected to the screen, not all points are equidistant in ourexample. When you start using lighting to accentuate a three-dimensionalenvironment, you will probably want to keep them equidistant in 3Dspace rather than trying to make them equidistant when projected.4.6.3.3Translate a 3D ObjectAmount of time required: 15 minutesLocation of example code: \3D\BasicRequired libraries: libgles_cm.libRequired header file(s): GLES\egl.hRequired platform security capability(s): NoneProblem: You want to move a 3D object along a vector.Solution: The one thing you need to consider when dealing with thetransformation of coordinates is that we are modifying the current statematrix.
If you keep the transformation active on the main state matrix, itwill be applied to all drawings.We are going to draw a single, simple triangle in a 3D space and showyou how to apply a translation to that object only, using a temporarystate matrix. You can reuse the same template to translate more complexobjects.void CMyMainControl::RenderScene(){GLubyte triangle [3 * 3] = {1,1,0, /**/ 0,1,0, /**/ 1,0,0};glEnableClientState( GL_VERTEX_ARRAY );glVertexPointer( 3, GL_BYTE, 0, triangle );glLoadIdentity();glPushMatrix();// Translate by (-5, -4, -3) bitshifting eachglTranslatex( -5 << 16 , -4 << 16 , -3 << 16 );glDrawArrays(GL_TRIANGLES, 0, 3);glPopMatrix();glDrawArrays(GL_TRIANGLES, 0, 3);eglSwapBuffers(iEglDisplay, iEglSurface);}3D GRAPHICS USING OPENGL ES227This code will show the same triangle drawn twice on the screen: oncein its original position, and once translated.Tip: Only the first 16 bits of the coordinates you pass to glTranslatex are used.
This is why there is a bit-shift in the code.4.6.3.4Rotate a 3D ObjectAmount of time required: 15 minutesLocation of example code: \3D\BasicRequired libraries: libgles_cm.libRequired header file(s): GLES\egl.hRequired platform security capability(s): NoneProblem: You want to rotate a 3D object along the three coordinate axes.Solution: As we described in Recipe 4.6.3.3, the one thing you need toconsider when dealing with the transformation of coordinates is that weare modifying the current state matrix.
If you keep the transformationactive on the main state matrix, it will be applied to all drawings.We are going to draw a single simple triangle in 3D space and showhow to apply a rotation to that object only by using a temporary statematrix (rotation angles are measured in degrees). You can reuse the sametemplate to rotate more complex objects.void CMyMainControl::RenderScene(){GLubyte triangle [3 * 3] ={1,1,0, /**/ 0,1,0, /**/ 1,0,0};glEnableClientState( GL_VERTEX_ARRAY );glVertexPointer( 3, GL_BYTE, 0, triangle );glLoadIdentity();glPushMatrix();// Rotate by 30 degrees on X and Y axesglRotatex( 30 << 16 , 1 << 16 , 0 , 0 );glRotatex( 30 << 16 , 0 , 1 << 16 , 0 );glDrawArrays(GL_TRIANGLES, 0, 3);glPopMatrix();glDrawArrays(GL_TRIANGLES, 0, 3);eglSwapBuffers(iEglDisplay, iEglSurface);}This code will show the same triangle drawn twice on the screen: oncerotated (by 30 degrees over both the X and Y axes) and once in its originalposition.Tip: Only the first 16 bits of the coordinates you pass to glRotatexare used.
This is why there is a bit-shift in the code.228SYMBIAN C++ RECIPES4.6.4 Intermediate Recipes4.6.4.1Apply a Texture to a 3D ObjectAmount of time required: 30 minutesLocation of example code: \3D\BasicRequired libraries: libgles_cm.libRequired header file(s): GLES\egl.hRequired platform security capability(s): NoneProblem: You want to apply a bitmap to an area of a 3D object.Solution: First, you are going to have to make a bitmap available to yourcode.
On a basic level, this is an area in memory containing a set ofRGB-coded pixels. The recipes in Section 4.5 cover 2D graphics, andthey will teach you how to load and manipulate a CFBsBitmap object.OpenGL ES v1.1 supports only 2D textures, so we need to tell thesystem to map a piece of our bitmap to a triangle. Essentially, texturecoordinates are used to ‘cut’ triangles out of bitmaps.There are a couple of things to keep in mind when using textures:• Only bitmaps with height and width of a power of 2 are supported(i.e., 256 × 64, 128 × 128, and so on).• Symmetries in the bitmap are important, since you can rotate your3D objects and look at the texture on both sides of the triangles it ismapped onto.We are going to map a texture to a rectangle made up of two triangles.You can repeat this approach with more triangles to form a more complex3D object.#include <FBS.H> // and link to fbscli.libvoid CMyMainControl::RenderScene(CFbsBitmap& aTexture){GLubyte triangles [ 2 * 3 * 3] ={2,1,1, /**/ -1,1,1, /**/ -1,-1,1,2,1,1, /**/ -1,-1,1, /**/ 2,-1,1,};// (0,0) is bottom-left, (1,1) is top-rightGLfloat texCoords[2 * 3 * 2] ={1.0f,1.0f,0.0f,1.0f,0.0f,0.0f,1.0f,1.0f,0.0f,0.0f,1.0f,0.0f,};glEnableClientState(GL_TEXTURE_COORD_ARRAY);glEnable(GL_TEXTURE_2D);3D GRAPHICS USING OPENGL ES229GLuint textureArray[1];glGenTextures(1, textureArray);glBindTexture(GL_TEXTURE_2D, textureArray[0]);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);aTexture.LockHeap();glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,aTexture.SizeInPixels().iWidth,aTexture.SizeInPixels().iHeight,0, GL_RGB, GL_UNSIGNED_BYTE,aTexture.DataAddress());aTexture.UnlockHeap();glEnableClientState(GL_VERTEX_ARRAY);glVertexPointer(3, GL_BYTE, 0, triangles);glTexCoordPointer(2, GL_FLOAT, 0, texCoords);glDrawArrays(GL_TRIANGLES, 0, 6);glDisableClientState(GL_TEXTURE_COORD_ARRAY);eglSwapBuffers(iEglDisplay, iEglSurface);}What may go wrong when you do this: The pixels in the texturemay actually be read as BGR data, instead of RGB.