シェーディングの設定

1.シェーディングモデル

シェーディングの設定
 フラットシェーディング(Flat shading):面の頂点の色を同一として描画する(Lambert shading)
 スムースシェーディング:滑らかな曲面の描画を行う.
     グ-ローシェーディング(Gouraud shading):
       頂点の法線ベクトルから面の頂点の色を求め,それを補間して面の色を描画する.
    フォンシェーディング(Phong shading):
       頂点の法線ベクトルを基に,面全体の法線ベクトルを求め,それにより面の色を決定する.

OpenGLによるシェーディングの設定                                
 フラットシェーディングの設定
     glShadeModel GL_FLAT
 スムースシェーディング(Gouraud Shading) の設定
     glShadeModel GL_SMOOTH

2.面の法線と塗りつぶし

面の向きは法線の向きにより決定される.また法線の向きは面の色に大きく影響する.
(点毎の法線も設定できる)

法線の設定
  glNormal3f  x, y, z

ポリゴンモードの設定
  glPolygonMode GL_FRONT_AND_BACK, GL_FILL  '両面を塗りつぶす
  glPolygonMode GL_FRONT, GL_FILL  '表を塗りつぶす
  glPolygonMode GL_BACK, GL_LINE '裏を線で描画
  glPolygonMode GL_BACK, GL_POINTS '裏を点で描画
 

3.物体あるいは面の色の設定方法

以下のようにglMaterialfv関数に配列で受け渡す必要がある.
例)
Dim MaterialDiffuse(4) As Single
Dim MaterialSpecular(4) As Single
MaterialDiffuse(0)=.4  '赤(R)
MaterialDiffuse(1)=.3 '緑(G)
MaterialDiffuse(2)=.3 '青(B)
MaterialDiffuse(3)=1  'アルファ(A)
MaterialSpecular(0)=.2  '赤(R)
MaterialSpecular(1)=.2 '緑(G)
MaterialSpecular(2)=.2 '青(B)
MaterialSpecular(3)=1  'アルファ(A)

'配列の0番目を受け渡す(環境光及び拡散光)
glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)

'配列の0番目を受け渡す(反射光)
glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
 

4.コード

'太字が前回のコードの主な変更個所
Option Explicit
'Form1上にPicture1及びCommand1(0),Command1(1)を配置する.
'重要 Command1ボタンをコントロール配列に (Command1ボタンをコピー&貼り付けで作成できる)
Dim m_hGLRC&
Private Type pnt3d
    x As Single
    y As Single
    z As Single
End Type
Dim r As pnt3d
Dim addr As pnt3d
'新たに定義(ポイント座標)
Dim pnt(100) As pnt3d
 

Private Sub Form_Initialize()
    Timer1.Interval = 10
    Timer1.Enabled = False
    Initialize
End Sub

Private Sub Command1_MouseDown(Index As Integer, Button As Integer, Shift As Integer, x As Single, y As Single)
    Dim add As Integer
    If Button = vbLeftButton Then add = 1 Else add = -1
    Select Case Index
        Case 0
            addr.z = add * 10: addr.y = 0
        Case 1
            addr.z = 0: addr.y = add * 10
    End Select
    Timer1.Enabled = True
End Sub

Private Sub Command1_MouseUp(Index As Integer, Button As Integer, Shift As Integer, x As Single, y As Single)
    Timer1.Enabled = False
End Sub

Private Sub Picture1_Paint()
    ViewSet 50, Picture1.ScaleWidth / Picture1.ScaleHeight, 1, 100
    SetLight
    Draw
End Sub

Private Function Initialize() As Boolean
    Dim pfd As PIXELFORMATDESCRIPTOR
    Dim r&
    Picture1.ScaleMode = vbPixels
    pfd.nSize = Len(pfd)
    pfd.nVersion = 1
'    pfd.dwFlags = PFD_SUPPORT_OPENGL Or PFD_DRAW_TO_WINDOW
    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)

    m_hGLRC = wglCreateContext(Picture1.hDC)
    wglMakeCurrent Picture1.hDC, m_hGLRC

    glDepthFunc GL_LEQUAL
    glEnable GL_DEPTH_TEST

    'シェーディング設定
'    glShadeModel GL_SMOOTH   'スムースシェーディングの場合
    glShadeModel GL_FLAT   'フラットシェーディングの場合
    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 ViewSet(fov As Single, aspect As Single, near As Single, far As Single)
    glMatrixMode GL_PROJECTION
    glLoadIdentity
    gluPerspective fov, aspect, near, far
    glViewport 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight
    glMatrixMode GL_MODELVIEW
End Sub

