2009/02/19

Cube Map

I found an interesting web page in nVIDIA. It is the biggest advantage of OpenGL CubicVR viwer compared to QTVR or Flash player based viewers.

OpenGLについて調べていた時、nVIDIA社の中で次のようなページを見つけました。これはCubicVRと鏡面反射モデルを用いた写り込みのテクスチャーマップですね。

http://developer.nvidia.com/object/cube_map_ogl_tutorial.html

たとえば砂漠でCubicVRを撮影し、自分の好きな車のモデル作ってCubicVRの箱の中に入れれば、車の窓には砂漠の景色が見事に映り込むはずです。車を回転させれば、映り込みも変わる。これはOpenGLを使う意味がありそうです。テレビゲームではきっと既に使われているのかもしれませんね。

CTRL, ALT and SHIFT

I found glut doesn't provide functionality to detect SHIFT or CTRL key is down. It's for only when some other key was pushed. Please see the web page below.

http://www.lighthouse3d.com/opengl/glut/index.php?5

先日の疑問についてですが、やはりSHIFTやCTRLキーが押されたかどうかだけを判断する機能をglutは持っていないようです。あくまでも他のキーが押された時にのみの判定だそうです。

-----------------------
CTRL, ALT and SHIFT

Sometimes we may want to know if one modifier key, i.e. CTRL, ALT or SHIFT is being pressed. GLUT provides a function that detects if any modifier is being pressed. This function should only be called inside the functions that process keyboard or mouse input events. The syntax for this function is:

int glutGetModifiers(void);
-----------------------

2009/02/18

cubeGL V1.0 dirty code

The first version of CubicVR Viewer "cubeGL" is now working. It still a dirty code.

一応CubicVR Viewer "cubeGL"が動きましたので、まだ汚いコードですが、参考になればと思い掲載します。本当はもっときれいなコードにしてから掲載したかったのですが、コードをきれいにすると動かなくなります。これをもとに、一から書き直した方が早いかもしれませんね。改良点としては、
1. glutMotionFunc( )を使ってマウスでグリグリ回せるようにした。
2. glutIdleFunc()を使って、マウスを放しても慣性力で回り続けるようにした。

# cube-GL V1.0 - still dirty code, but has minimum functionality set
# A Python/Open-GL based cubic VR viewer
# By R.Kishimoto 2009.2.18

import sys
import math
import Image
import time
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

tex_size = 256
window_size = (500, 500)
input_file_name = "./pcube/sj256.jpg"
mx=my=0
gx=gy=0
mod = 0
now = past = 0
xspeed = yspeed = 0

def prep_tex (pfname):
global rc, image_x
im=Image.open(pfname)
size=im.size
image_x = size[0]
image_y = size[1]

if image_x*6 == image_y:
print "good y = 6x"
else:
print "error y != 6x"
sys.exit

rc = image_x / tex_size
rc_mod = image_x % tex_size
if rc_mod != 0:
rc = rc + 1

for face in range(6):
for y in range(rc):
for x in range(rc):
x1 = tex_size*x
x2 = x1 + tex_size
y1 = face * image_x + tex_size * y
y2 = y1 + tex_size

box = (x1, y1, x2, y2)
region = im.crop(box)
fname = '%s%d%d%d%s' % (pfname, face, y, x, ".jpg")
region.save(fname)
print (face, y, x, x1, y1, x2, y2, fname)

fov = 120
vertices = ((-1.0, 1.0, -1.0), (1.0, 1.0, -1.0), (1.0, -1.0, -1.0), (-1.0, -1.0, -1.0),
(-1.0, 1.0, 1.0), (1.0, 1.0, 1.0), (1.0, -1.0, 1.0), (-1.0, -1.0, 1.0))

def polygon(a, b, c, d):
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3fv(vertices[a])
glTexCoord2f(1.0, 0.0)
glVertex3fv(vertices[b])
glTexCoord2f(1.0, 1.0)
glVertex3fv(vertices[c])
glTexCoord2f(0.0, 1.0)
glVertex3fv(vertices[d])
glEnd()

def cube():
ti = 0
step = 2.0 * 256.0 / 1000.0
glEnable(GL_TEXTURE_2D)

