!/usr/bin/env python
#coding:utf-8
# [2019-08-24]
"""
@@@ 3D空間を戦車のように移動
@@@ ドラッグ量により回転量、移動量が決まる
@@@ ドラッグ位置で左右前後する
@@@ 上を変更してドラッグする方向により進行方向を変える
@@@ 鳥瞰できるようにする。-> 難しい
"""
# 参考サイト
# walkthrogh.c
#A. ウォークスルーの実験
#https:#komori.issp.u-tokyo.ac.jp/iimori/opengl/ex-a.html
#他参考サイト
#物理のかぎしっぽ
# http://hooktail.org/computer/index.php?OpenGL%BD%AC%BA%EE%A5%D7%A5%ED%A5%B0%A5%E9%A5%E0
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys
import math
objects = 0 # ディスプレイリスト番号 ダミーで0を入れる
RadToDeg = 0.01753 # 1度に対する1ラジアン
#後で画面サイズを格納する。ダミーで0を入れる
ww =0
hh =0
#ハンドルを切る角度
theta = 0.0
thetam = 0.0
#画面上位置ドラッグで前進 下位置ドラッグで後退
#V = 0.0 # 進行方向に対する速度
t = 0.01 #回転量、移動量を調整するパラメータ
# 視点の位置
ex = 0.0
ez = 0.0
ey = 0.0
# 速度ベクトルVを x,y成分に分解して前後左右の移動量を決める
#Vx = 0.0
#Vz = 0.0
#Vy = 0.0
# 視点の向き 回転量
r = 0.0
r2 = 0.0
point = [[0, 0], [0, 0]] #xz座標を記憶する配列 ダミーで要素2つ入れる
pointm = [[0, 0], [0, 0]] #y座標計算用 ダミーで0を入れる
flg_ldown = 0 #マウス左ボタンが押さていない
flg_mdown = 0 #マウス中ボタンが押さていない
def display(flg_ret=0):
#print "display"
global objects
global ex
global ez
global ey
global r
global r2
lightpos = [ 3.0, 4.0, 5.0, 1.0 ] # 光源の位置
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
#rは初期位置からの角度を決めるもので、rが一定数値ならその
#glRotated を2回実行したところで、2r回転するわけではない。
glRotated(r, 0.0, 1.0, 0.0) # y回転
glRotated(r2, 1.0, 0.0, 0.0) # x回転
glTranslated(ex, ey, ez) # 移動
glLightfv(GL_LIGHT0, GL_POSITION, lightpos) # 光源の位置
glCallList(objects) # シーンの描画
glutSwapBuffers()
def resize(w, h):
global ww
global hh
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60.0, w / h, 1.0, 1000.0)
glMatrixMode(GL_MODELVIEW)
ww = w
hh = h # 画面サイズを格納
def init2():
glClearColor(1 , 1 , 1 , 0);
def idle():
global t
#t += .0001 # 時間経過 時間経過による「変化」をやめる
#t = 0.0001
glutPostRedisplay()
def mouse(button, state, x, y):
print "mouse"
global point
global pointm
global flg_ldown
global flg_mdown
if button == GLUT_LEFT_BUTTON:
print "GLUT_LEFT_BUTTON"
if state == GLUT_DOWN:
flg_ldown = 1
point[0] = [x, y]
if state == GLUT_UP:
flg_ldown = 0
if button == GLUT_MIDDLE_BUTTON:
print "-----------------------"
if state == GLUT_DOWN:
flg_mdown = 1
pointm[0] = [x, y]
if state == GLUT_UP:
flg_mdown = 0
#プログラミング FAQ — Python 3.7.4 ドキュメント
#https://docs.python.org/ja/3/faq/programming.html
#関数の本体のどこかで値が変数に代入されたなら、明示的にグローバルである
#と宣言されない限り、ローカルであるとみなされます
#マウスドラッグ中のx,y座標
#xy ウィンドウ座標左上0,0 右下w,h ウィンドウの幅、高さ
#マウスドラッグを連続的にしているように思っても、その隙間で
#idleが実行displayが実行されている。
#ゆえにドラッグ中でも画面の景色が変化する。
def motion(x, y):
print "motion"
global point
global pointm
global flg_ldown
global flg_mdown
global theta
global thetam
#local variable "V" referenced before assignment
#上エラーがでるので 以下コード一行いれる。
V = 0
global RadToDeg
global t
global ex
global ez
global ey
#global Vx
#global Vz
#global Vy
global r
global r2
par1 = 10
par2 = 10
#前後左右関係-----------------------------
if flg_ldown == 1:
point[1] = [x, y]
x0 = point[0][0]
y0 = point[0][1]
x1 = point[1][0]
y1 = point[1][1]
#左へ向く
if x0 < x1:
#最後の*2はただの係数。元コードにあったのでそのまま
theta = -math.sqrt( (x0-x1)**2 + (y0-y1)**2 ) * 2
#右へ向く
if x0 > x1:
theta = math.sqrt( (x0-x1)**2 + (y0-y1)**2 ) * 2
r += theta * t
#スピードV
#前進
if y0 < y1:
V = abs(theta)/par1
#後退
if y0 > y1:
V = -abs(theta)/par1
# 以下バックに関しては上式でVに-が入る。
#2. 以下のif文のVx成分に関しては r<0 の時
#画面の左でドラッグすれば視点の向きrが-
#世界がVx+移動するのだから視点は-Vx移動する
if( r < 0 ):
Vx = V * math.sin(abs(r) * RadToDeg)#RadToDegラジアンに変換
Vz = V * math.cos(abs(r) * RadToDeg)
#3. 以下のelse文のVx成分に関しては r>0 の時であり
#画面の右でドラッグすれば視点の向きrが+
#世界がVx-移動するのだから視点はVx移動する
else:
Vx = -V * math.sin(abs(r) * RadToDeg)
Vz = V * math.cos(abs(r) * RadToDeg)
#前後左右の移動量を決める
ex += Vx * t
ez += Vz * t
#以下むずかしい。別の機会に
#y軸移動 鳥瞰関係回転-------------------------------
if flg_mdown == 1:
print "flg_mdown == 1:"
pointm[1] = [x, y]
x0m = pointm[0][0]
y0m = pointm[0][1]
x1m = pointm[1][0]
y1m = pointm[1][1]
#上へ向く
if y0m < y1m:
#最後の*2はただの係数。元コードにあったのでそのまま
thetam = -math.sqrt( (x0m-x1m)**2 + (y0m-y1m)**2 ) * 2
#下へ向く
if y0m > y1m:
thetam = math.sqrt( (x0m-x1m)**2 + (y0m-y1m)**2 ) * 2
r2 += thetam * t
if r2 < -90:
r2 = -89
if r2 > 90:
r2 = 89
print "r2", r2
#次は上下の移動
#スピードV
#上昇
if y0m < y1m:
V = abs(thetam)/par2
#下降
if y0m > y1m:
V = -abs(thetam)/par2
if( r2 < 0 ):
Vy = V * math.tan(abs(r2) * RadToDeg)
Vz = -V * math.cos(abs(r2) * RadToDeg)
if Vy > 100:
Vy = 100
else:
Vy = -V * math.tan(abs(r2) * RadToDeg)
Vz = V * math.cos(abs(r2) * RadToDeg)
if Vy < -100:
Vy = 100
#上の移動量を決める
ey += Vy * t
print "ey", ey
def MouseWheel(x, y):
print "MouseWheel"
pass
def keyboard(key, x, y):
if(key == '\033' or key == 'q'):
sys.exit() # ESC か q で終了
def scene():
global objects
# 物体の色
red = [ 0.8, 0.2, 0.2, 1.0 ]
green = [ 0.2, 0.8, 0.2, 1.0 ]
blue = [ 0.2, 0.2, 0.8, 1.0 ]
yellow = [ 0.8, 0.8, 0.2, 1.0 ]
ground = [
[ 0.6, 0.6, 0.6, 1.0 ],
[ 0.3, 0.3, 0.3, 1.0 ]
]
# 図形をディスプレイリストに登録
objects = glGenLists(1)
glNewList(objects, GL_COMPILE)
# 赤い箱
glPushMatrix()
glTranslated(0.0, 0.0, -6.0)
glMaterialfv(GL_FRONT, GL_DIFFUSE, red)
glutSolidCube(1.0)
glPopMatrix()
# 緑の箱
glPushMatrix()
glTranslated(0.0, 0.0, 6.0)
glMaterialfv(GL_FRONT, GL_DIFFUSE, green)
glutSolidCube(1.0)
glPopMatrix()
# 青い箱
glPushMatrix()
glTranslated(-6.0, 0.0, 0.0)
glMaterialfv(GL_FRONT, GL_DIFFUSE, blue)
glutSolidCube(1.0)
glPopMatrix()
# 黄色い箱
glPushMatrix()
glTranslated(6.0, 0.0, 0.0)
glMaterialfv(GL_FRONT, GL_DIFFUSE, yellow)
glutSolidCube(1.0)
glPopMatrix()
# 地面
glBegin(GL_QUADS)
glNormal3d(0.0, 1.0, 0.0)
for j in range(-20, 20):
for i in range(-20, 20):
glMaterialfv(GL_FRONT, GL_DIFFUSE, ground[(i + j) & 1])
glVertex3d(i, -0.5, j)
glVertex3d(i, -0.5, (j + 1))
glVertex3d((i + 1), -0.5, (j + 1))
glVertex3d((i + 1), -0.5, j)
glEnd()
glEndList()
def init():
# 初期設定
glClearColor(1.0, 1.0, 1.0, 0.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
glutInitWindowSize(600, 600)
glutCreateWindow("ウォークスルー")
glutDisplayFunc(display)
glutReshapeFunc(resize)
glutIdleFunc(idle)
#マウスドラッグ時に呼び出す関数
glutMotionFunc(motion)
glutMouseFunc(mouse)
glutKeyboardFunc(keyboard)
#以下のコールバックはマウスの移動に関するもの
#中ボタン押したままのマウスの移動は検知しないため殺す
#glutPassiveMotionFunc(move)
#以下の関数使えないようだ。殺す
#glutMouseWheelFunc(MouseWheel)
scene()
init()
glutMainLoop()
if __name__ == "__main__":
main()
0 件のコメント:
コメントを投稿