メタセコ風味のカメラ
#!/usr/bin/python
# coding: utf-8
from OpenGL.GL import *
from OpenGL.GLU import *
import baseview
class RokuroView(baseview.BaseView):
def __init__(self, distance):
super(RokuroView, self).__init__()
self.w=1
self.h=1
self.head=0
self.pitch=0
self.distance=distance
self.shiftX=0
self.shiftY=0
self.aspect=1
self.n=1
self.f=10000
def onResize(self, w=None, h=None):
super(RokuroView, self).onResize(w, h)
self.aspect=float(self.w)/float(self.h)
def dolly(self, d):
if d>0:
self.distance*=1.1
elif d<0:
self.distance*=0.9
def shift(self, dx, dy):
self.shiftX+=dx
self.shiftY+=dy
def rotate(self, head, pitch):
self.head+=head
self.pitch+=pitch
def updateProjection(self):
gluPerspective(30, self.aspect, self.n, self.f)
def updateView(self):
glTranslate(self.shiftX, self.shiftY, -self.distance)
glRotate(self.head, 0, 1, 0)
glRotate(self.pitch, 1, 0, 0)
def onMotion(self, x, y):
redraw=False
if self.isLeftDown:
self.dolly(y-self.y)
redraw=True
if self.isMiddelDown:
self.shift(x-self.x, self.y-y)
redraw=True
if self.isRightDown:
self.rotate(x-self.x, y-self.y)
redraw=True
self.x=x
self.y=y
return redraw
def onWheel(self, d):
if d!=0:
self.dolly(d)
return True
if __name__=="__main__":
import glut_ui
import Cube
import glbase
glut_ui.run(
glbase.BaseController(
RokuroView(80),
Cube.createCube(10)))
頂点情報から頂点配列を組み立てる
#!/usr/bin/python
# coding: utf8
from OpenGL.GL import *
import glut_ui
import glbase
import Rokuro
import vertexarray
import mqo
def build(loader):
vertices=[]
indices=[]
offset=0
for o in loader.objects:
if o.name.startswith("anchor"):
continue
if o.name.startswith("bone:"):
continue
if o.name.startswith("MCS:"):
continue
print o.name
for v in o.vertices:
vertices.append(v)
for f in o.faces:
if f.vertexCount==3:
indices.append(offset+f.V[0])
indices.append(offset+f.V[1])
indices.append(offset+f.V[2])
elif f.vertexCount==4:
# triangle 1
indices.append(offset+f.V[0])
indices.append(offset+f.V[1])
indices.append(offset+f.V[2])
# triangle 2
indices.append(offset+f.V[2])
indices.append(offset+f.V[3])
indices.append(offset+f.V[0])
offset+=len(o.vertices)
return vertexarray.IndexedVertexArray(vertices, indices)
if __name__=="__main__":
import sys
import time
if len(sys.argv)<2:
print "usage: %s {mqo file}" % sys.argv[0]
sys.exit()
t=time.time()
l=mqo.Loader()
if not l.load(sys.argv[1]):
sys.exit()
print time.time()-t, "sec"
print l
glut_ui.run(glbase.BaseController(
Rokuro.RokuroView(400), build(l)))
非常に遅くなるので、numpyの配列を使うことで高速化する
違うのは下記の部分だけ。
return vertexarray.IndexedVertexArray(
numpy.array(vertices, 'f'),
numpy.array(indices, 'u4'))
頂点配列をマテリアルで分割。分割された頂点配列ごとにマテリアルを適用する
class Material(object):
def __init__(self, r, g, b, a):
self.r=r
self.g=g
self.b=b
self.a=a
def begin(self):
glColor4f(self.r, self.g, self.b, self.a)
def end(self):
pass
def onInitialize(self):
pass
@staticmethod
def create(src):
m=material.Material(*src.col)
return m
#!/usr/bin/python
# coding: utf8
from OpenGL.GL import *
import glut_ui
import glbase
import Rokuro
import mqo
import material
import vertexarraymap
def build(loader):
vertexArrayMap=vertexarraymap.VertexArrayMap(
[material.Material.create(m) for m in loader.materials])
for o in loader.objects:
if o.name.startswith("anchor"):
continue
if o.name.startswith("bone:"):
continue
if o.name.startswith("MCS:"):
continue
for f in o.faces:
if f.vertexCount==3:
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[0]],
o.vertices[f.V[1]],
o.vertices[f.V[2]]
)
elif f.vertexCount==4:
# triangle 1
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[0]],
o.vertices[f.V[1]],
o.vertices[f.V[2]]
)
# triangle 2
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[2]],
o.vertices[f.V[3]],
o.vertices[f.V[0]]
)
vertexArrayMap.optimize()
return vertexArrayMap
if __name__=="__main__":
import sys
import time
if len(sys.argv)<2:
print "usage: %s {mqo file}" % sys.argv[0]
sys.exit()
# load scenee
t=time.time()
l=mqo.Loader()
if not l.load(sys.argv[1]):
sys.exit()
print time.time()-t, "sec"
# build
print l
view=Rokuro.RokuroView(400)
root=build(l)
glut_ui.run(glbase.BaseController(view, root))
頂点配列にUV属性を追加する。
class VertexArrayWithUV(object):
def __init__(self, vertices, uvarray):
self.vertices=vertices
self.uvarray=uvarray
def __str__(self):
return "<VertexArrayWithUV %d>" % len(self.vertices)
def draw(self):
# 位置属性
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertices)
# UV属性
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glTexCoordPointer(2, GL_FLOAT, 0, self.uvarray)
# 描画
glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))
# 後始末
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
PILを使ったテクスチャ読み込み。
#!/usr/bin/python
# coding: utf-8
import Image
from OpenGL.GL import *
class Texture(object):
def __init__(self, path):
self.path=path
self.image=None
def onInitialize(self):
if not self.image:
self.loadImage()
assert(self.image)
if self.createTexture():
return True
def loadImage(self):
self.image=Image.open(self.path)
if self.image:
print "load image:", self.path
return True
else:
print "failt to load image:", self.path
return False
def createTexture(self):
self.texture=glGenTextures(1)
if self.texture==0:
print "fail to glGenTextures"
return False
channels=len(self.image.getbands())
w, h=self.image.size
glBindTexture(GL_TEXTURE_2D, self.texture)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
if channels==4:
print "RGBA"
glPixelStorei(GL_UNPACK_ALIGNMENT, 4)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h,
0, GL_RGBA, GL_UNSIGNED_BYTE, self.image.tostring())
elif channels==3:
print "RGB"
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h,
0, GL_RGB, GL_UNSIGNED_BYTE, self.image.tostring())
def begin(self):
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, self.texture)
def end(self):
glDisable(GL_TEXTURE_2D)
バックフェイスカリングとアルファテストの有効化。
class MQOMaterial(object):
def __init__(self, r, g, b, a):
self.r=r
self.g=g
self.b=b
self.a=a
self.texture=None
def begin(self):
glColor4f(self.r, self.g, self.b, self.a)
if self.texture:
self.texture.begin()
# backface culling
glEnable(GL_CULL_FACE)
glFrontFace(GL_CW)
glCullFace(GL_BACK)
# alpha test
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5);
def end(self):
if self.texture:
self.texture.end()
def onInitialize(self):
if self.texture:
self.texture.onInitialize()
@staticmethod
def create(src, basedir):
m=MQOMaterial(*src.col)
if src.tex:
m.texture=texture.Texture((basedir+'/'+src.tex).replace('\\', '/'))
return m
UV属性の組み込みと、テクスチャ対応マテリアルの構築。
#!/usr/bin/python
# coding: utf8
from OpenGL.GL import *
import os
import material
import vertexarraymap
def build(loader):
basedir=os.path.dirname(loader.path)
vertexArrayMap=vertexarraymap.VertexArrayMapWithUV(
[material.MQOMaterial.create(m, basedir)
for m in loader.materials])
for o in loader.objects:
if o.name.startswith("anchor"):
continue
if o.name.startswith("bone:"):
continue
if o.name.startswith("MCS:"):
continue
for f in o.faces:
if f.vertexCount==3:
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[0]],
o.vertices[f.V[1]],
o.vertices[f.V[2]],
f.UV[0:6]
)
elif f.vertexCount==4:
# triangle 1
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[0]],
o.vertices[f.V[1]],
o.vertices[f.V[2]],
f.UV[0:6]
)
# triangle 2
vertexArrayMap.addTriangle(
f.M,
o.vertices[f.V[2]],
o.vertices[f.V[3]],
o.vertices[f.V[0]],
f.UV[4:8]+f.UV[0:2]
)
vertexArrayMap.optimize()
return vertexArrayMap
if __name__=="__main__":
import sys
import time
import glut_ui
import glbase
import Rokuro
import mqo
if len(sys.argv)<2:
print "usage: %s {mqo file}" % sys.argv[0]
sys.exit()
# load scenee
t=time.time()
l=mqo.Loader()
if not l.load(sys.argv[1]):
sys.exit()
print time.time()-t, "sec"
# build
print l
view=Rokuro.RokuroView(400)
root=build(l)
glut_ui.run(glbase.BaseController(view, root))