Planning the Spontaneous

It's more than just a blueprint.

RenderToTexture() { RenderToTexture(); }

Posted by Robert Chow on 09/10/2009

Rendering To Texture

Ever since I started, I’ve been given the task of rendering an image to a texture, and then to render it onto the screen.  And to be honest, I never really got the hang of it.  And I still kind of haven’t.  But it’s been a couple of months now, and I’m managed to grab hold of it by the thread.  Check this out.

RenderingToTextureRendering To Texture.  This effect is done by taking a snapeshot of the cube, and then rendering the image onto the cube itself, as it rotates.  Psychedelic, some might say.

Cool huh?!  So how’s it done?!

We need to render the cube, then copy that to a texture.  This texture is then renderered onto each face of the cube itself, and does so each time the display loop is called – creating a mise en abîme.  This is done using mainly two functions, but before we call those functions, we have to set up the texture first.

int texSize = 256;
byte[] texture = new byte[4 * texSize * texSize];
int textureId;

Gl.glGenTextures(1, out textureId);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureId);
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, texSize, texSize, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, texture);
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);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP);

These calls initialize the texture – it is asking for a texture of size texSize * texSize (these have to be a power of 2 (although not so necessarily anymore these days)), and bind to a reference, textureId.  I’m still playing around a bit with the parameters for glTexImage2D – like I said, I’m only just starting to get to grips with this.  As far as I’m aware, the last 4 parameter calls are saying that when the texture is far away, and very close, render them using a smooth algorithm; and that the texture should not be repeated in either the X or Y direction (S and T in texture terms).  But again, I’m not too sure.

So the first of the function calls is the actual drawing of the cube.  If we draw this in immediate mode – where we define all the vertices – we have to preceed each one with a texture coordinate beforehand, so we know which part of the texture to bind to that vertex.  Of course, if there is no texture available, then the texture coordinate call is ignored, and the vertrex renderered as normal.  I’m not going to show you the whole code, but here is an example of one of the faces.

Gl.glTexCoord2i(0, 0); Gl.glColor3f(1.0f, 1.0f, 0.0f); Gl.glVertex3f(-1, -1, -1);
Gl.glTexCoord2i(1, 0); Gl.glColor3f(0.0f, 1.0f, 0.0f); Gl.glVertex3f(-1, -1, 1);
Gl.glTexCoord2i(1, 1); Gl.glColor3f(0.0f, 1.0f, 1.0f); Gl.glVertex3f(1, -1, 1);
Gl.glTexCoord2i(0, 1); Gl.glColor3f(1.0f, 1.0f, 1.0f); Gl.glVertex3f(1, -1, -1);

Now that we’ve got the cube, we have to be able to render it, copy it to a texture, then render it again, using the texture.  Before we can use the texture however, we do need to enable texturing – this is a simple call.

Gl.glEnable(Gl.GL_TEXTURE_2D);

So first we render the scene, appropriate to copy to the texture.

Gl.glClearColor( 1.0f, 1.0f, 1.0f, 0.0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);

Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glLoadIdentity();
Glu.gluPerspective(45, 1, 0.1f, 10);
Gl.glViewport(0, 0, texSize, texSize);

Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
Gl.glTranslatef(0, 0, -5);
Gl.glRotatef(alpha, 0.75f, 1, 0.5f);

DrawCube();
Gl.glFlush();

Gl.glCopyTexSubImage2D(Gl.GL_TEXTURE_2D, 0, 10, 10, 0, 0, texSize -20, texSize -20);

This code first sets clears the scene as per usual, asking for a white background.  Secondly, it adjusts the projection matrix so it is suitable for the texture.  Thirdly it processes the model matrix so the cube can renderered appropriately onto the screen.  It is also taking in the variable alpha for its rotation adjustment.  Lastly, it draws the cube, and then copies the image onto the texture.  There are two different calls to copy an image to a texture, and the one I have used here is to only a copy the image to a sub-part of the texture.  I have done this so I can get a border to the texture without much trouble.  I need this border, otherwise the cube will disappear into itself, and I won’t know where the original cube is in comparison to the textured cubes.  Confused?  I am, a little.  This call is often also used when devising a texture-atlas.  A texture-atlas is a texture full of many different textures, mostly unrelated.  Instead of having to change texture to be drawn, you just change the coordinates pointing to the image in the texture.  This is a lot quicker and less-expensive way of using textures.

Now that we have our texture.  We just render the cube again, but this time, without copying the final output to texture – this one goes to the device context, aka the screen!

Advertisements

One Response to “RenderToTexture() { RenderToTexture(); }”

  1. […] notice that the lines at the end of the code above is a lot different to the code where I render to texture again and again.  This is because this method incorporates mipmapping.  Mipmapping is the process of taking a […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: