【PyOpenGL学习笔记】第二篇:移动功能

一、前情提要

        在前一篇中,我们已经完成了一个旋转的彩色立方体的制作,对GL来说算是一个简单的helloworld。同时我们简单接触了一下状态机这个概念,我们用【glEnable()】和【glBegin()  & glEnd()】来控制了GL的状态实现渲染。

        但这是不够的!我相信来看这篇文章的你们都是想做一个3D小游戏的吧,那么我们就需要什么?添加交互!!!

二、添加摄像机交互

        首先让我们设计一下我们的交互,我们希望先实现摄像机的移动,就用游戏的标配wasd作为输入键,用空格和Ctrl作为上升和下降的输入键。

        计划好了,让我们先为摄像机的三轴定义一个变量

cam_pos_x = 0
cam_pos_y = 0
cam_pos_z = 0

        然后就是处理移动逻辑了,这里我们使用pygame的事件处理来实现,所以说pygame真是天赐之物

for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            quit()
        keys = pg.key.get_pressed()
        if keys[pg.K_w]:
            cam_pos_z += 0.1
        if keys[pg.K_s]:
            cam_pos_z -= 0.1
        if keys[pg.K_a]:
            cam_pos_x += 0.1
        if keys[pg.K_w]:
            cam_pos_x -= 0.1
        if keys[pg.K_w]:
            cam_pos_y -= 0.1
        if keys[pg.K_w]:
            cam_pos_y += 0.1

        OK,这样移动的逻辑就设定好了,速度设置为了0.1,接下来让我们在循环中为移动赋值

for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            quit()
        keys = pg.key.get_pressed()
        if keys[pg.K_w]:
            cam_pos_z += 0.1
        if keys[pg.K_s]:
            cam_pos_z -= 0.1
        if keys[pg.K_a]:
            cam_pos_x += 0.1
        if keys[pg.K_d]:
            cam_pos_x -= 0.1
        if keys[pg.K_SPACE]:
            cam_pos_y -= 0.1
        if keys[pg.K_LCTRL]:
            cam_pos_y += 0.1

    glLoadIdentity()
    glTranslatef(cam_pos_x, cam_pos_y, cam_pos_z)

        GL的位移旋转是由矩阵操作的,我们调用【glTranslatef()】函数来创建一个4x4的齐次矩阵,并将其右乘到当前的矩阵堆栈,同时在每次循环中我们需要调用【glLoadIdentity()】函数来将矩阵重置为单位矩阵,不然坐标的变化会一直累积直到变成闪电侠

        话不多说,让我们运行代码看看效果如何

        。。。这什么玩意儿。。。

        别急,我们还需要设置一下投影矩阵,让我们回到main()函数的开头加上这段代码

glMatrixMode(GL_PROJECTION)
glLoadIdentity()

gluPerspective(70, (display[0] / display[1]), 0.1, 50.0)

glMatrixMode(GL_MODELVIEW)

        记得去掉初始化时我们添加上的位移,然后将摄像机的z值设置为-5!然后让我们再运行一下看看

        "The World!!"

        这个立方体就像被时停了的承太郎一样只能狠狠的看着我们,但是我们可以在这个空间中自由移动,让我们来修复这个BUG。

        这里的关键问题是:GL的矩阵操作是逆序应用的,当前的矩阵实际变换顺序是【旋转→平移→透视投影】,这会导致旋转只发生在相机坐标系中,所以我们不能用之前的世界坐标系的方式来操作,让我们修改一下代码

import pygame as pg
from pygame.locals import *

from OpenGL.GL import *
from OpenGL.GLU import *

# Vertex
cubeVertices = ((1, 1, 1), (1, 1, -1), (1, -1, -1), (1, -1, 1),
                (-1, 1, 1), (-1, -1, -1), (-1, -1, 1), (-1, 1, -1))
cubeQuads = ((0, 4, 6, 3), (2, 3, 6, 5), (1, 2, 5, 7),
             (1, 7, 4, 0), (7, 5, 6, 4), (2, 1, 0, 3))
cubeColors = ((1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1))

def draw_cube():
    glBegin(GL_QUADS)
    for i, quad in enumerate(cubeQuads):
        glColor3fv(cubeColors[i])
        for vertex in quad:
            glVertex3fv(cubeVertices[vertex])
    glEnd()

def main():
    pg.init()
    display = (960, 540)
    pg.display.set_mode(display, DOUBLEBUF | OPENGL | RESIZABLE)

    glEnable(GL_CULL_FACE)
    glEnable(GL_DEPTH_TEST)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    gluPerspective(70, (display[0] / display[1]), 0.1, 50.0)

    glMatrixMode(GL_MODELVIEW)

    cam_pos_x = 0
    cam_pos_y = 0
    cam_pos_z = -5

    rotation_y = 0
    rotate_speed = 1
    move_speed = 0.1

    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
                quit()
        keys = pg.key.get_pressed()
        if keys[pg.K_w]:
            cam_pos_z += move_speed
        if keys[pg.K_s]:
            cam_pos_z -= move_speed
        if keys[pg.K_a]:
            cam_pos_x += move_speed
        if keys[pg.K_d]:
            cam_pos_x -= move_speed
        if keys[pg.K_SPACE]:
            cam_pos_y -= move_speed
        if keys[pg.K_LCTRL]:
            cam_pos_y += move_speed

        rotation_y += rotate_speed

        glLoadIdentity()
        glTranslatef(cam_pos_x, cam_pos_y, cam_pos_z)

        glRotatef(rotation_y, 0, 1, 0)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        
        draw_cube()

        pg.display.flip()
        pg.time.wait(10)

if __name__ == "__main__":
    main()

        这里我顺便给移动速度定义为了一个变量,这样代码更优雅的同时调整起来也方便;同时我们定义了一个y轴旋转角和旋转速度的变量,在每次循环中为旋转角增加一个单位速度;最后我也给绘制立方体封装为了一个函数。

        我真的很不喜欢在循环中有一大段一大段的东西,让我在后续加功能的时候一个脑袋两个大,所以封装函数对我来说真的很有用,感觉延长了至少一年的寿命,话扯远了,让我们运行一下看看效果

        完美,下一篇让我们为摄像机添加上视角变化的功能,就可以用鼠标来控制视角了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值