Computer graphics -- 2008-2009 -- info.uvt.ro/Laboratory 4

From Wikiversity

Jump to: navigation, search

Quick links: front; laboratories agenda, 1, 2, 3, 4, 5, JOGL template.


Contents

[edit] (J)OGL BASICS (PART 3)

NOTE: Grab the application template from the following link: Computer graphics -- 2008-2009 -- info.uvt.ro/JOGL-Template

[edit] Textures

A texture is a rectangular array of data containing information about color, luminance, color and alpha. Each element in this array is called a texel.

Textures can be 1D, 2D or 3D (used to simulate certain characteristics in the material they depict)

Texture mapping allows one to glue together an image of an object on a polygon. For example images of walls, vegetation, landscapes, etc. NOTE: besides being applied to polygons textures could be also applied to other primitives such as points, lines, polygons, bitmaps and images. It implies mapping texture coordinates to geometric coordinates.

NOTE: you can download textures from the following link: [1].

Links:

[edit] Creating and displaying 2D textures

The steps involved in generating a 2D texture are as follows:

  • Generate a name for our texture using glGenTextures function (method)
  • Bind (select) our texture in a target. The target is in our case GL_TEXTURE_2D but can also take other values such as GL_TEXTURE_3D or GL_TEXTURE_1D. The binding is accomplished by using the glBindTexture function (method)
  • Specify the pixel storage mode by using the glPixelStorei function (method). This affects how the pixels stored in memory are read
  • Define the filters used when the texture is scaled (resized) during the drawing by using the glTexParameteri function (method)
  • Construct the texture with the representation of the picture file by using either glTexImage2D or gluBuild2DMipmaps functions (methods) depending on whether we want mipmaps (multiple levels of detail in our texture) or not
  • Enable GL_TEXTURE_2D by using the glEnable function (method)
  • Render the texture by assigning vertex coordinates to texture coordinates. The texture coordinates are usually given inside the [0, 1] interval. One can specify a texture coordinate by using the glTexCoord2* family functions (methods)

NOTE: an alternate method for generating textures by using the Texture and TextureIO classes is presented at the following link: Computer_graphics -- 2007-2008 -- info.uvt.ro/Laboratory 5.

Important: texture size must be a power of 2 (32x32, 64x64, 512x128, etc) for the texture loader to work properly. Failing to provide a power of 2 texture size will result in an error.