for y in range(rc):
for x in range(rc):
x1 = -1 + step * x
x2 = x1 + step
y1 = 1 - step * y
y2 = y1 - step
#print "x1,x2,y1,y2,step,ti", x1, x2, y1, y2, step, ti
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(0,1,2,3)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(x1, y1, -1.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(x2, y1, -1.0)
glTexCoord2f(1.0, 1.0)
glVertex3f(x2, y2, -1.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(x1, y2, -1.0)
glEnd()
ti=ti+1

for y in range(rc):
for x in range(rc):
x1 = -1 + step * x
x2 = x1 + step
y1 = 1 - step * y
y2 = y1 - step
#print "x1,x2,y1,y2,step,rc", x1, x2, y1, y2, step, rc
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(1,5,6,2)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, y1, x1)
glTexCoord2f(1.0, 0.0)
glVertex3f(1.0, y1, x2)
glTexCoord2f(1.0, 1.0)
glVertex3f(1.0, y2, x2)
glTexCoord2f(0.0, 1.0)
glVertex3f(1.0, y2, x1)
glEnd()
ti=ti+1

for y in range(rc):
for x in range(rc):
x1 = 1 - step * x
x2 = x1 - step
y1 = 1 - step * y
y2 = y1 - step
#print "x1,x2,y1,y2,step,rc", x1, x2, y1, y2, step, rc
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(5,4,7,6)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(x1, y1, 1.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(x2, y1, 1.0)
glTexCoord2f(1.0, 1.0)
glVertex3f(x2, y2, 1.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(x1, y2, 1.0)
glEnd()
ti=ti+1

for y in range(rc):
for x in range(rc):
x1 = 1 - step * x
x2 = x1 - step
y1 = 1 - step * y
y2 = y1 - step
#print "x1,x2,y1,y2,step,rc", x1, x2, y1, y2, step, rc
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(4,0,3,7)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(-1.0, y1, x1)
glTexCoord2f(1.0, 0.0)
glVertex3f(-1.0, y1, x2)
glTexCoord2f(1.0, 1.0)
glVertex3f(-1.0, y2, x2)
glTexCoord2f(0.0, 1.0)
glVertex3f(-1.0, y2, x1)
glEnd()
ti=ti+1

for y in range(rc):
for x in range(rc):
x1 = -1 + step * x
x2 = x1 + step
y1 = 1 - step * y
y2 = y1 - step
#print "x1,x2,y1,y2,step,rc", x1, x2, y1, y2, step, rc
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(4,5,1,0)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(x1, 1.0, y1)
glTexCoord2f(1.0, 0.0)
glVertex3f(x2, 1.0, y1)
glTexCoord2f(1.0, 1.0)
glVertex3f(x2, 1.0, y2)
glTexCoord2f(0.0, 1.0)
glVertex3f(x1, 1.0, y2)
glEnd()
ti=ti+1

for y in range(rc):
for x in range(rc):
x1 = -1 + step * x
x2 = x1 + step
y1 = -1 + step * y
y2 = y1 + step
#print "x1,x2,y1,y2,step,rc", x1, x2, y1, y2, step, rc
glBindTexture(GL_TEXTURE_2D, texture[ti])
#polygon(3,2,6,7)
glBegin(GL_POLYGON)
glTexCoord2f(0.0, 0.0)
glVertex3f(x1, -1.0, y1)
glTexCoord2f(1.0, 0.0)
glVertex3f(x2, -1.0, y1)
glTexCoord2f(1.0, 1.0)
glVertex3f(x2, -1.0, y2)
glTexCoord2f(0.0, 1.0)
glVertex3f(x1, -1.0, y2)
glEnd()
ti=ti+1

def drawText( value, x,y, windowHeight, windowWidth, step = 18 ):
"""Draw the given text at given 2D position in window
"""
glMatrixMode(GL_PROJECTION);
# For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
# glPushMatrix()
matrix = glGetDouble( GL_PROJECTION_MATRIX )

glLoadIdentity();
glOrtho(0.0, windowHeight or 32, 0.0, windowWidth or 32, -1.0, 1.0)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glClearColor(1.0, 1.0, 1.0, 0.0)

glBegin(GL_LINES)
glColor3f(1.0, 1.0, 1.0)
glVertex2i(x, y+20)
glVertex2i(x+60, y+20)
glVertex2i(x+60, y)
glVertex2i(x+60, y+20)
glVertex2i(x, y)
glVertex2i(x, y+20)
glEnd()

glRasterPos2i(x, y);
lines = 0
for character in value:
if character == '\n':
glRasterPos2i(x, y-(lines*18))
else:
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(character));
glPopMatrix();
glMatrixMode(GL_PROJECTION);
# For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
# glPopMatrix();
glLoadMatrixd( matrix ) # should have un-decorated alias for this...

glMatrixMode(GL_MODELVIEW);

def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glViewport(0, 0, window_size[0], window_size[1])

glMatrixMode(GL_PROJECTION)
glLoadIdentity()

# set camera FOV=100 degree, aspect=1.0, near=0.01(0.0 will cause error), far=100.0
gluPerspective(fov, 1.0, 0.01, 100.0)

glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# eye, at, up
gluLookAt(0.0, 0.0, 0.0, xxx, yyy, zzz, 0, 1, 0)

cube()

drawText( 'ksmt', 430, 1, window_size[0], window_size[1] )
drawText( 'Z-OUT', 360, 1, window_size[0], window_size[1] )
drawText( 'Z-IN', 290, 1, window_size[0], window_size[1] )
drawText( 'DOWN', 220, 1, window_size[0], window_size[1] )
drawText( 'UP', 150, 1, window_size[0], window_size[1] )
drawText( '-->', 80, 1, window_size[0], window_size[1] )
drawText( '<--', 10, 1, window_size[0], window_size[1] )

glFlush()

def deg2rad(deg):
rad = math.pi * deg / 360
return rad

uuu = 10.0
fov = 120
xzd = -180
xyd = 0
xzt = deg2rad(xzd)
xyt = deg2rad(xyd)

yyy = math.sin(xyt)
zzz = math.sin(xzt) * math.cos(xyt)
xxx = math.cos(xzt) * math.cos(xyt)

def mykey(key, x, y):
global xxx, yyy, zzz, fov, xzd, xyd
print "key, mod ", key, glutGetModifiers()

if key=='a': # -xzt
xzd = xzd - uuu
elif key=='d': # +xzt
xzd = xzd + uuu
elif key=='x': # -xyt
if (xyd - uuu) >= -180 :
xyd = xyd - uuu
elif key=='w': # +xyt
if (xyd + uuu) <= 180:
xyd = xyd + uuu
elif key=='s': # default
xzd = -180.0
xyd = 0.0
fov = 120

elif key=='e': # zoom out
if fov <= 160:
fov = fov + 10
elif key=='z': # zoom in
if fov > 10:
fov = fov - 10

elif key=='-': # zoom out
if fov <= 160:
fov = fov + 10
elif key=='+': # zoom in
if fov >=10:
fov = fov - 10

xzt = deg2rad(xzd)
xyt = deg2rad(xyd)

yyy = math.sin(xyt)
zzz = math.sin(xzt) * math.cos(xyt)
xxx = math.cos(xzt) * math.cos(xyt)

glutPostRedisplay()

def mymouse(button, state, x, y):
global xxx, yyy, zzz, fov, xzd, xyd, start_x, start_y, gx, gy, mod
sy = window_size[1] - y
mod = glutGetModifiers()
#print "click button, state, x, y, mod--------", button, state, x , sy, mod
if state == 0 & button == 0:
start_x = x
start_y = sy
if ((10 < x) & (x < 70) & (sy < 20)):
xzd = xzd - uuu
print "left ", x, sy
elif ((80 < x) & (x < 140) & (sy < 20)):
xzd = xzd + uuu
print "right ", x, sy
elif ((150 < x) & (x < 210) & (sy < 20)):
if (xyd - uuu) >= -180 :
xyd = xyd + uuu
print "up ", x, sy
elif ((220 < x) & (x < 280) & (sy < 20)):
if (xyd + uuu) <= 180:
xyd = xyd - uuu
print "down ", x, sy
elif ((290 < x) & (x < 350) & (sy < 20)):
if fov <= 160:
fov = fov - 10
print "out ", x, sy
elif ((360 < x) & (x < 420) & (sy < 20)):
if fov > 10:
fov = fov + 10
print "in ", x, sy

gx = x
gy = sy

xzt = deg2rad(xzd)
xyt = deg2rad(xyd)

yyy = math.sin(xyt)
zzz = math.sin(xzt) * math.cos(xyt)
xxx = math.cos(xzt) * math.cos(xyt)

prev_state = state

glutPostRedisplay()


def gentex(t, img):
# use the given texture
glBindTexture(GL_TEXTURE_2D, t)

# read texture data from .bmp file using Image library
image=Image.open(img)
if len(image.getbands())!=4:
image=image.convert("RGBA")
size=image.size

# generate texture from array image.tostring() inside current texture 'texture'
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, image.tostring())

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

def mymotion(x, y):
global xxx, yyy, zzz, fov, xzd, xyd, start_x, start_y, gx, gy, mod, now, past, xspeed, yspeed
y = window_size[1]-y
#print "motion xy, frist_flag, gx, gy, mod", x, y, gx, gy, mod

dx = x - gx
dy = y - gy
xzd = xzd + dx
if ((xyd + dy) >= -180) & ((xyd + dy) <= 180):
xyd = xyd + dy

now = time.time()
dtime = now - past
if dtime == 0:
xspeed = yspeed = 0
else:
xspeed = 0.9 * dx / dtime
yspeed = 0.9 * dy / dtime

speedlimit = 200.0
if xspeed > speedlimit :
xspeed = speedlimit
elif xspeed < ( -1 * speedlimit) :
xspeed = -1 * speedlimit

if yspeed > speedlimit:
yspeed = speedlimit
elif yspeed < (-1 * speedlimit) :
yspeed = -1 * speedlimit

#print "xspeed, yspeed", xspeed, yspeed
past = now

if mod==GLUT_ACTIVE_SHIFT: # zoom in
if fov > 10:
fov = fov - 1
elif mod==GLUT_ACTIVE_CTRL: # zoom out
if fov <= 160:
fov = fov + 1

xzt = deg2rad(xzd)
xyt = deg2rad(xyd)

yyy = math.sin(xyt)
zzz = math.sin(xzt) * math.cos(xyt)
xxx = math.cos(xzt) * math.cos(xyt)

glutPostRedisplay()
gx = x
gy = y

def myidle():
global now, past, xspeed, yspeed, xxx, yyy, zzz, fov, xzd, xyd
now = time.time()
dtime = now - past

dy = dtime * yspeed
if ((xyd + dy) >= -180) & ((xyd + dy) <= 180):
xyd = xyd + dy
xzd = xzd + (dtime * xspeed)

xzt = deg2rad(xzd)
xyt = deg2rad(xyd)

yyy = math.sin(xyt)
zzz = math.sin(xzt) * math.cos(xyt)
xxx = math.cos(xzt) * math.cos(xyt)

glutPostRedisplay()
past = now
xspeed = xspeed * 0.99
yspeed = yspeed * 0.99

def myspecial( key, x, y ):
mod = glutGetModifiers()
print "special key, x, y, mod ", key, x, y, mod

glutInit( sys.argv )
#glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH )
glutInitDisplayMode( GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH )
glutInitWindowSize( window_size[0], window_size[1] )
glutInitWindowPosition(0,0)
glutCreateWindow( 'cube' )
glutDisplayFunc( display )
glutKeyboardFunc( mykey )
glutMouseFunc( mymouse )
glutMotionFunc( mymotion)
glutSpecialFunc( myspecial )
glutIdleFunc( myidle )
glEnable(GL_DEPTH_TEST)
#glEnable(GL_CULL_FACE)
#glCullFace(GL_BACK)
# prep_tex(input_file_name)

### TEXTURE
rc=4
tex_num=0
glEnable(GL_TEXTURE_2D)
texture=glGenTextures(rc*rc*6)
for face in range(6):
for y in range(rc):
for x in range(rc):
fname = '%s%d%d%d%s' % ("./pcube/sjtex", face, y, x, ".jpg")
gentex(texture[tex_num], fname)
#print 'reading texture %s %d' % (fname, tex_num)
tex_num = tex_num+1

#Menu
def selectMessage():
return 1
print "select message meny selected"

glutMainLoop()

#
# Six Cubic face global mapping
# 0-----1
# | |
# | F0 |
# 3-----2
# 1-----5
# | |
# | R1 |
# 2-----6
# 5-----4
# | |
# | B2 |
# 6-----7
# 4-----0
# | |
# | L3 |
# 7-----3
# 4-----5
# | |
# | U4 |
# 0-----1
# 3-----2
# | |
# | D5 |
# 7-----6
#
# 4-----5
# | |
# | U4 |
# 0-----1
# 4-----00-----11-----55-----4
# | || || || |
# | L3 || F0 || R1 || B2 |
# 7-----33-----22-----66-----7
# 3-----2
# | |
# | D5 |
# 7-----6
#
# local texture mapping
#
# 0.0----------------------------1.0
# |-----------image_x--------------|
# |--tex_size--|
# |<-- (tex_size/image_x) * 0
# |<-- (tex_size/image_x) * 1
# |<-- (tex_size/image_x) * 2

cannot detect SHIFT key status while doing anything else

Other CubicVR viewers use SHIFT ket for zoom in and CTRL key for zoom out. However, I cannto find any ways to do this in OpenGL. If I push some other key or mouse button while pushing down SHIFT key, I can detect it by useing glutGetModifiers(). But, if I just push SHIFT key, no event detected by OpenGL even in glutIdleFunc(). glutSpecialFunc() doesn't detect SHIFT key. I found some people are asking the same question in web, but I couldn't find any good answere yet. If you know how I can detect SHIFT key event, please let me know.

普通のCubicVR Viewerでは、シフトキーを押すとズームイン、コントロールキーを押すとズームアウトなのですが、OpenGLでうまく実装できていません。シフトキーを押しながら何かすれば(他のキーを押す、マウスボタンを押す)glutGetModifiersでshift, ctrl, altキーが同時に押されたことが分かるのですが、ただシフトキーが押されただけという状態を検出できないのです。シフトキーを押しながらマウスを動かしても、ボタンを押さない限り検出できません。glutSpecialFunc()もシフトキーは認識しません。Webで探しても、同じ質問をしている人は何人か見つかるのですが、誰も回答をもらっていないようです。ご存じの方がおられたら、教えて下さい。

glutKeyboardFunc( mykey ) --- can detect shift key down stat
glutMouseFunc( mymouse ) --- can detect shift key down stat
glutMotionFunc( mymotion) --- can NOT detect
glutSpecialFunc( myspecial ) --- can
glutIdleFunc( myidle ) --- can NOT

まあ、とりあえず、マウスを押したときにシフトキーを押していれば、パンと一緒にズームインするようにしました。まあ、これでも使用上は問題ありませんが、他のソフトとの共通性の問題が残ります。

glutMotionFunc

By using glutMotionFunc, I can smoothly move camera direction, panning camera. Please refer the following sample code. Since glutMotionFunc is activated only after the first move of mouse, glutMouseFunc( mymouse ) shold be used to get the point you clicked the mouse button.

glutMotionFuncを使って、マウスのボタンを押しながらマウスを動かすことによって、スムースにカメラの方向を変えられるようになりました。OpenGLの入門書を読んでも今ひとつはっきりしないのですが、下のようにやれば簡単です。glutMotionFuncはマウスを動かした後の座標しかレポートしませんので、マウスボタンを押した時の座標はglutMouseFunc( mymouse ) から取得しなければなりません。

gx=gy=0

def mymouse(button, state, x, y):
global gx, gy
y = window_size[1] - y
gx = x
gy = y

def mymotion(x, y):
global gx, gy
y = window_size[1] - y
dx = x - gx
dy = y - gy
# calculation of global vars used in glutDisplayFunc( display )
glutPostRedisplay()
gx = x
gy = y

glutDisplayFunc( display )
glutMouseFunc( mymouse )
glutMotionFunc( mymotion)

2009/02/17

Text display for menu button

I couldn't add bitmap text for my menu button on Python/OpenGL. By some reason, I cannot use glutBitmapCharacter(). I couldn't find any information on Web. Finally, I found an example at,
Python25\Lib\site-packages\OpenGL\tests\test_glutwindow.py
Now, I can add some text, but I still cannot specify text color yet.

OpenGL/Pythonでメニューボタンを作ろうと思ったのですが、どうしてもうまくテキストが表示できません。教科書には次のように書いてあるのですが。
glWindowPos*()
glutBitmapCharacter( GLUT_BITMAP_8_BY_13, 'a')
これはPythonではエラーになってしまいます。

どうやらPythonでは、
glutBitmapCharacter( GLUT_BITMAP_8_BY_13, ord('a'))
らしいのですが、これもうまくいきません。

Webを見ても回答を得られません。これは困った。しょうがないので、PythonのOpenGLのライブラリの中にヒントがないかと探してみたところ、ありました。
Python25\Lib\site-packages\OpenGL\tests\test_glutwindow.py
です。これを見ると、


def drawText( value, x,y, windowHeight, windowWidth, step = 18 ):
"""Draw the given text at given 2D position in window
"""
glMatrixMode(GL_PROJECTION);
# For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
# glPushMatrix()
matrix = glGetDouble( GL_PROJECTION_MATRIX )

glLoadIdentity();
glOrtho(0.0, windowHeight or 32, 0.0, windowWidth or 32, -1.0, 1.0)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glRasterPos2i(x, y);
lines = 0
for character in value:
if character == '\n':
glRasterPos2i(x, y-(lines*18))
else:
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(character));
glPopMatrix();
glMatrixMode(GL_PROJECTION);
# For some reason the GL_PROJECTION_MATRIX is overflowing with a single push!
# glPopMatrix();
glLoadMatrixd( matrix ) # should have un-decorated alias for this...

