ラベル QTVR の投稿を表示しています。 すべての投稿を表示
ラベル QTVR の投稿を表示しています。 すべての投稿を表示

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

2008/06/09

The result of 360 degree cubic panorama player looks like this. Type keys to rotate/zoom the panorama image.
"s" home position
"a" rotate left
"d" rotate right
"w" rotate up
"x" rotate down
"-" zoom in
"+" zoom out

実行するとこんな感じで表示されます。キーボードを使って回転させます。

I should do the following thins to fix issues or enhance usability. 次のような点を改善しなければなりません。
1. Rotate -90 degree of the initial image
2. Use mouse rather than keyboard
3. Fix bugs of rotation
4. Limit the FOV not to show black portion

QTVR functionality usign OpenGL (1)

To display 360 degree cubic panorama movie, either QuickTime(QTVR) or Adobe Flash player is used as viewer. I like QTVR very much and I participate "World Wide Panorama" ten times, http://geoimages.berkeley.edu/worldwidepanorama/wwppeople/html/RikuichiKishimoto.html
360度キュービックVRの表示には通常QuickTime(QTVR)またはAdobe Flash Playerが使われます。私はQTVRの製作が趣味でして、World Wide Panoramaにも参加しています。

It would be very easy to implement 360 degree cubic panorama viewer using OpenGL. The source image has 6 cubic faces in one JPEG file.
OpenGLでキュービックパノラマを実現することは、割と簡単だと思われますので、やってみました。普通は次のような6面の画像を繋げたJPEGの画像を使いますが、簡単化のため6枚の別々の写真に分けました。
I manually cut the image into 6 pieces to simplify the OpenGL program.
Convert six JPEG files into six texture and attach to six cubic faces. It's very straight foward. The following code still have some bugs, but I can show you the basic idea. It's really a "inside rotating cube". まだバグなどがありますが、アイデアとしては次のようなものになります。


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

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))
uuu = 0.1
fov = 120
xzt = yzt = 0
yyy = math.sin(yzt)
r = math.cos(yzt)
zzz = r * math.sin(xzt)
xxx = r * math.cos(xzt)

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

def cube():
global texture
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, texture[4])
polygon(4,5,6,7)
glBindTexture(GL_TEXTURE_2D, texture[1])
polygon(1,5,4,0)
glBindTexture(GL_TEXTURE_2D, texture[2])
polygon(3,7,6,2)
glBindTexture(GL_TEXTURE_2D, texture[0])
polygon(0,4,7,3)
glBindTexture(GL_TEXTURE_2D, texture[5])
polygon(1,0,3,2)
glBindTexture(GL_TEXTURE_2D, texture[3])
polygon(2,6,5,1)

def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

glMatrixMode(GL_PROJECTION)
glLoadIdentity()

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

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

cube()
glFlush()

def mykey(key, x, y):
global xxx, yyy, zzz, fov, xzt, yzt
if key=='a': # -xzt
xzt = xzt - uuu
elif key=='d': # +xzt
xzt = xzt + uuu
elif key=='x': # -yzt
yzt = yzt - uuu
elif key=='w': # +yzt
yzt = yzt + uuu
elif key=='s': # default
xzt = yzt = 0.0

elif key=='-': # zoom out
fov = fov - 10
elif key=='+': # default
fov = fov + 10

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

print "xyzf:", xxx, yyy, zzz, fov
glutPostRedisplay()

def gentex(t, img):
# use the given texture
glBindTexture(GL_TEXTURE_2D, t)
print "texture", 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)

glutInit( sys.argv )
#glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH )
glutInitDisplayMode( GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH )
glutInitWindowSize( 500, 500 )
glutInitWindowPosition(0,0)
glutCreateWindow( 'cube' )
glutDisplayFunc( display )
glutKeyboardFunc(mykey)

glEnable(GL_DEPTH_TEST) #hidden-surface removal
# glEnable(GL_CULL_FACE) #don't draw back side surface
# glCullFace(GL_BACK) #don't draw back side surface

### TEXTURE
glEnable(GL_TEXTURE_2D)

# generate continuous two texture
# different format from C, void glGenTexture(n, *name)
texture=glGenTextures(6)

gentex(texture[0], "./pcube/r1.bmp")
gentex(texture[1], "./pcube/r2.bmp")
gentex(texture[2], "./pcube/r3.bmp")
gentex(texture[3], "./pcube/r4.bmp")
gentex(texture[4], "./pcube/rb.bmp")
gentex(texture[5], "./pcube/rt.bmp")

glutMainLoop()