The following code fragments exemplifies the previous steps (IMPORTANT - Please be sure to download and copy the classes found inside the following arhive: http://www.info.uvt.ro/~mfrincu/textureManager.zip):

// Import the GLU class so that we can use them.
import javax.media.opengl.glu.GLU;
 
public class MainFrame [...] {
 
 
	[...]
 
	private final int NO_TEXTURES = 1;
	private int texture[] = new int[NO_TEXTURES];
	TextureReader.Texture[] tex = new TextureReader.Texture[NO_TEXTURES];
 
	// GLU object used for mipmapping.
	private GLU glu;
 
	public void init(GLAutoDrawable canvas)
	{
		[...]
 
		// Create a new GLU object.
		glu = new GLU();
 
		// Generate a name (id) for the texture.
	        gl.glGenTextures(1, texture, 0);
		// Bind (select) the texture.
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
 
		// Read the texture from the image.
		try {
			tex[0] = TextureReader.readTexture("path/to/your/image/here");
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
 
		// Define the filters used when the texture is scaled.
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
 
		// Construct the texture and use mipmapping in the process.
		this.makeRGBTexture(gl, glu, tex[0], GL.GL_TEXTURE_2D, true);
 
		// Do not forget to enable texturing.
		gl.glEnable(GL.GL_TEXTURE_2D);
 
		[...]
	}
 
	public void display(GLAutoDrawable canvas)
	{
		[...]
 
		// Bind (select) the texture
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
 
		// Draw a square and apply a texture on it.
		gl.glBegin(GL.GL_QUADS);
			// Lower left corner.
			gl.glTexCoord2f(0.0f, 0.0f);
			gl.glVertex2f(0.1f, 0.1f);
 
			// Lower right corner.
			gl.glTexCoord2f(1.0f, 0.0f);
			gl.glVertex2f(0.9f, 0.1f);
 
			// Upper right corner.
			gl.glTexCoord2f(1.0f, 1.0f);
			gl.glVertex2f(0.9f, 0.9f);
 
			// Upper left corner.
			gl.glTexCoord2f(0.0f, 1.0f);
			gl.glVertex2f(0.1f, 0.9f);
		gl.glEnd();
 
		[...]
	}
 
	private void makeRGBTexture(GL gl, GLU glu, TextureReader.Texture img, int target, boolean mipmapped) {     
	        if (mipmapped) {
			glu.gluBuild2DMipmaps(target, GL.GL_RGB8, img.getWidth(), img.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
		} else {
			gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(), img.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
		}
	}
 
	[...]
}

Textures can also be repeated or clamped:

  • repeated - copies of the texture map tile the surface
  • clamped - a single copy of the image appears on a large surface

The previous techniques are useful when one decides to give texture coordinates outside the [0, 1] interval.

 
	[...]
 
	public void init(GLAutoDrawable canvas)
	{
		[...]
 
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
		gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);
 
		[...]
	}
 
	[...]

Links:

[edit] Replacing parts of a texture with another

(J)OGL allows one to replace parts of a texture with another. This technique is also used for improving performance as replacing a texture is much faster than rebuilding it each time.

The following code fragment shows how one can replace a texture with another. Be sure to generate 2 textures inside init, and change NO_TEXTURES = 1 with NO_TEXTURES = 2 inside your code before testing it.

 
	[...]
 
	public void display(GLAutoDrawable canvas)
	{
		[...]
 
		// Replace all of our texture with another one.
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
		gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, tex[0].getWidth(), tex[0].getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, tex[1].getPixels());
 
		[...]
	}
 
	[...]

Links:

[edit] Anisotropic Fitering

Mipmapping often produces blurred images for distant textures viewed at oblique angles. This is due to the fact that texture mapping mode assumes the texture space is a square (isotropic) while in reality it is rather long and narrow (anisotropic). To overcome this problem one could apply anisotropic filtering as detailed in the following code fragment:

 
	[...]
 
	public void init(GLAutoDrawable canvas)
	{
		[...]
 
		if( gl.isExtensionAvailable("GL_EXT_texture_filter_anisotropic") )   
		{
			float max[] = new float[1];
			gl.glGetFloatv( GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max, 0 );
 
			gl.glTexParameterf( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, max[0] );
		}
 
		[...]
	}
 
	[...]

[edit] Texture transparency and blending

Blending means combining two or more textures by mixing their components.

Transparency means making some pixels transparent. The transparency factor can range from opaque to fully transparent.

[edit] Steps for blending
  • Enable blending by using the glEnable(GL.GL_BLEND) function (method)
  • Set the blend function by using the glBlendFunc(mode, mode) function (method)
  • Draw the object(s)
  • disabling blending by using the gl.glDisable(GL.GL_BLEND) function (method)

Note: (for 3D graphics) there are cases when you need to disable the depth test while blending, by using the glEnable(GL_DEPTH_TEST) and glDisable(GL_DEPTH_TEST) functions (methods)

[edit] Steps for transparency (alpha testing)
  • Enable alpha testing by using the glEnable(GL_ALPHA_TEST) function (method)
  • Set alpha testing by using the glAlphaFunc(GL_GREATER, 0.7f) function (method) which tells OGL to discard the pixels with an alpha value greater then 0.7 (for example)


 
	[...]
 
	public void display(GLAutoDrawable canvas)
	{
		[...]
 
		// Disable blending for this texture.
		gl.glDisable(GL.GL_BLEND);
 
		// Bind (select) the texture
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
 
		// Draw a square and apply a texture on it.
		gl.glBegin(GL.GL_QUADS);
			// Lower left corner.
			gl.glTexCoord2f(0.0f, 0.0f);
			gl.glVertex2f(0.1f, 0.1f);
 
			// Lower right corner.
			gl.glTexCoord2f(1.0f, 0.0f);
			gl.glVertex2f(0.9f, 0.1f);
 
			// Upper right corner.
			gl.glTexCoord2f(1.0f, 1.0f);
			gl.glVertex2f(0.9f, 0.9f);
 
			// Upper left corner.
			gl.glTexCoord2f(0.0f, 1.0f);
			gl.glVertex2f(0.1f, 0.9f);
		gl.glEnd();
 
		// Enable blending for this texture.
		gl.glEnable(GL.GL_BLEND);
 
		// Set the blend function.
		gl.glBlendFunc(GL.GL_SRC_COLOR, GL.GL_DST_ALPHA);
 
		// Bind (select) the texture
		gl.glBindTexture(GL.GL_TEXTURE_2D, texture[2]);
 
		// Draw a square and apply a texture on it.
		gl.glBegin(GL.GL_QUADS);
			// Lower left corner.
			gl.glTexCoord2f(0.0f, 0.0f);
			gl.glVertex2f(0.1f, 0.1f);
 
			// Lower right corner.
			gl.glTexCoord2f(1.0f, 0.0f);
			gl.glVertex2f(0.9f, 0.1f);
 
			// Upper right corner.
			gl.glTexCoord2f(1.0f, 1.0f);
			gl.glVertex2f(0.9f, 0.9f);
 
			// Upper left corner.
			gl.glTexCoord2f(0.0f, 1.0f);
			gl.glVertex2f(0.1f, 0.9f);
		gl.glEnd();
 
		[...]
	}
 
	private void makeRGBTexture(GL gl, GLU glu, TextureReader.Texture img, int target, boolean mipmapped) {     
	        if (mipmapped) {
			glu.gluBuild2DMipmaps(target, GL.GL_RGB8, img.getWidth(), img.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
		} else {
			gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(), img.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels());
		}
	}
 
	[...]

Links:

[edit] API

[edit] Exercises

  • Create a square and place a texture on it. Try playing with the glCullFace function (method) and notice what happens.
  • Create a separate class called TextureHandler for generating a texture and test it by loading and displaying two textures. The class should have the following methods:
    • a method called bind() for binding (selecting) the texture. Wrapper for gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);.
    • a method called enable() for enabling the texture. Wrapper for gl.glEnable(GL.GL_TEXTURE_2D);.
    • a method called disable() for disabling the texture. Wrapper for gl.glDisable(GL.GL_TEXTURE_2D);.
    • a method called getTexture() for retrieving the TextureReader.Texture object.
    • a constructor called TextureHandler(GL gl, GLU glu, String filename, boolean mipmapped) for generating the texture. Much of the code in the init method presented at the beginning of this lab goes in there. The constructor should receive as argument a reference to the GL and GLU objects, the path to the image and a boolean argument which specifies whether mipmapping should be used or not.
    • a private method makeRGBTexture(...) as the one presented in this laboratory.
  • Replace a section of the previous texture with another one.
  • Create two squares on top of each other, apply two textures to them and set up blending.