2019年8月31日土曜日

pyopengl pyopengl ウォークスルー 視点の移動 動き回る





!/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 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ブログ アーカイブ

ページ

Featured Posts