2019年8月8日木曜日

pyopengl 立方体が2つマウス操作で回転、 チェス盤のテクスチャを立方体に貼る





pyopengl

立方体が2つマウス操作で回転、 チェス盤のテクスチャを立方体に貼る
サイトの説明が難しく、関数の理解ができない。


#!/usr/bin/env python
#coding:utf-8
# [2019-08-02]

#参考サイト
#http://web.wakayama-u.ac.jp/~wuhy/GSS/07.html#8.1
#グラフィックス科学演習
#テクスチャ
"""
@@@ テクスチャ
@@@ 立方体の面にチェス盤テクスチャのマッピング
@@@ 各関数がなにをしているのか理解しがたい
"""
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys

#テクスチャの大きさを設定
checkImageWidht = 32
checkImageHeight = 32
#最大インデックス checkImage[31][31][4] = c
checkImage = [[[0 for i in range(4)] for i in
                range(checkImageHeight)]
                for k in range(checkImageWidht)]
"""
たとえば、2次元テクスチャマッピングの場合、テクスチャ座標は双方向に0.
0~1.0の範囲になりますが、テクスチャ処理されるオブジェクトの座標は任意
の座標をとることが可能です。
レンガの壁の例の場合、壁が正方形で1枚のテクスチャを表しているとき、プ
ログラムは壁の4隅にテクスチャ座標(0,0), (1,0), (1,1), (0,1)を割り当て
ます
"""
#テクスチャ座標指定用
texcoord = [
        [0.0, 0.0],
        [1.0, 0.0],
        [1.0, 1.0],
        [0.0, 1.0]
        ]

adjust_r = 5
r = 0

vertex = [
        [0.0, 0.0, 0.0 ],
        [1.0, 0.0, 0.0 ],
        [1.0, 1.0, 0.0 ],
        [0.0, 1.0, 0.0 ],
        [1.0, 0.0, 1.0 ],
        [0.0, 0.0, 1.0 ],
        [0.0, 1.0, 1.0 ],
        [1.0, 1.0, 1.0 ]
        ]
#OpenGL では,標準では,視点から見て頂点が左回りになっているとき,
#その面を表として扱う
#頂点を視点から見て右回り(時計回り)で結んでいます
#視点からというより視点に近い立方体内部から面を見た状態でしょう
#下のfaceを有効にするならglCullFace(GL_FRONT)を有効にする
#またはglFrontFace(GL_CW)とする
face = [
        [0, 1, 2, 3],
        [1, 4, 7, 2],
        [5, 0, 3, 6],
        [4, 5, 6, 7],
        [7, 6, 3, 2],
        [1, 0, 5, 4],
        ]
#立方体6面の表面法線ベクトル
#長さ1で面を表面から外への方向
normal = [
        [0.0, 0.0, -1.0],
        [1.0, 0.0, 0.0],
        [-1.0, 0.0, 0.0],
        [0.0, 0.0, 1.0],
        [0.0, 1.0, 0.0],
        [0.0, -1.0, 0.0],
        ]
#光源設定用 4つ目の要素は1.0にする
Light0pos = [0.0, 3.0, 5.0, 1.0]
Light1pos = [5.0, 3.0, 0.0, 1.0]
red = [1.0, 0.4, 0.3, 1.0]
blue= [0.2, 0.4, 1.0, 1.0]
yellow = [1.0, 1.0, 0.0, 1.0]

"""
void glTexCoord2dv( const GLdouble *v )
テクスチャを定義する座標空間は,2次元の s-t 空間で, s, t が 0.0~1.0
の範囲でテクスチャを定義します. この関数は,テクスチャ座標を s, t の
順で与える配列のポインタを指定します. テクスチャ座標は常に更新可能で
,glBegin と glEnd の間で有効です.
"""

#チェス盤テクスチャ生成
def makeCheckImage():
    global checkImageWidht
    global checkImageHeight
    global checkImage
    for i in range(checkImageWidht):
        for j in range(checkImageHeight):
            #ビット演算
            #c = ( ( (i&0x8)==0 )^( (j&0x8)==0 ) )*255;
            # 0x8 2進数1000 
            # ^ XOR abが異なる場合に1 同じ場合に0
            # i,jが2進数で4桁目が1でなく
            c = ( ( (i&0x8)==0 ) ^ ( (j&0x8)==0 ) )*255;#0 か1を返す
            checkImage[i][j][0] = c
            checkImage[i][j][1] = c
            checkImage[i][j][2] = c
            checkImage[i][j][3] = 255

#立方体を描く
def cube():
    glBegin(GL_QUADS)
    for j in range(6):
        glNormal3dv(normal[j])
        for i in range(4):
            glTexCoord2dv(texcoord[i])
            glVertex3dv(vertex[face[j][i]])
    glEnd()

def idle():
    glutPostRedisplay()
    #プログラム中でウィンドウの再描画イベントを発生させる
    #glutTimerFunc(50 , idle , 0)

