画像の上書き


テクスチャの置き換え

ポリゴンにテクスチャを貼り付けることによって、より複雑な3次元グラフィックスを表現できます
しかし、テクスチャ・オブジェクトの生成はそれなりの負荷がかかります
テクスチャを動的に変化させる場合、テクスチャ・オブジェクトの生成と削除を繰り返しますが
これはあまり効率的な方法だとはいえません

できることなら、新しいオブジェクトを生成するのではなく
現在のテクスチャ・オブジェクトの画像を上書きしたほうが効率的だと考えられます
glTexImage2D() で設定したテクスチャ・オブジェクトの画像を更新するには
2次元テクスチャ画像を上書きするglTexSubImage2D() 関数を使います
void glTexSubImage2D(
	GLenum target, GLint level, 
	GLint xoffset, GLint yoffset,
	GLsizei width, GLsizei height,
	GLenum format, GLenum type, const GLvoid *pixels  
);
target には必ず GL_TEXTURE_2D を指定します
level は 0 を基準とした詳細番号を指定します

xoffset にはテクスチャ画像の x 座標を、yoffset には y 座標それぞれピクセル単位で指定します
ここで指定した座標から、新しい画像が配列に対して上書きされます
この座標は、画像の左下を原点 (0 , 0) としています

width には画像の幅、height には高さを、それぞれピクセル単位で指定します
format にはピクセル・データのフォーマットを、type にはデータ型をそれぞれ指定します
これらは glDrawPixels() の format と type 引数と同じです
pixels には、新しく設定する画像を表す配列へのポインタを指定します

幸い、glTexSubImage2D() の画像サイズは glTexImage2D() と異なり自由に指定できます
2の累乗以外の画像サイズのテクスチャを作る場合にも有効となるでしょう

画像のサイズを変更するには GLU の gluScaleImage() 関数を使うと便利です
int gluScaleImage(
	GLenum format, GLint widthin, GLint heightin, 
	GLenum typein, const void * datain, 
	GLint widthout, GLint heightout,
	GLenum typeout, void * dataout         
);
format にはピクセル・データのフォーマットを指定します
この引数も、glDrawPixels() 関数の format と同じです

widthin には元画像の幅を、heightin には元画像の高さをピクセル単位で指定します
typein には、入力する元画像のデータ形式を指定します
datain に、元画像が格納されている配列へのポインタを指定します

widthout には新しい画像の幅を、heightout には高さをピクセル単位で指定します
typeout は、新しい画像のデータ形式を指定します
dataout に、新しい画像のデータを保存するバッファへのポインタを指定します
このバッファは、新しい画像を格納する十分なサイズが必要です

関数が成功すれば 0 が、そうでなければ GLU のエラーコードを返します
GLU のエラーコードについては、この場では説明しません
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#define TEXSIZE 64
#define SUBTEX_SIZE TEXSIZE / 2

GLubyte pixels[TEXSIZE][TEXSIZE][3];
GLubyte dest[SUBTEX_SIZE][SUBTEX_SIZE][3];
GLuint texName;

void disp( void ) {
	glClear(GL_COLOR_BUFFER_BIT);
	glBindTexture(GL_TEXTURE_2D , texName);

	glBegin(GL_POLYGON);
		glTexCoord2f(0 , 0); glVertex2f(-0.9 , -0.9);
		glTexCoord2f(0 , 1); glVertex2f(-0.9 , 0.9);
		glTexCoord2f(1 , 1); glVertex2f(0.9 , 0.9);
		glTexCoord2f(1 , 0); glVertex2f(0.9 , -0.9);
	glEnd();
	glFlush();
}

int main(int argc , char ** argv) {
	unsigned int i , j;

	for (i = 0 ; i < TEXSIZE ; i++) {
		int r = (i * 0xFF) / TEXSIZE;
		for (j = 0 ; j < TEXSIZE ; j++) {
			pixels[i][j][0] = (GLubyte)r;
			pixels[i][j][1] = (GLubyte)(( j * 0xFF ) / TEXSIZE);
			pixels[i][j][2] = (GLubyte)~r;
		}
	}

	glutInit(&argc , argv);
	glutInitWindowSize(400 , 300);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
	
	glutCreateWindow("Kitty on your lap");
	glutDisplayFunc(disp);

	glEnable(GL_TEXTURE_2D);
	glGenTextures(1 , &texName);
	glBindTexture(GL_TEXTURE_2D , texName);

	glTexImage2D(
		GL_TEXTURE_2D , 0 , 3 , TEXSIZE , TEXSIZE ,
		0 , GL_RGB , GL_UNSIGNED_BYTE , pixels
	);
	gluScaleImage(
		GL_RGB , TEXSIZE , TEXSIZE , GL_UNSIGNED_BYTE , pixels ,
		SUBTEX_SIZE , SUBTEX_SIZE , GL_UNSIGNED_BYTE , dest
	);
	glTexSubImage2D(
		GL_TEXTURE_2D , 0 , SUBTEX_SIZE / 2 , SUBTEX_SIZE  / 2,
		SUBTEX_SIZE , SUBTEX_SIZE , GL_RGB , GL_UNSIGNED_BYTE , dest
	);

	glutMainLoop();

	glDeleteTextures(1 , &texName);
	return 0;
}


このプログラムは、テクスチャ画像の中央に
同じ画像を縮小した画像を glTexSubImage2D() を用いて上書きしています
新しい画像を生成するよりも、このほうが簡単で、高速に動作します



前のページへ戻る次のページへ