Difference between revisions of "Project5SP15"

From Immersive Visualization Lab Wiki
Jump to: navigation, search
(Project 5: Textures and Scene Graphs)
(1. Sky Box (20 Points))
 
(35 intermediate revisions by 2 users not shown)
Line 1: Line 1:
DO NOT START YET - UNDER CONSTRUCTION
+
=Project 5: Android Army=
  
======================================
+
In this project you will practice the texturing of geometry, and you will implement your own scene graph, in order to render an army of androids.
  
=Project 5: Textures and Scene Graphs=
+
You can start out with your code from project 4. Don't worry if your mouse routines lights don't work perfectly, neither is required for this homework project.
 
+
In this project you will need to put textures on geometry, and create a scene graph data structure to render an army of androids.
+
 
+
You can start out with your code from project 3. Don't worry if your lights don't work perfectly, it will have no impact on this homework project.
+
 
   
 
   
 
The project is due on <b>Friday, May 8th, 2015 at 1:00pm</b>. You need to present your results in the CSE basement labs as usual, grading starts at 12:15pm.  
 
The project is due on <b>Friday, May 8th, 2015 at 1:00pm</b>. You need to present your results in the CSE basement labs as usual, grading starts at 12:15pm.  
Line 13: Line 9:
 
The homework discussion for this project will be on <b>Monday, May 4th</b>.
 
The homework discussion for this project will be on <b>Monday, May 4th</b>.
  
==1. Sky Box==
+
The total score for this project is 100 points, plus 10 for extra credit.
  