"""
*glPixelStorei*(GL_UNPACK_ALIGNMENT, 1)
ピクセル格納モードを設定します. 引数 pname で指定できるのは20種類の定
数で, その値を引数 param で設定します. 通常は,上のプログラムのよう
に GL_UNPACK_ALIGNMENT を 1 と設定してください.


void *glTexParameteri*( GLenum target, GLenum pname, GLint param )
テクスチャマッピングでは,オブジェクトをテクスチャで包むことになります
が, どのように包みこむか,また, テクスチャのピクセルと画面のピクセル
の間に正確な対応がない場合に どのように処理するか,を指定します.

targetでは, GL_TEXTURE_1D または GL_TEXTURE_2D のいずれかを指定します

pname では, テクスチャのパラメータを表す定数を指定します.よく指定す
るものは, GL_TEXTURE_MIN_FILTER,GL_TEXTURE_MAG_FILTER,
GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T です. param では, pname の値を
指定します.

GL_TEXTURE_MIN_FILTER,GL_TEXTURE_MAG_FILTER の場合
param を GL_NEAREST や GL_LINEAR などに設定します. これは,テクスチャ
を縮小または拡大してマッピングする場合に, どのようなフィルタリングを
用いるかを指定するものです.GL_NEAREST では, テクスチャ処理するピクセ
ルの中心に最も近いテクスチャ要素の値を返し, GL_LINEAR ではテクスチャ
処理するピクセルの中心に最も近い4つのテクスチャ要素の 加重平均を返し
ます.

GL_TEXTURE_WRAP_S,GL_TEXTURE_WRAP_T の場合
paramu を GL_REPEAT か GL_CLAMP のいずれかに設定します. デフォルトは
GL_REPEAT で,テクスチャ座標が [0, 1] の範囲外の場合, テクスチャを反
復して貼り付けます.
GL_CLAMP では,0.0 よりも小さな値は 0.0 に設定さ れ, 1.0 よりも大きな
値は 1.0 に設定されます. この設定は,大きな面に1 枚だけテクスチャを表
示させたいときなどに有効です.

他にも pname で指定できるパラメータがあります.詳しくは,man
glTexParameteri を見てください.

void *glTexEnvi*( GLenum target, GLenum pname, GLfloat param )
テクスチャ環境のパラメータを設定します.
target: 必ず GL_TEXTURE_ENV にします.
pname: 必ず GL_TEXTURE_ENV_MODE にします.
param: GL_MODULATE,GL_DECAL,GL_BLEND,GL_REPLACE,GL_REPLACE_EXT,
GL_ADD の いずれかを指定します.
GL_DECAL では,テクスチャがない場合の ポリゴンの色を無視して テクス
チャをマッピングしますが,
GL_MODULATE や GL_BLEND の場合にはもとの ポリゴンの色と混合されます.
GL_BLEND では , 要素の数(glTexImage2Dを参照)が 1 と 2 のときしか定
義されていませ んが,
GL_MODULATE の場合には,1, 2, 3, 4 の全ての場合に定義されていま す.

void *glTexImage2D*( GLenum target, GLint level, GLint components,
GLsizei width, Glsizei height, GLint border, GLenum format, Glenum
type, const GLvoid *pixels )
2次元のテクスチャ画像を指定します.いろいろなパラメータ値を設定できま
す. 詳しくは man glTexImage2D を参照してください.
target: 必ず GL_TEXTURE_2D を指定します.
level: 詳細レベルの番号を指定します.レベル 0 は画像レベルの基準とな
り, レベル n は n 番目のミップマップ画像です. ミップマップ画像につい
ては,後で説明します.
components: テクスチャのカラー要素の数で,1(輝度),2(輝度と不透明
度),3(RGB), 4(RGB A(不透明度))のずれか,または, GL_ALPHA や
GL_RGBA などのシンボリック定数を指定します.
width,height: テクスチャのサイズを指定します. それぞれ "2**n + I*境
界の幅"(n は整数,I はほとんどの場合 1 )にしてください.
border: 境界の幅で, 0 か 1 を指定します.
format: データのフォーマットを指定します. GL_COLOR_INDEX, GL_RED,
GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA などが有効です.
type: データのタイプを指定します. GL_UNSIGNED_BYTE, GL_BYTE,
GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
GL_FLOAT などが有効です.
pixels: メモリ上の画像データのポインタを指定します.
void glTexCoord2dv( const GLdouble
"""

