Python 3.x 如何在Pyopengl中从三维numpy数组创建曲面?

Python 3.x 如何在Pyopengl中从三维numpy数组创建曲面?,python-3.x,numpy,pyqt5,pyopengl,python-moderngl,Python 3.x,Numpy,Pyqt5,Pyopengl,Python Moderngl,我创建了一个由X、Y和Z轴坐标组成的三维numpy阵列。现在我正试图用opengl中的这些点创建一个曲面,但我所取得的成功就是创建了如下类似的线模型。有人能建议修改我的代码,从数据中形成实际的三维表面吗? 用于链接的数据文件 代码:- import OpenGL.GL as gl import OpenGL.arrays.vbo as glvbo from PyQt5.Qt import * import numpy as np import Backend_algo as Sb import

我创建了一个由X、Y和Z轴坐标组成的三维numpy阵列。现在我正试图用opengl中的这些点创建一个曲面,但我所取得的成功就是创建了如下类似的线模型。有人能建议修改我的代码,从数据中形成实际的三维表面吗? 用于链接的数据文件

代码:-

import OpenGL.GL as gl
import OpenGL.arrays.vbo as glvbo
from PyQt5.Qt import *
import numpy as np
import Backend_algo as Sb
import sys
import ctypes


def compile_vertex_shader(source):
    """Compile a vertex shader from source."""
    vertex_shader = gl.glCreateShader(gl.GL_VERTEX_SHADER)
    gl.glShaderSource(vertex_shader, source)
    gl.glCompileShader(vertex_shader)
    # check compilation error
    result = gl.glGetShaderiv(vertex_shader, gl.GL_COMPILE_STATUS)
    if not (result):
        raise RuntimeError(gl.glGetShaderInfoLog(vertex_shader))
    return vertex_shader


def compile_fragment_shader(source):
    """Compile a fragment shader from source."""
    fragment_shader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
    gl.glShaderSource(fragment_shader, source)
    gl.glCompileShader(fragment_shader)
    result = gl.glGetShaderiv(fragment_shader, gl.GL_COMPILE_STATUS)
    if not (result):
        raise RuntimeError(gl.glGetShaderInfoLog(fragment_shader))
    return fragment_shader


def link_shader_program(vertex_shader, fragment_shader):
    """Create a shader program with from compiled shaders."""
    program = gl.glCreateProgram()
    gl.glAttachShader(program, vertex_shader)
    gl.glAttachShader(program, fragment_shader)
    gl.glLinkProgram(program)

    result = gl.glGetProgramiv(program, gl.GL_LINK_STATUS)
    if not (result):
        raise RuntimeError(gl.glGetProgramInfoLog(program))
    return program


VS = '''

attribute vec3 position;


uniform float right;
uniform float bottom;
uniform float left;
uniform float top;
uniform float far;
uniform float near;

void main() {

    mat4 testmat = mat4(
            vec4(2.0 / (right - left), 0, 0, 0),
            vec4(0, 2.0 / (top - bottom), 0, 0),
            vec4(0, 0, -2.0 / (far - near), 0),
            vec4(-(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1)
    );

    gl_Position = testmat * vec4(position, 1.);

}

'''
FS = '''
#version 450
// Output variable of the fragment shader, which is a 4D vector containing the
// RGBA components of the pixel color.
uniform vec3 triangleColor;
out vec4 outColor;

void main()
{
    outColor = vec4(triangleColor, 1.0);
}
'''