Embed your 3D models in a sky box. A sky box is a large box which is drawn around your entire scene and which your scene is inside of. The walls of the box have pictures of a sky and perhaps imagery at the horizon. Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. [http://www.f-lohmueller.de/pov_tut/skyboxer/skyboxer_3.htm Here is is a nice collection of textures for sky boxes].
+
==1. Sky Box (20 Points)==
  
Draw a cubic sky box around your patch by generating five sides of a cube (all but the bottom - the bottom side will be replaced by your patch) out of large textured GL_QUADS. Position and scale the box so that the patch is at its base, and it snugly hugs the patch.
+
Create a sky box for your androids to have a space to live in. A sky box is a large box which is drawn around your entire scene and which your scene is inside of. The walls of the box typically have pictures of a sky with clouds, objects in the distance, and the ground below the camera. But they can just as soon represent the interior of a building. Perhaps an alien spaceship?
  
Make sure single-sided rendering (triangle culling) is enabled with these lines somewhere in your code to ensure the box never occludes your patch:
+
Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. [http://www.f-lohmueller.de/pov_tut/skyboxer/skyboxer_3.htm Here is is a nice collection of textures for sky boxes], but there are many others all over the internet.
  
<pre>
+
Draw a cubic sky box by generating six sides of a cube out of large textured GL_QUADS. Position and scale the box so that its center is in the origin, and the walls of the cube are about 100 times farther apart than the width of your scene. Put the camera inside the sky box (so that you can see what is inside of it).
glEnable(GL_CULL_FACE);
+
glCullFace(GL_BACK);
+
</pre>
+
  
 
Use the following settings for your texture after your first <tt>glBindTexture</tt> for correct lighting and filtering settings:
 
Use the following settings for your texture after your first <tt>glBindTexture</tt> for correct lighting and filtering settings:
Line 40: Line 33:
 
</pre>
 
</pre>
  
To familiarize yourself with texture mapping in OpenGL, we provide a [[texture.cpp | sample program]], which loads a PPM file and uses it as a texture for a quad. If you decide to use one of the above referenced sky box images, you will have to convert them from JPEG to PPM format. The free image processing tool [http://www.irfanview.com IrfanView] for Windows will do this for you.
+
To familiarize yourself with texture mapping in OpenGL, we provide a [[texture.cpp | sample program]], which loads a PPM file and uses it as a texture for a quad. If you decide to use one of the above referenced sky box images, you will have to convert them from JPEG to PPM format. The free image processing tool [http://www.irfanview.com IrfanView] for Windows will do this for you. For Linux or Mac, we recommend [http://www.imagemagick.org/script/binary-releases.php ImageMagick].
  
Alternatively, you can use a third party library such as [http://lonesock.net/soil.html SOIL] to natively load JPEG images.
+
If you want to load image formats other than PPMs (e.g., JPEG or TIFF) directly into your application, link your code against a third party library such as [http://lonesock.net/soil.html SOIL].
  
==2. Scene Graph Engine==
+
'''Grading''':
 +
* -5 if the same texture shows up on all sides of the sky box
 +
* -5 if less than six texture files are loaded
 +
* -5 if all textures are loaded and displayed but they do not match up at the edges
  
Implement scene graph classes with the following hierarchy:
+
==2. Android Head (15 Points)==
 +
 
 +
Now it is time to create the head of an android. The first step is to create the geometry for it, along with texture coordinates. The easiest way to do this is to create a sphere or cylinder. [http://www.crackinwise.com/3d-tessellation-algorithms-in-c/ This web site] explains the algorithms and gives pseudo-code. Make sure you assign appropriate texture coordinates to each vertex, as well as normals. Refer to the course slides for how to generate texture coordinates for a sphere or cylinder.
 +
 
 +
Androids' faces typically look human-like. So we are going to use somebody's head shot as the texture. [www.cse.ucsd.edu/faculty_profile Here] is a good starting point for images, but you are free to use any image you would like.
 +
 
 +
==3. Scene Graph Engine (20 Points)==
 +
 
 +
To create the remaining body parts of the android (torso, arms, legs), we need to first implement a scene graph structure for our rendering engine. Use the following hierarchy:
  
 
[[Image:project4F14-scenegraph-half.jpg]]
 
[[Image:project4F14-scenegraph-half.jpg]]
  
The classes should have at least the following functionality (5 points for each class):
+
The classes should have at least the following functionality:
  
 
* Class <tt>Node</tt> should be abstract and serve as the common base class. It should implement an abstract draw method: <tt>virtual void draw(Matrix4 C) = 0</tt>, and also an abstract <tt>virtual void update() = 0</tt> method to separate bounding sphere updates from rendering.
 
* Class <tt>Node</tt> should be abstract and serve as the common base class. It should implement an abstract draw method: <tt>virtual void draw(Matrix4 C) = 0</tt>, and also an abstract <tt>virtual void update() = 0</tt> method to separate bounding sphere updates from rendering.
Line 56: Line 60:
 
* <tt>Geode</tt> should be an abstract class. It should set OpenGL's ModelView matrix to the current C matrix, and have an abstract render function to render its geometry.
 
* <tt>Geode</tt> should be an abstract class. It should set OpenGL's ModelView matrix to the current C matrix, and have an abstract render function to render its geometry.
 
* <tt>MatrixTransform</tt> should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method.
 
* <tt>MatrixTransform</tt> should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method.
* <tt>Sphere</tt> should have a draw function which draws a sphere. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutSolidSphere]</tt> for that.
+
* <tt>Sphere</tt> should have a draw function which draws a sphere. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutSolidSphere]</tt> for that, or use your own tessellation algorithm.
* <tt>Cube</tt> should have a draw function which draws a cube. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node82.html glutSolidCube]</tt> for that.
+
* <tt>Cube</tt> should have a draw function which draws a cube. You can use <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node82.html glutSolidCube]</tt> for that, or use your own implementation of a cube.
  
==3. Walking Robot==
+
'''Note:'''
 +
* If you created your android's head with a cylinder, you can replace the Cube class with your Cylinder class.
  
Demonstrate your scene graph functionality by constructing a walking robot.  
+
==4. Walking Android (30 Points)==
  
First get your rendering engine ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.
+
Now we are going to finish our android's geometry. First get your rendering engine ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.
  
The robot should have a torso, head, arms and legs. This means that the robot has to consist of at least '''6''' instances of <tt>Geode</tt>-derivatives. You can use the sphere and cube classes for the body parts, and add more shapes as you like (e.g., using any of [https://www.opengl.org/resources/libraries/glut/spec3/node80.html GLUT's pre-defined shapes]). Each <tt>Geode</tt>-derivative should have a <tt>MatrixTransform</tt> before it to position the body part(s) below it in the scene graph. You might want some of your basic shapes, such as spheres and cubes, elongated, rotated, or otherwise deformed, which you should do with separate <tt>MatrixTransform</tt> nodes for (non-uniform) scales, and/or rotations. Note that it is very common to concatenate multiple <tt>MatrixTransform</tt> nodes in a scene graph, each of which doing a separate affine transformation (e.g., one for position, one for scale, one to rotate). ('''20 points''')
+
Besides the head, the android should have a torso, arms and legs. This means that it has to consist of at least '''6''' instances of <tt>Geode</tt>-derivatives. You can use the sphere and cube classes for the body parts, and add more shapes as you like (e.g., using any of [https://www.opengl.org/resources/libraries/glut/spec3/node80.html GLUT's pre-defined shapes]). Each <tt>Geode</tt>-derivative should have a <tt>MatrixTransform</tt> before it to position the body part(s) below it in the scene graph. You might want some of your basic shapes, such as spheres and cubes, elongated, rotated, or otherwise deformed, which you should do with separate <tt>MatrixTransform</tt> nodes for (non-uniform) scales, and/or rotations. It is very common to concatenate multiple <tt>MatrixTransform</tt> nodes in a scene graph, each of which doing a separate affine transformation (e.g., one for position, one for scale, one to rotate - each separate MatrixTransforms).
  
Animate the robot to make it look like it is walking: move arms and legs back and forth by rotating around hip and shoulder joints. You can do this by re-calculating rotation matrices every frame by increasing or decreasing the respective angle by a small amount, up to a limit point at which you reverse the direction. ('''10 points''')
+
Animate the android to make it look like it is walking: move arms and legs back and forth by rotating around hip and shoulder joints. You can do this by re-calculating rotation matrices every frame by increasing or decreasing the respective angle by a small amount, up to a limit point at which you reverse the direction.
  
==4. Robot Army==
+
==5. Android Army (15 Points)==
  
Test your implementation by constructing a scene which consists of a sufficiently large amount of your robots to speed up rendering when object culling is used.  
+
Test your implementation by constructing a scene which consists of a large amount of androids, at least 100. The androids can all be identical clones, or you can use different pictures for their heads, or even vary the geometry.
  
* Distribute the robots on a 2D grid (i.e., place them on a plane with uniform spacing). (5 points)
+
* Distribute the androids on a 2D grid (i.e., place them on a plane with uniform spacing). For 100 androids, use a 10x10 grid of them.
  
* Choose the camera parameters so that many of the robots are located outside of the view frustum (off-screen), so that object-level culling matters. (5 points)
+
* Enable the animation for your androids so that they look like they are walking.
  
* Use your rotation and scale routines to allow the user to rotate the grid of 3D objects and zoom in or out. (5 points)
+
* Enable your rotation, pan and scale routines (keyboard or mouse) to allow the user to rotate the grid of 3D objects and zoom in or out.
 
+
* Compare the frame rates with and without object-level culling by supporting the keyboard key 'c' to toggle culling on and off, and displaying the rendering rate (frames per second) in the console window for every frame (frames_per_second = 1/rendering_time). Tweak the number of robots, their spatial density, and your camera parameters until your frame rate is noticeably higher with culling enabled. (5 points)
+
 
+
'''Notes:'''
+
* All your robots need to be walking like in part 2. This means that you need to re-calculate the bounding spheres each frame.
+
* For the calculation of the view frustum bounding planes you may want to take a look at [http://www.lighthouse3d.com/tutorials/view-frustum-culling/ the Lighthouse3D web site].
+
  
 
This image illustrates the grid layout of the robots:
 
This image illustrates the grid layout of the robots:
Line 89: Line 88:
 
[[Image:robots.png]]
 
[[Image:robots.png]]
  
==5. Extra Credit: Optimization by Culling==
+
==6. Extra Credit (10 Points)==
 +
 
 +
There are two options for extra credit. '''Each''' of them gets you 10 points. (You cannot get more than 10 points total even if you do both.)
 +
 
 +
===A. Optimization by Culling===
 +
 
 +
The first option is to implement object level culling, to allow the existence of thousands of instances of your android, without having to render them all.
 +
 
 +
Calculate a bounding sphere (Vector3 for its center point, and a radius) for each of your androids, which contains all parts of the robot. Allow the display of the bounding spheres by rendering them as wireframe spheres with <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutWireSphere]</tt>. Enable a keyboard key to toggle the bounding spheres on and off.
 +
 
 +
'''Note:''' You do not need to find the tightest possible bounding spheres - that can be rather difficult. Just make them as tight as you reasonably can.
 +
 
 +
Add view frustum culling using the bounding spheres of the objects. If the bounding sphere of an object is completely outside of the view frustum, the object should be culled (not rendered). Your culling algorithm should make use of a utility function to test whether a bounding sphere intersects with a given plane (the planes of the view frustum), or whether the sphere is entirely on one side of the plane.
 +
 
 +
Enable a keyboard key to turn culling on and off.
 +
 
 +
Increase the amount of androids by orders of magnitude, by creating a larger array of them. A good portion of the array should be off screen for the culling to be effective. Display the rendering time per frame in your text window, and show that by turning culling on your rendering time decreases.
 +
 
 +
===B. Texturing of 3D Models===
 +
 
 +
This option allows you to practice how to texture more complex 3D models. Each of the two models gets you 5 points.
 +
 
 +
====Cow====
 +
 
 +
Load this [http://ivl.calit2.net/wiki/files/cow.obj 3D model file of a cow].
 +
 
 +
Texture the cow with [[Media:cow.jpg | this texture]]. The cow model file does not come with texture coordinates, so you will need to generate them yourself. Use the following approach:
 +
 
 +
Calculate the 3D location of the center of the cow: find the minimum and maximum x, y and z coordinates across all vertices (i.e., the edges of the tightest axis parallel bounding box), and calculate its center point. This is the center of the sphere which you should shrink-wrap onto the cow's surface, as covered in class.
 +
 
 +
====Teapot====
  
Add a bounding sphere (Vector3 for its center point, and a radius) to your <tt>Node</tt> class, and implement code to update the bounding box parameters in all other classes of your scene graph. You also need to add code to your <tt>Node</tt> class to display each node's bounding sphere as a wireframe sphere with <tt>[https://www.opengl.org/documentation/specs/glut/spec3/node81.html glutWireSphere]</tt>. Support the 'b' key to toggle these bounding spheres on and off.
+
Load this [[Media:teapot.zip | 3D model of a teapot]]. Note that it comes with texture coordinates, so you will need to extend your OBJ reader code to parse texture coordinates.
  
'''Note:''' You do not need to find the smallest possible bounding sphere, but can use an approach similar to the one in homework assignment 2:
+
The goal is to texture the teapot with this [[Media:ucsd-logo.png| UCSD logo]]. The goal is to show the logo only on the kettle part of the teapot. When you first load it in using the texture coordinates from the file, the logo will cover the entire teapot including handle and spout, and it will be in the wrong place.
  
* Find minimum and maximum extents of your geometry in x,y and z (bounding box).
+
To get it into a more reasonable place, i.e., on the side of the teapot, you will need to apply an affine transformation to the texture coordinates you pass on to OpenGL. The best place to do this might be just before you pass them on to OpenGL between glBegin and glEnd.  
* The center of the bounding sphere is the center of the bounding box.
+
* The radius of the bounding sphere is equal to half the diameter of the bounding box.
+
  
Extend the <tt>Node</tt> class to perform view frustum culling using the bounding spheres of the objects. If the bounding sphere of an object is completely outside of the view frustum, the object should be culled (not rendered). Your culling algorithm should make use of a utility function to test whether a bounding sphere intersects with a given plane, or whether the sphere is entirely on one side of the plane.
+
Note that you should use glTexParameter GL_CLAMP_TO_EDGE, so that the logo's edge color (white) fills the rest of the teapot.

Latest revision as of 14:34, 7 May 2015

Contents

Project 5: Android Army

In this project you will practice the texturing of geometry, and you will implement your own scene graph, in order to render an army of androids.

You can start out with your code from project 4. Don't worry if your mouse routines lights don't work perfectly, neither is required for this homework project.

The project is due on Friday, May 8th, 2015 at 1:00pm. You need to present your results in the CSE basement labs as usual, grading starts at 12:15pm.

The homework discussion for this project will be on Monday, May 4th.

The total score for this project is 100 points, plus 10 for extra credit.

1. Sky Box (20 Points)

Create a sky box for your androids to have a space to live in. A sky box is a large box which is drawn around your entire scene and which your scene is inside of. The walls of the box typically have pictures of a sky with clouds, objects in the distance, and the ground below the camera. But they can just as soon represent the interior of a building. Perhaps an alien spaceship?

Sky boxes are typically cubic, which means that they consist of six square textures for the six sides of a cube. Here is is a nice collection of textures for sky boxes, but there are many others all over the internet.

Draw a cubic sky box by generating six sides of a cube out of large textured GL_QUADS. Position and scale the box so that its center is in the origin, and the walls of the cube are about 100 times farther apart than the width of your scene. Put the camera inside the sky box (so that you can see what is inside of it).

Use the following settings for your texture after your first glBindTexture for correct lighting and filtering settings:

  // Make sure no bytes are padded:
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  // Select GL_MODULATE to mix texture with polygon color for shading:
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  // Use bilinear interpolation:
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

To familiarize yourself with texture mapping in OpenGL, we provide a sample program, which loads a PPM file and uses it as a texture for a quad. If you decide to use one of the above referenced sky box images, you will have to convert them from JPEG to PPM format. The free image processing tool IrfanView for Windows will do this for you. For Linux or Mac, we recommend ImageMagick.

If you want to load image formats other than PPMs (e.g., JPEG or TIFF) directly into your application, link your code against a third party library such as SOIL.

Grading:

  • -5 if the same texture shows up on all sides of the sky box
  • -5 if less than six texture files are loaded
  • -5 if all textures are loaded and displayed but they do not match up at the edges

2. Android Head (15 Points)

Now it is time to create the head of an android. The first step is to create the geometry for it, along with texture coordinates. The easiest way to do this is to create a sphere or cylinder. This web site explains the algorithms and gives pseudo-code. Make sure you assign appropriate texture coordinates to each vertex, as well as normals. Refer to the course slides for how to generate texture coordinates for a sphere or cylinder.

Androids' faces typically look human-like. So we are going to use somebody's head shot as the texture. [www.cse.ucsd.edu/faculty_profile Here] is a good starting point for images, but you are free to use any image you would like.

3. Scene Graph Engine (20 Points)

To create the remaining body parts of the android (torso, arms, legs), we need to first implement a scene graph structure for our rendering engine. Use the following hierarchy:

Project4F14-scenegraph-half.jpg

The classes should have at least the following functionality:

  • Class Node should be abstract and serve as the common base class. It should implement an abstract draw method: virtual void draw(Matrix4 C) = 0, and also an abstract virtual void update() = 0 method to separate bounding sphere updates from rendering.
  • Group should store a list of pointers to child nodes (std::list<Node*>) and provide functionality to add and remove child nodes (addChild(), removeChild()). Its draw method needs to traverse the list of children and call each child node's draw function.
  • Geode should be an abstract class. It should set OpenGL's ModelView matrix to the current C matrix, and have an abstract render function to render its geometry.
  • MatrixTransform should store a 4x4 transformation matrix M which is multiplied with matrix C, which is passed to the draw method.
  • Sphere should have a draw function which draws a sphere. You can use glutSolidSphere for that, or use your own tessellation algorithm.
  • Cube should have a draw function which draws a cube. You can use glutSolidCube for that, or use your own implementation of a cube.

Note:

  • If you created your android's head with a cylinder, you can replace the Cube class with your Cylinder class.

4. Walking Android (30 Points)

Now we are going to finish our android's geometry. First get your rendering engine ready to recursively traverse the scene graph for rendering by creating a root node of type Group and calling its draw() function with the identity matrix as its parameter.

Besides the head, the android should have a torso, arms and legs. This means that it has to consist of at least 6 instances of Geode-derivatives. You can use the sphere and cube classes for the body parts, and add more shapes as you like (e.g., using any of GLUT's pre-defined shapes). Each Geode-derivative should have a MatrixTransform before it to position the body part(s) below it in the scene graph. You might want some of your basic shapes, such as spheres and cubes, elongated, rotated, or otherwise deformed, which you should do with separate MatrixTransform nodes for (non-uniform) scales, and/or rotations. It is very common to concatenate multiple MatrixTransform nodes in a scene graph, each of which doing a separate affine transformation (e.g., one for position, one for scale, one to rotate - each separate MatrixTransforms).

Animate the android to make it look like it is walking: move arms and legs back and forth by rotating around hip and shoulder joints. You can do this by re-calculating rotation matrices every frame by increasing or decreasing the respective angle by a small amount, up to a limit point at which you reverse the direction.

5. Android Army (15 Points)

Test your implementation by constructing a scene which consists of a large amount of androids, at least 100. The androids can all be identical clones, or you can use different pictures for their heads, or even vary the geometry.

  • Distribute the androids on a 2D grid (i.e., place them on a plane with uniform spacing). For 100 androids, use a 10x10 grid of them.
  • Enable the animation for your androids so that they look like they are walking.
  • Enable your rotation, pan and scale routines (keyboard or mouse) to allow the user to rotate the grid of 3D objects and zoom in or out.

This image illustrates the grid layout of the robots:

Robots.png

6. Extra Credit (10 Points)

There are two options for extra credit. Each of them gets you 10 points. (You cannot get more than 10 points total even if you do both.)

A. Optimization by Culling

The first option is to implement object level culling, to allow the existence of thousands of instances of your android, without having to render them all.

Calculate a bounding sphere (Vector3 for its center point, and a radius) for each of your androids, which contains all parts of the robot. Allow the display of the bounding spheres by rendering them as wireframe spheres with glutWireSphere. Enable a keyboard key to toggle the bounding spheres on and off.

Note: You do not need to find the tightest possible bounding spheres - that can be rather difficult. Just make them as tight as you reasonably can.

Add view frustum culling using the bounding spheres of the objects. If the bounding sphere of an object is completely outside of the view frustum, the object should be culled (not rendered). Your culling algorithm should make use of a utility function to test whether a bounding sphere intersects with a given plane (the planes of the view frustum), or whether the sphere is entirely on one side of the plane.

Enable a keyboard key to turn culling on and off.

Increase the amount of androids by orders of magnitude, by creating a larger array of them. A good portion of the array should be off screen for the culling to be effective. Display the rendering time per frame in your text window, and show that by turning culling on your rendering time decreases.

B. Texturing of 3D Models

This option allows you to practice how to texture more complex 3D models. Each of the two models gets you 5 points.

Cow

Load this 3D model file of a cow.

Texture the cow with this texture. The cow model file does not come with texture coordinates, so you will need to generate them yourself. Use the following approach:

Calculate the 3D location of the center of the cow: find the minimum and maximum x, y and z coordinates across all vertices (i.e., the edges of the tightest axis parallel bounding box), and calculate its center point. This is the center of the sphere which you should shrink-wrap onto the cow's surface, as covered in class.

Teapot

Load this 3D model of a teapot. Note that it comes with texture coordinates, so you will need to extend your OBJ reader code to parse texture coordinates.

The goal is to texture the teapot with this UCSD logo. The goal is to show the logo only on the kettle part of the teapot. When you first load it in using the texture coordinates from the file, the logo will cover the entire teapot including handle and spout, and it will be in the wrong place.

To get it into a more reasonable place, i.e., on the side of the teapot, you will need to apply an affine transformation to the texture coordinates you pass on to OpenGL. The best place to do this might be just before you pass them on to OpenGL between glBegin and glEnd.

Note that you should use glTexParameter GL_CLAMP_TO_EDGE, so that the logo's edge color (white) fills the rest of the teapot.