テクスチュアマッピング(1)

1.テクスチュアマッピングとは

 3次元の面に対して画像を貼り付ける方法である.
 例えばレンガの壁を作る場合に,本来であればすべてのレンガをモデリングする必要があるが,テクスチュアマッピングを用いることにより,より容易に現実的な画像を効率的に得ることを可能とする.

2.テクスチャアマッピングの座標系

 テクスチュアマッピングに用いる画像は以下のような座標系をもつ.
 
 OpenGLの場合には,画像サイズは2^mピクセル×2^nピクセル(ただしm=6,7,8・・・,n=6,7,8・・・)である必要がある.
 最大画像サイズは動作環境により異なる.
 縦横が違うピクセル数をもつことも可能である.(例えば128×64等)
 (テクスチュアのピクセルをテクセルと呼ぶ)

3.テクスチュアマッピングを用いたプログラム


(準備)
tex1.bmpという名前で64ピクセル×64ピクセルの画像ファイルを作成すること.
プログラム>>アクセサリ>>ペイント  変形>>キャンバスの色とサイズ 64×64ピクセルにし,画像を作成

(コード)
'Texture1.frm
'Form1上にCommand1,Picture1,Picture2が必要
Option Explicit
Dim m_hGLRC&
Private Type axis
    x As Single
    y As Single
    z As Single
End Type
Dim tex() As Byte 'テクスチュアマッピング用の配列
Dim rot As axis
Dim tr As axis

Private Sub Command1_Click()
    Timer1.Enabled = Not Timer1.Enabled
End Sub

Private Sub Form_Load()
    Timer1.Interval = 10
    Timer1.Enabled = False
    Command1.Caption = "回転"
End Sub

Private Sub Picture1_Paint()
    SetView
    SetLight
    display
End Sub

Private Sub SetView()
    glMatrixMode mmProjection
    glLoadIdentity
    glFrustum -2, 2, -2, 2, 2, 100   '透視投影変換設定(gluPerspectiveの代替)
    glMatrixMode mmModelView
    glViewport 0, 0, Picture1.Width, Picture1.Height
End Sub

Private Sub Form_Initialize()
    Initialize
    ReadTex
    texdraw
End Sub

Private Function Initialize() As Boolean
    Dim pfd As PIXELFORMATDESCRIPTOR
    Dim R&
    Picture1.ScaleMode = vbPixels
 
    'set standard parameters
    pfd.nSize = Len(pfd)
    pfd.nVersion = 1
    pfd.dwFlags = PFD_SUPPORT_OPENGL Or PFD_DRAW_TO_WINDOW Or PFD_DOUBLEBUFFER Or PFD_TYPE_RGBA
    pfd.iPixelType = PFD_TYPE_RGBA
    pfd.cColorBits = 24
    pfd.cDepthBits = 16
    pfd.iLayerType = PFD_MAIN_PLANE
    R = ChoosePixelFormat(Picture1.hDC, pfd)
    If R = 0 Then
        MsgBox "ChoosePixelFormat failed"
        Exit Function
    End If
    R = SetPixelFormat(Picture1.hDC, R, pfd)
    'palette?
    m_hGLRC = wglCreateContext(Picture1.hDC)
    wglMakeCurrent Picture1.hDC, m_hGLRC
 
    glDepthFunc GL_LEQUAL
    glEnable GL_DEPTH_TEST
    glShadeModel GL_FLAT
 
    'Fog
    Dim fogclr(4) As Single
    fogclr(0) = 1: fogclr(1) = 1: fogclr(2) = 1: fogclr(3) = 1
    glFogfv GL_FOG_COLOR, fogclr(0)
    glFogfv GL_FOG_DENSITY, 0.1
    glDisable GL_FOG  'fogをONにする場合には glEnable GL_FOG
 
    Picture2.Visible = True  'ここをFalseにするとPicture2は表示されない.
    Initialize = True
End Function
 

Private Sub Form_Unload(Cancel As Integer)
    If m_hGLRC <> 0 Then
        wglMakeCurrent 0, 0
        wglDeleteContext m_hGLRC
    End If
End Sub