class GLPlotWidget3D(QGLWidget):

    def __init__(self, *args):
        # QGLWidget.__init__(self)
        super(GLPlotWidget3D, self).__init__()
        # self.parent = args[0]
        self.width, self.height = 100, 100
        self.right, self.left, self.top, self.bottom = 21000, -21000, 10, -10
        self.data = np.zeros((3, 10, 2))
        self.vbo = glvbo.VBO(self.data)

        self.showMaximized()

    def initializeGL(self):
        vs = Sb.compile_vertex_shader(VS)
        fs = Sb.compile_fragment_shader(FS)
        self.shaders_program = link_shader_program(vs, fs)
        self.e = np.load(('three.npy'), mmap_mode='r')
        self.e = np.array(self.e, dtype=np.float32)

        self.right, self.left, self.top, self.bottom, self.far, self.near = self.e[:, :, 1].min(), self.e[:, : , 1].max(), self.e[:, : , 0].min(), self.e[:, : , 0].max(), self.e[:, : , 2].max(), self.e[:, : , 2].min()

    def ortho_view(self):
        right = gl.glGetUniformLocation(self.shaders_program, "right")
        gl.glUniform1f(right, self.right)

        left = gl.glGetUniformLocation(self.shaders_program, "left")
        gl.glUniform1f(left, self.left)

        top = gl.glGetUniformLocation(self.shaders_program, "top")
        gl.glUniform1f(top, self.top)

        bottom = gl.glGetUniformLocation(self.shaders_program, "bottom")
        gl.glUniform1f(bottom, self.bottom)

        far = gl.glGetUniformLocation(self.shaders_program, "far")
        gl.glUniform1f(far, self.far)

        near = gl.glGetUniformLocation(self.shaders_program, "near")
        gl.glUniform1f(near, self.near)


    def paintGL(self):
        self.resizeGL(self.width, self.height)
        gl.glClearColor(0.2, 0.2, 0.2, 0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)
        gl.glUseProgram(self.shaders_program)

        buffer = gl.glGenBuffers(1)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
        stride = self.e.strides[0]
        offset = ctypes.c_void_p(1)
        loc = gl.glGetAttribLocation(self.shaders_program, "position")
        gl.glEnableVertexAttribArray(loc)
        gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
        gl.glBufferData(gl.GL_ARRAY_BUFFER, self.e.nbytes, self.e, gl.GL_DYNAMIC_DRAW)

        gl.glDrawArrays(gl.GL_LINE_LOOP, 0, self.e.shape[0])

        self.ortho_view()
        uni_color = gl.glGetUniformLocation(self.shaders_program, "triangleColor")
        gl.glUniform3f(uni_color, 0.9, 0.9, 0.9)


    def resizeGL(self, width, height):
        self.width, self.height = width, height
        gl.glViewport(0, 0, width, height)


def main():
    app = QApplication(sys.argv)
    editor = GLPlotWidget3D()
    editor.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

“three.npy”包含一个三维数组(7782 x 24 x3),带有管状体的顶点坐标。尺寸为3的第三维包含顶点的x、y和z坐标。顶点组织在7782个环中,圆周上有24个点

将顶点坐标读取到展平缓冲区(numpy数组将自动展平)。
生成索引数组(顶点缓冲区的索引)。这些索引描述了叠加7781个环的原语。每个环由圆周上的24个四边形组成

self.e=np.load('three.npy'),mmap_mode='r')
self.e=np.array(self.e,dtype=np.float32)
self.elems=[]
环c=self.e.shape[1]
slice_c=self.e.shape[0]
对于范围内的si(切片c-1):
self.elems+=[si*环c,si*环c]
对于范围内的ri(环c+1):
ie=ri%环
self.elems+=[ie+si*环c,ie+(si+1)*环c]
self.elems=np.array(self.elems,dtype=np.int32)
顶点的x和y分量在范围[-10,10]内,但z分量在范围[329724672]内

x最小x最大y最小y最大z最小z最大
-10.589109 10.517833 -10.464569 10.594374 29724672.0 3.1618009
我建议定义z坐标的比例:

self.scaleZ=0.000001
为顶点创建(
GL_数组_缓冲区
),为索引创建(
GL_元素_数组_缓冲区
):

self.vertexbuffer=gl.glGenBuffers(1)
gl.glBindBuffer(gl.gl_数组_BUFFER,self.vertexbuffer)
gl.glBufferData(gl.gl\u数组\u缓冲区、self.e、gl.gl\u动态\u绘图)
self.elementbuffer=gl.glGenBuffers(1)
gl.glBindBuffer(gl.gl\u元素\u数组\u缓冲区,self.elementbuffer)
gl.glBufferData(gl.gl\u元素\u数组\u缓冲区、self.elems、gl.gl\u动态\u绘图)
指定顶点坐标的数组。看见 的步幅和偏移参数必须为0。
步长指定连续通用顶点属性之间的字节偏移量,它必须是
3*self.e.itemsize
(12)或
0
。0具有特殊含义,并将属性解释为紧密打包。如果步幅为0,则由大小和类型参数计算。
偏移量必须为
ctypes.c\u void\u p(0)
None
,因为数组中1属性的偏移量为0。
在任何情况下,步幅和偏移量的单位都是字节

