我创建了一个由X,Y和Z轴坐标组成的3-d numpy数组。现在,我正在尝试使用opengl中的这些点来创建曲面,但我成功完成的工作就是在下创建线模型。谁能建议我对代码进行更改以根据数据形成实际的3D表面?数据文件使用链接https://drive.google.com/open?id=1PWbNIt3xbchtQ9HIIS96k7ZjblzPO_wO
代码:-
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'包含一个3维数组(7782 x 24 x3),具有管的顶点坐标。尺寸为3的第3维包含顶点的x,y和z坐标。顶点以7782环的形式组织,圆周周围有24个点。
将顶点坐标读取到展平缓冲区(numpy数组由glBufferData
自动展平)。生成索引数组(顶点缓冲区的索引)。索引描述堆积了7781个环的glBufferData
原语。每个环由圆周上的24个四边形组成。
GL_TRIANGLE_STRIP
顶点的x和y分量在[-10,10]范围内,但是z分量在[3,29724672]范围内。
GL_TRIANGLE_STRIP
我建议为z坐标定义比例尺:
self.e = np.load(('three.npy'), mmap_mode='r')
self.e = np.array(self.e, dtype=np.float32)
self.elems = []
ring_c = self.e.shape[1]
slice_c = self.e.shape[0]
for si in range(slice_c-1):
self.elems += [si*ring_c, si*ring_c]
for ri in range(ring_c+1):
ie = ri % ring_c
self.elems += [ie+si*ring_c, ie+(si+1)*ring_c]
self.elems = np.array(self.elems, dtype=np.int32)
为顶点创建x min x max y min y max z min z max
-10.589109 10.517833 -10.464569 10.594374 29724672.0 3.1618009
(self.scaleZ = 0.000001
),为索引创建Vertex Buffer Object(GL_ARRAY_BUFFER
):
Index buffer Object
指定顶点坐标数组。参见GL_ELEMENT_ARRAY_BUFFER
。self.vertexbuffer = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexbuffer)
gl.glBufferData(gl.GL_ARRAY_BUFFER, self.e, gl.GL_DYNAMIC_DRAW)
self.elementbuffer = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.elementbuffer)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, self.elems, gl.GL_DYNAMIC_DRAW)
的stride和偏移量parameter必须为0。stride指定连续通用顶点属性之间的字节偏移,它必须为Vertex Specification(12)或glVertexAttribPointer
。 0具有特殊含义,并且会将属性解释为紧密包装。如果stride为0,则由size和type参数计算。offset不必为glVertexAttribPointer
或3*self.e.itemsize
,因为数组中1属性的偏移量为0。在任何情况下,stride和offset的单位都是字节。
0
ctypes.c_void_p(0)
类型为None
,并且必须先绑定索引缓冲区,然后才能用gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vertexbuffer)
stride = 0 # 3*self.e.itemsize
offset = None # ctypes.c_void_p(0)
loc = self.attrib['position']
gl.glEnableVertexAttribArray(loc)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
绘制元素:
primitive
而不是在顶点着色器中指定GL_TRIANGLE_STRIP
矩阵,我建议对投影,模型转换和视图转换分别使用矩阵glDrawElements
。投影矩阵定义了3D视区到2D视口的投影。视图矩阵定义了视图的观看位置和场景上的观看方向。模型矩阵定义了模式的比例和动画。
glDrawElements
链接着色器程序后获取属性索引和统一位置:
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.elementbuffer)
self.perspective_view()
gl.glUniform3f(self.uniform['triangleColor'], 1, 1, 1)
gl.glDrawElements(gl.GL_TRIANGLE_STRIP, self.elems.size, gl.GL_UNSIGNED_INT, None)
对于3D外观,我建议使用Orthographic projection而不是Uniform variable。使用attribute vec3 position;
uniform mat4 u_proj;
uniform mat4 u_view;
uniform mat4 u_model;
void main() {
gl_Position = u_proj * u_view * u_model * vec4(position, 1.0);
}
或vs = compile_vertex_shader(VS)
fs = compile_fragment_shader(FS)
self.shaders_program = link_shader_program(vs, fs)
self.attrib = { a : gl.glGetAttribLocation (self.shaders_program, a) for a in ['position'] }
print(self.attrib)
self.uniform = { u : gl.glGetUniformLocation (self.shaders_program, u) for u in ['u_model', 'u_view', 'u_proj', "triangleColor"] }
print(self.uniform)
设置矩阵。
Perspective projection
完整示例:(片段着色器根据片段的深度来着色片段)
numpy.array