glMatrixMode(GL_MODELVIEW);

drawText( 'hello', 20,20, size[0],size[1] )
#glutBitmapCharacter( GLUT_BITMAP_8_BY_13, ord('a'))


と書いてあります。これをそのままコピーして使うと、やっと文字が書けるようになったのでした。しかし、まだ文字の色が自由に決められないので完全ではありません。まあ、でも、これでOpenGLでメニューボタンを作るめどがたちました。

PIL (Python Image Library)による画像分割

For OpenGL texture mapping, only limited size picture can be accepted such as 128x128, and 256x256. I should cut large picture (such as 1500 x 9000) into smaller pieces such as 256 x 256
for OpenGL texture mapping. In Python, I can use PIL to do this. I included PIL sample and OpenGL sample to read the small jpeg files.

OpenGLのテクスチャーは128とか256とか512という2の累乗のサイズの画像しか受け付けません。CubicVRでは普通3000 x 3000ピクセルとかの画像を上下左右前後6枚使います。(私の使う画像は6枚が縦に繋がっています) jpegで保存された大きな画像をPythonで読みだして、複数の256x256の小さな画像に切り分け、またjpegで書き出すプログラムをPIL (Python Image Library)で作ってみました。これで、いくら大きな画像でもPython/OpenGLのCubicVR Viewerに読み込むことができます。ついでにOpenGLに読み込む時のPythonのサンプルもつけます。