Public Sub Draw()
    Dim n As Integer

    '色・ライト設定用配列の定義
    Dim MaterialDiffuse(3) As Single
    Dim MaterialSpecular(3) As Single
    Dim positionLight0(3) As Single

    '法線格納用変数
    Dim normal As pnt3d

    '背景色の設定(RGBA)
    glClearColor 0.2, 0.2, 0.3, 0
    glClear GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT
    glColor3f 1#, 1#, 1#
    glLoadIdentity

    'ここにライトのポジション設定を与えると
    '物体の移動・回転とは関係ない.
    FillArray4f positionLight0(), 0!, 1!, 1!, 1!
    glLightfv GL_LIGHT0, GL_POSITION, positionLight0(0)
 

    glRotatef 10, 1, 0, 0    '視点回転
    glTranslatef 0#, -1#, -5#  '視点設定
    glPushMatrix

    '    glRotatef 90, 1, 0, 0   '球の回転 X軸周りに90度
        glRotatef r.y, 0, 1, 0
        glRotatef r.z, 0, 0, 1

        'ここにライトのポジション設定を与えると物体の回転とともに
        'ライトも回転する.
    '    FillArray4f positionLight0(), 0!, 1!, 1!, 1!
    '    glLightfv GL_LIGHT0, GL_POSITION, positionLight0(0)

        '物体の色の設定1
        FillArray4f MaterialDiffuse(), 0.45, 0.3, 0.15, 1!
        FillArray4f MaterialSpecular(), 0.2, 0.1, 0.1, 1!
        glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
        glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)

        glutSolidSphere 0.3, 20, 20
    '    glutWireSphere .3, 20, 20
        glPushMatrix
            glTranslatef 1, 0, 0

            '物体の色の設定2
            FillArray4f MaterialDiffuse(), 0.2, 0.2, 0.2, 1!
            FillArray4f MaterialSpecular(), 0.3, 0.4, 0.4, 1!
            glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
            glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
            glutSolidSphere 0.5, 20, 20
        glPopMatrix
        '任意の物体の描画
        FillArray4f MaterialDiffuse(), 0.5, 0.1, 0.1, 1!
        FillArray4f MaterialSpecular(), 0.2, 0.1, 0.1, 1!
        glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
        glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
        glPolygonMode GL_FRONT, GL_FILL
        glPolygonMode GL_BACK, GL_LINE
        glBegin GL_POLYGON
            glNormal3f 0, 0, 1  '法線の指定
            glVertex3f -1, -1, 2
            glVertex3f 1, -1, 2
            glVertex3f 0, 1, 2
        glEnd

        '配列を用いた面の描画
        pnt(0).x = -2: pnt(0).y = -1: pnt(0).z = -4
        pnt(1).x = -1: pnt(1).y = -1: pnt(1).z = -4
        pnt(2).x = 2: pnt(2).y = 0: pnt(2).z = -4
        pnt(3).x = 1: pnt(3).y = 1: pnt(3).z = -4
        pnt(4).x = -2: pnt(4).y = 0: pnt(4).z = -4

        '法線の計算,3点のみ与えればよい.
        FillArray4f MaterialDiffuse(), 0.1, 0.1, 0.4, 1!
        FillArray4f MaterialSpecular(), 0.1, 0.1, 0.4, 1!
        glMaterialfv faceFront, mprAmbientAndDiffuse, MaterialDiffuse(0)
        glMaterialfv faceFront, mprSpecular, MaterialSpecular(0)
        normal = calcNormal(pnt(0), pnt(1), pnt(2))
        glPolygonMode GL_FRONT_AND_BACK, GL_FILL
        glBegin GL_POLYGON
            glNormal3f normal.x, normal.y, normal.z
            For n = 0 To 4
                glVertex3f pnt(n).x, pnt(n).y, pnt(n).z
            Next

        glEnd

    glPopMatrix
    SwapBuffers Picture1.hDC
End Sub
 

'ポリゴンの法線を計算するプロシージャ
Private Function calcNormal(P1 As pnt3d, P2 As pnt3d, P3 As pnt3d) As pnt3d
    Dim n As pnt3d
    Dim length As Single

    n.x = (P2.y - P1.y) * (P3.z - P2.z) - (P2.z - P1.z) * (P3.y - P2.y)
    n.y = (P2.z - P1.z) * (P3.x - P2.x) - (P2.x - P1.x) * (P3.z - P2.z)
    n.z = (P2.x - P1.x) * (P3.y - P2.y) - (P2.y - P1.y) * (P3.x - P2.x)

    '長さの計算
    length = Sqr(n.x * n.x + n.y * n.y + n.z * n.z)
    '単位ベクトルにする
    If length <> 0 Then
        calcNormal.x = n.x / length
        calcNormal.y = n.y / length
        calcNormal.z = n.z / length
    End If
End Function
 

Private Sub Timer1_Timer()
    r.z = r.z + addr.z
    r.y = r.y + addr.y
    Draw
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

Private Sub SetLight()
    Dim ambientLight0(3) As Single
    Dim positionLight0(3) As Single

    'fillarray4fはユーザー定義
    FillArray4f ambientLight0(), 0.3!, 0.3!, 0.3!, 1!
    glLightfv GL_LIGHT0, GL_AMBIENT, ambientLight0(0)
    glEnable GL_LIGHTING
    glEnable GL_LIGHT0
End Sub