def init():
    global checkImageWidht
    global checkImageHeight
    global checkImage
    #白で画面クリア
    glClearColor(1.0, 1.0, 1.0, 0.0)
    #チェス盤テクスチャ生成
    makeCheckImage()
    #ピクセル格納モードを設定
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    """
    オブジェクトをテクスチャで包むことになりますが,
    どのように包みこむか,
    テクスチャのピクセルと画面のピクセルの間に正確な対応がない場合に,
    どのように処理するか,などの指定
    """
    #glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    #テクスチャ環境のパラメータを設定
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
    #2次元のテクスチャ画像を指定する
    glTexImage2D(GL_TEXTURE_2D, 0, 4, checkImageWidht,
            checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
            checkImage)
    #2次元テクスチャの処理を有効にする
    glEnable(GL_TEXTURE_2D)

    glEnable(GL_DEPTH_TEST)

    glEnable(GL_CULL_FACE)#カリング
    glCullFace(GL_BACK)
    #glCullFace(GL_FRONT)
    glFrontFace(GL_CW)      #時計回りを表に設定

    ##光源の設定と物体の質感
    #ライティング処理のオン
    glEnable(GL_LIGHTING)
    #0番めの光源点灯
    glEnable(GL_LIGHT0)
    #拡散光 赤
    glLightfv(GL_LIGHT0, GL_DIFFUSE, red)
    #1番めの光源点灯
    glEnable(GL_LIGHT1)
    #拡散光 青 
    glLightfv(GL_LIGHT1, GL_DIFFUSE, blue)
    #glEnable(GL_COLOR_MATERIAL)



#resizeはウィンドウリサイズ時と最初に一回実行される
def resize(w,h):
    print "resize"
    glViewport(0,0,w,h)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    #glOrtho(-w/300, w/300, -h/300, h/300, -1.0, 1.0)
    #glFrustum(-3.0, 3.0, -3.0, 3.0, 5.0, 10000.0)
    #gluPerspective(20.0, w/h, 1.0, 10.0) 
    gluPerspective(30.0, w/h, 3.0, 10.0)
    #glTranslated(0.0, 0.0, -5.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    #glTranslated(0.0, 0.0, -5.0 )
    gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)


def display():
    print "display"

    global r
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    #glLoadIdentity()
    #gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
    #gluLookAt(3.0, 4.0, -5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)

    #光源の位置設定
    glLightfv(GL_LIGHT0, GL_POSITION, Light0pos)
    glLightfv(GL_LIGHT1, GL_POSITION, Light1pos)

    #モデルビュー変換行列の保存
    glPushMatrix()
    #図形の回転
    glRotated(r/adjust_r, 0.0, 1.0, 0.0)
    #図形の色(黃)
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, yellow)
    #glColor3d(0.0, 0.0, 0.0)
    #立方体を描く # GL_QUADS 四角形を描く
    cube()

    #2つ目の図形の描画
    glPushMatrix()      #省略可
    glTranslated(1.0, 1.0, 1.0)
    #下のglRotatedは2つめのcubeだけに影響している
    glRotated(3*r/adjust_r, 0.0,  1.0,  0.0)
    glScaled(0.5, 0.5, 0.5)
    glMaterialfv(GL_FRONT, GL_DIFFUSE, blue)
    cube()
    glPopMatrix()       #省略可

    #モデルビュー変換行列の取り出し
    glPopMatrix()

    glutSwapBuffers()

    #回転の制御
    #処理対象のウィンドウの関係するレイヤーの状態を調べる
    #*glutLayerGet*(GLUT_NORMAL_DAMAGED)
    #glutPostRedisplayでdisplayされているなら0
    #ウィンドウが隠されて等displayされているなら1
    r+=2
    if (glutLayerGet(GLUT_NORMAL_DAMAGED)==0):
        #glutPostRedisplayで再描画
        if (r >= 360*adjust_r):
            #一周回ったらアニメーションを止める
            r = 0
            #暇なときに実行するプログラムを指定するが、それを
            #ここで解除している
            glutIdleFunc(0)
    glFlush()

def mouse(button, state, x, y):
    if button == GLUT_LEFT_BUTTON:
        #アニメーション開始
        if state == GLUT_UP:
            glutIdleFunc(idle)
    if button == GLUT_MIDDLE_BUTTON:
        #コマ送り
        if state == GLUT_UP:
            print "middle"
            glutPostRedisplay()
    if button == GLUT_RIGHT_BUTTON:
        #アニメーション停止
        if state == GLUT_UP:
            glutIdleFunc(None)


def keyboard(key, x, y):
    if key == 'q' or key == 'Q':
        sys.exit()

def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    #glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE)
    #glutInitDisplayMode(GLUT_RGBA)
    glutInitWindowSize(300, 300)
    glutInitWindowPosition(200, 50)
    glutCreateWindow("テクスチャ")
    init()
    glutDisplayFunc(display)

    glutReshapeFunc(resize)
    #glutTimerFunc(5 , idle , 0)
    glutKeyboardFunc(keyboard)
    glutMouseFunc(mouse)
    #特殊なキーの入力を受け付ける
    #*glutSpecialFunc*
    #glutSpecialFunc(special_key)
    glutMainLoop()

if __name__ == "__main__":
    main()

                                                   
検索キーワード
opengl pyopengl 

0 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ブログ アーカイブ

ページ

Featured Posts