#6枚の正方形画像が縦につながった大きな画像をtex_size x tex_sizeの小さな画像に分割して, jpegで保存

def prep_tex (pfname):
global rc, image_x
im=Image.open(pfname)
size=im.size
image_x = size[0]
image_y = size[1]

if image_x*6 == image_y:
print "good y = 6x"
else:
print "error y != 6x"
sys.exit

rc = image_x / tex_size
rc_mod = image_x % tex_size
if rc_mod != 0:
rc = rc + 1

for face in range(6):
for y in range(rc):
for x in range(rc):
x1 = tex_size*x
x2 = x1 + tex_size
y1 = face * image_x + tex_size * y
y2 = y1 + tex_size

box = (x1, y1, x2, y2)
region = im.crop(box)
fname = '%s%d%d%d%s' % (pfname, face, y, x, ".jpg")
region.save(fname)
print (face, y, x, x1, y1, x2, y2, fname)

# 分割されたjpegファイルを読みだして、OpenGLのTextureに変換
tex_num=0
glEnable(GL_TEXTURE_2D)
texture=glGenTextures(rc*rc*6)
for face in range(6):
for y in range(rc):
for x in range(rc):
fname = '%s%d%d%d%s' % ("./pcube/sjtex", face, y, x, ".jpg")
gentex(texture[tex_num], fname)
#print 'reading texture %s %d' % (fname, tex_num)
tex_num = tex_num+1