gl.glBindBuffer(gl.gl\u数组\u缓冲区,self.vertexbuffer)
步幅=0#3*self.e.itemsize
偏移量=无#ctypes.c#u void_p(0)
loc=self.attrib['position']
gl.GlenableVertexAttributeArray(loc)
gl.GLVertexAttribute指针(loc,3,gl.gl\U浮点,False,跨步,偏移)
类型为
GL\u TRIANGLE\u STRIP
,绘制元素前必须绑定索引缓冲区:

gl.glBindBuffer(gl.gl\u元素\u数组\u缓冲区,self.elementbuffer)
self.perspective_view()
glUniform3f(自均匀['triangelecolor'],1,1,1)
gl.GLD元素(gl.gl\U三角形\U带,self.elems.size,gl.gl\U无符号\U INT,无)
与在顶点着色器中指定矩阵不同,我建议使用矩阵进行投影,分别用于模型和视图变换。
投影矩阵定义了三维观察体积到二维视口的投影。视图矩阵定义了视图的查看位置和在场景上的查看方向。模型矩阵定义模式的比例和动画

属性向量3位置;
统一材料工程;
统一的mat4 u_视图;
统一mat4-u_模型;
void main(){
gl_位置=u_项目*u_视图*u_模型*vec4(位置,1.0);
}
链接着色器程序后,获取属性索引和统一位置:

vs=编译顶点着色器(vs)
fs=编译片段着色器(fs)
self.shaders_程序=链接_着色器_程序(vs,fs)
self.attrib={a:gl.glGetAttribLocation(self.shaders_program,a)用于['position']}
打印(self.attrib)
self.uniform={u:gl.glGetUniformLocation(self.shaders_program,u)在['u_model'、'u_view'、'u_proj'、'triangleColor']}
打印(自我统一)
对于3D外观,我建议使用而不是。
使用或设置矩阵

投影矩阵 纵横比,ta,近,远=自宽/自高,np.tan(np.radians(90.0)/2),0.1,50 项目=np.矩阵((1/ta/纵横比,0,0,0),(0,1/ta,0,0),(远+近)/(远-近),-1),(0,0,-2*远*近/(远-近),np.32) #视图矩阵 视图=np.矩阵((1,0,0,0),(0,0,-1,0),(0,1,0,0),(0,0,-30,1)),np.32) #模型矩阵 c、 s=math.cos(self.angle),math.sin(self.angle) 模型=比例 gl.glUniformMatrix4fv(自均匀['u_proj'],1,gl.gl_FALSE,proj) gl.glUniformMatrix4fv(自均匀['u_视图'],1,gl.gl_假,视图) gl.glUniformMatrix4fv(自均匀['u_模型'],1,gl.gl_假,模型) 完整示例:
(片段着色器根据片段的深度对其着色)

将OpenGL.GL导入为GL
将OpenGL.arrays.vbo作为glvbo导入
从PyQt5.Qt导入*
将numpy作为np导入
#作为Sb导入后端算法
导入系统
导入ctypes
导入操作系统
输入数学
sourceFileDir=os.path.dirname(os.path.abspath(_文件__))
def编译_顶点_着色器(源):
“”“从源代码编译顶点着色器。”“”
顶点着色器=gl.glCreateShader(gl.gl\u顶点着色器)
gl.glShaderSource(顶点着色器,源)
gl.glCompileShader(顶点着色器)
#检查编译错误
结果=gl.glGetShaderiv(顶点着色器,gl.gl编译状态)
若否(结果):
引发运行时错误(gl.glGetShaderInfoLog(顶点着色器))
ret