通过PyOpenGL生成3D图形

时间:2016-02-08 15:16:22

标签: python opengl 3d pyopengl

我根据" 2D波动方程"使用PyOpenGL生成3D海面。主要目的是显示" 2D波动方程的动态图形"但它一直告诉我这个错误:

E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\mytest>python seawave_2d_opengl.py
Traceback (most recent call last):
  File "E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\lib\site-packages\OpenGL\GLUT\
special.py", line 130, in safeCall
    return function( *args, **named )
  File "seawave_2d_opengl.py", line 106, in Draw
    glVertex3f(x,y,z)
  File "E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\lib\site-packages\OpenGL\p
latform\baseplatform.py", line 402, in __call__
    return self( *args, **named )
ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type
GLUT Display callback <function Draw at 0x0000000004086950> with (),{} failed: r
eturning None argument 3: <class 'TypeError'>: wrong type

E:\WinPython-64bit-3.4.3.5\python-3.4.3.amd64\mytest>

以下是代码:

from numpy import linspace,zeros,sin,pi,exp,sqrt
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys

def solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, tstop, user_action=None):
    dx = Lx/float(nx)
    dy = Ly/float(ny)
    x = linspace(0, Lx, nx+1)  #grid points in x dir
    y = linspace(0, Ly, ny+1)  #grid points in y dir
    if dt <= 0:                #max time step?
        dt = (1/float(c))*(1/sqrt(1/dx**2 + 1/dy**2))
    Cx2 = (c*dt/dx)**2
    Cy2 = (c*dt/dy)**2  #help variables
    dt2 = dt**2

    up = zeros((nx+1,ny+1))  #solution array
    u = up.copy()            #solution at t-dt
    um = up.copy()           #solution at t-2*dt

    #set initial condition:
    t =0.0
    for i in range(0,nx):
        for j in range(0,ny):
            u[i,j] = I(x[i], y[j])
    for i in range(1,nx-1):
        for j in range(1,ny-1):
            um[i,j] = u[i,j] + \
                      0.5*Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
                      0.5*Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
                      dt2*f(x[i], y[j], t)
    #boundary values of um (equals t=dt when du/dt=0)
    i = 0
    for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
    j = 0
    for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)
    i = nx
    for j in range(0,ny): um[i,j] = bc(x[i], y[j], t+dt)
    j = ny
    for i in range(0,nx): um[i,j] = bc(x[i], y[j], t+dt)

    if user_action is not None:
        user_action(u, x, y, t)   #allow user to plot etc.

    while t <= tstop:
        t_old = t
        t += dt

        #update all inner points:
        for i in range(1,nx-1):
            for j in range(1,ny-1):
                up[i,j] = -um[i,j] + 2*u[i,j] + \
                          Cx2*(u[i-1,j] - 2*u[i,j] + u[i+1,j]) + \
                          Cy2*(u[i,j-1] - 2*u[i,j] + u[i,j+1]) + \
                          dt2*f(x[i], y[j], t_old)

        #insert boundary conditions:
        i = 0
        for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
        j = 0
        for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)
        i = nx
        for j in range(0,ny): up[i,j] = bc(x[i], y[j], t)
        j = ny
        for i in range(0,nx): up[i,j] = bc(x[i], y[j], t)

        if user_action is not None:
            user_action(up, x, y, t)

        um, u, up = u, up, um  #update data structures
    return u  #dt might be computed in this function
#Actually,the book wrote `return dt`,but I changed `dt` to `u`
def I(x, y):
    return exp(-(x-Lx/2.0)**2/2.0 -(y-Ly/2.0)**2/2.0)
def f(x, y, t):
    return sin(2*x*y*pi*t/Lx)  #defined by myself
def bc(x, y, t):
    return 0.0
#These three functions are some basic functions related to the first function "solver0"

Lx = 10
Ly = 10
c = 1.0
dt = 0
nx = 40
ny = 40
tstop = 20

#The following part is to generate 3D graphics,where I must make mistakes:
def init():
    glClearColor(1.0,1.0,1.0,0.0)  

def Draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(0,0,1.0)
    glBegin(GL_LINES)   
    for t in range(0,20,1):
        z = solver0(I, f, c, bc, Lx, Ly, nx, ny, dt, t, user_action=None)
        glVertex3f(x,y,z) 
 #x and y cannot be used here because they are not defined as global variables.
    glEnd()
    glFlush  

def Update():
    global t
    t += 0.1
    glutPostRedisplay() 

def main():    
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
    glutInitWindowSize(800,600)
    glutInitWindowPosition(100,50)
    glutCreateWindow("2D Wave Equations".encode("cp932"))
    init()
    glutDisplayFunc(Draw)
    glutIdleFunc(Update)
    glutMainLoop()   

main()

我犯了什么错误?有人可以帮助我吗? :(

1 个答案:

答案 0 :(得分:1)

正如您可以从堆栈跟踪中猜到的那样,glVertex3f(x,y,z)中的一个参数(第三个?!?)的类型错误。评论中的讨论清楚地表明z是二维ndarrayglVertex3f()期望标量。看起来solver0()计算z值的数组,而不是每次调用一个z值。

EDIT 我现在理解solver0()的作用。该函数应该记录在打印它的书中。虽然Stackoverflow不是为了解释复制和粘贴代码,但我将对我认为该函数的作用进行一些概述:

  1. Lx和Ly给出所有x和y
  2. 的范围
  3. nx和ny给出0和Lx之间使用的x和y值的数量。
  4. 该函数计算x和y值的数组,计算z值(up)。
  5. 它会计算up从0到tstop的多个时间值,步长为dt
  6. 如果给出了用户函数user_action,则在计算up后调用它。用up, x, y, t作为参数调用用户函数。
  7. 总结一下:solver0的一次调用计算给定x和y值范围的所有x,y和z值以及给定分辨率的给定时间跨度。