'テクスチュア画像の読み込み
Private Sub ReadTex()
    Dim i As Integer, j As Integer, w As Integer, h As Integer
    Picture2.AutoRedraw = True
    Picture2.AutoSize = True
    Picture2.ScaleMode = vbPixels
 
    '画像ファイルの読み込み
    '(画像ファイルは自分の作成したファイル名)
    Picture2.Picture = LoadPicture("tex1.bmp")
    w = Picture2.ScaleWidth - 1
    h = Picture2.ScaleHeight - 1
 
    '画像サイズが分かったので配列を再定義
    ReDim tex(2, w, h)
    '配列に画像情報を入力する(上下反転に注意)
    For j = 0 To h
        For i = 0 To w
            tex(0, i, h - j) = getR(Picture2.Point(i, j))
            tex(1, i, h - j) = getG(Picture2.Point(i, j))
            tex(2, i, h - j) = getB(Picture2.Point(i, j))
        Next
    Next
End Sub
Private Sub texdraw()
    'テクスチュアの設定
    glPixelStorei GL_UNPACK_ALIGNMENT, 1
    glTexImage2D GL_TEXTURE_2D, 0, 3, Picture2.ScaleWidth, Picture2.ScaleHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, tex(0, 0, 0)
    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_NEAREST
    glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST
    glTexEnvf GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL
End Sub
Private Sub SetLight()
    '平行光源(固定)
    Dim valueLight0(3) As Single
    Dim positionLight0(3) As Single
 
    'fillarray4fはユーザー定義
    FillArray4f valueLight0(), 0.7!, 0.7!, 0.7!, 1!
    FillArray4f positionLight0(), 0!, 1!, 1!, 0!
 
    glLightfv GL_LIGHT0, GL_AMBIENT, valueLight0(0)
    glLightfv GL_LIGHT0, GL_DIFFUSE, valueLight0(0)
    glLightfv GL_LIGHT0, GL_SPECULAR, valueLight0(0)
    glLightfv GL_LIGHT0, GL_POSITION, positionLight0(0)
 
    glEnable GL_LIGHTING
    glEnable GL_LIGHT0
End Sub

Private Sub display()
    Dim MaterialDiffuse(3) As Single
    Dim MaterialSpecular(3) As Single
 
    glMatrixMode GL_MODELVIEW
    glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
    glClearColor 0, 0, 0, 0
    glLoadIdentity
    glTranslatef 0, 0, -5
 
    'テクスチュアON
    glEnable GL_TEXTURE_2D
    glRotatef rot.y, 0, 1, 0
 
    FillArray4f MaterialDiffuse(), 0.2, 0.2, 0.2, 1!
    FillArray4f MaterialSpecular(), 0.25, 0.25, 0.3, 1!
    glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
    glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
 
    glBegin GL_QUADS
        '法線の設定
        glNormal3f 0, 0, 1
        'テクスチャア座標の設定:及び物体の作成
        glTexCoord2f 0, 0: glVertex3f -4, -4, 0
        glTexCoord2f 1, 0: glVertex3f 4, -4, 0
        glTexCoord2f 1, 1: glVertex3f 4, 4, 0
        glTexCoord2f 0, 1: glVertex3f -4, 4, 0
    glEnd
    'テクスチュアOFF
    glDisable GL_TEXTURE_2D
 
    '球を描く
    glTranslatef 0, 0, 2
    FillArray4f MaterialDiffuse(), 0.4, 0.4, 0.1, 1!
    FillArray4f MaterialSpecular(), 0.3, 0.3, 0.1, 1!
    glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
    glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
    glutSolidSphere 0.5, 20, 20
 
    SwapBuffers Picture1.hDC
End Sub

Public Function getR(color As Long) 'Longの整数からR成分を抜き出す関数を設定
    getR = color And &HFF&
End Function

Public Function getG(color As Long)  'Longの整数からG成分を抜き出す関数を設定
    getG = (color And &HFF00&) / &H100&
End Function

Public Function getB(color As Long) 'Longの整数からB成分を抜き出す関数
    getB = (color And &HFF0000) / &H10000
End Function

Private Sub Timer1_Timer()
    rot.y = rot.y + 5
    display
End Sub

Private Sub FillArray4f(a() As Single, f1 As Single, f2 As Single, f3 As Single, f4 As Single)
    a(0) = f1: a(1) = f2: a(2) = f3: a(3) = f4
End Sub