【问题标题】:Generating 3D graphic by PyOpenGL通过 PyOpenGL 生成 3D 图形
【发布时间】:2016-02-11 20:12:27
【问题描述】:

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

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()

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

【问题讨论】:

  • 听起来变量z 的类型不正确。检查solver0(...) 的输出。也许你错过了返回结果。
  • @jochen 我确实返回了结果。所以z不能这样定义?我以为z 是一个类型array...
  • 堆栈跟踪指向glVertex3f(x,y,z) 并告诉您其中一个参数的类型错误。只需仔细检查所有三个参数的类型(例如 print type(x), type(y), type(z))。
  • @jochen 你是对的。z 的类型是错误的。表明x和y的类型为numpy.float64,z的类型为numpy.ndarry。我怎么解决这个问题?我尝试通过float(z)转换z的类型,但是没有用,说only length-1 arrays can be converted to Python scalars
  • 你应该打印 z print z.shape 的形状。它将显示z 有多个元素。问题可能是,solver0 计算了一个由z 组成的数组,而不是您要绘制的特定xyz。我的猜测是基于xy 没有出现在对solver0() 的调用中。

标签: python opengl 3d pyopengl


【解决方案1】:

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

编辑 我现在有点明白solver0() 做了什么。该函数应该记录在打印它的书中。虽然 Stackoverflow 并不是要解释复制和粘贴代码,但我将简要概述一下我认为该函数的作用:

  1. Lx 和 Ly 给出所有 x 和 y 的范围
  2. nx 和 ny 给出 0 和 Lx、Ly 之间使用的 x 和 y 值的数量。
  3. 该函数计算 x 和 y 值的数组,计算 z 值 (up)。
  4. 它计算从 0 到 tstop 的多个时间值 up,步长为 dt
  5. 如果给定用户函数user_action,则在计算up 后调用它。使用 up, x, y, t 作为参数调用用户函数。

总结一下:solver0 的一次调用会计算给定 x 和 y 值范围以及给定时间跨度和给定分辨率的所有 x、y 和 z 值。

【讨论】:

  • 对不起,我不太明白你的意思。如您所知,z 是一个二维的ndarry,我如何通过 PyOpenGL 解决这个问题?我只想使用glvertex 绘制每个x yz 以生成3D 曲线图形。请原谅我对此知之甚少...
  • 不要担心提问。我不知道solver0() 是如何工作的。你必须先解决这个问题。应该有一些文档,或者您应该联系开发人员。仅仅因为 x 和 y 是全局的,并不意味着它们是 If 的参数。在I(4,5) 行中,I 的参数将是(4,5),而不是全局(x, y)。无论如何,使用全局变量通常不是一个好主意。另外使用for x in x: 是个坏主意,因为这样你就可以用它的一个元素覆盖你的全局x
  • 哦,我明白了。 xy 没有传递给 If...我已将代码粘贴到 solver0。它来自一本书,我修改了一点。实际上xy已经在solver0中定义了,但是我不能在这个函数之外使用它,所以我在main中定义了xy我自己的身体,显然我做错了事。所以我现在应该做的是弄清楚如何绘制曲线......我再次感到困惑......
  • 我绘制曲线的方法是否错误?我以前用这种方式绘制了一条二维曲线。所以很自然我也用这种方法来绘制 3D 曲线。但这似乎是很多问题。实际上,我希望曲线与t一起移动以显示动画。我想我必须修改Draw函数,但我不知道如何......
  • 非常感谢您向我解释这些。所以我是否可以将solver0OpenGL 结合起来。似乎solver0 已经完成了一切,所以我不应该在 OpenGL 中使用循环来绘制曲线。我应该考虑一下。非常感谢您的耐心和帮助。
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 2020-09-16
  • 1970-01-01
  • 2011-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多