Stworzyłem tablicę numeryczną 3-D składającą się z współrzędnych osi X, Y i Z. Teraz staram się stworzyć powierzchnię przy użyciu tych punktów w OpenGL, ale wszystko, co mam sukces, jest tworzenie modelu drutu czegoś takiego poniżej Model "SRC =" https://i.stack.imgur.com/aupgq.png "/>. Czy ktoś może zasugerować zmiany w moim kodzie, aby utworzyć rzeczywistą powierzchnię 3-D z danych? Plik danych Używany link https://drive.google.com/open?id=1PWBNIT3XBCHTQ9HIIS96K7ZJBLZPO_WO 2/a >.

Kod:-

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()
1
AKS 18 styczeń 2020, 09:31

1 odpowiedź

Najlepsza odpowiedź

"Three.npy" zawiera 3 wymiarową tablicę (7782 x 24 x3) z współrzędnymi wierzchołkami rury. I trzeci wymiar o rozmiarze 3 zawiera x , y i z wierzchołki. Wierzchołki organizowane są w 7782 ringach z 24 punktem wokół obwodu.

Przeczytaj współrzędne wierzchołka do bufora spłaszczonego (tablica numpy jest spłaszczona automatycznie przez {{ X0}}).
Wygeneruj tablicę indeksów (wskaźniki bufora wierzchołka). Wskaźniki opisują GL_TRIANGLE_STRIP prymitywy, które stosują 7781 pierścieni. Każdy pierścień składający się z 24 quadów wokół obwodu.

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)

Składnik wierzchołków x Y> i> w zakresie [-10, 10], ale składnik z mieści się w zakresie [3, 29724672].

x min      x max     y min      y max     z min      z max
-10.589109 10.517833 -10.464569 10.594374 29724672.0 3.1618009

Zalecam zdefiniować skalę dla współrzędnych Z:

self.scaleZ = 0.000001

Utwórz Obiekt buforowy VEREX ({x0}}) dla wierzchołków i Obiekt buforów indeksu ({x1}}) dla indeksów:

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)

Określ tablicę współrzędnych wierzchołków. Zobacz Specyfikacja wierzchołka. Parametr i offset z glVertexAttribPointer trzeba wynosić 0.
Stride Określa przesunięcie bajtów między kolejnymi ogólnymi atrybutami wierzchołkami, które musi być 3*self.e.itemsize (12) lub 0. 0 ma szczególne znaczenie i interpretuje atrybuty, aby być ściśle zapakowane. Jeśli Stride jest 0, jest obliczany przez parametr rozmiar i> .
offset Hast, aby być ctypes.c_void_p(0) lub None, ponieważ przesunięcie atrybutu 1 w tablicy wynosi 0.
W każdym razie jednostka krążka offset
jest bajtami.

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)

Prymitywne typ to GL_TRIANGLE_STRIP i bufor indeksowy musi być zobowiązany wcześniej Elementy są narysowane przez {X1}}:

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)

Zamiast określać Matryca ortograficznego w cieniowaniu VERTEX, zalecam używanie matrycy Zmienna jednolita dla projekcji, odpowiednio modelu i przeglądania transformacji.
Matryca projekcyjna określa projekcję 3 wymiarowej objętości oglądania do 2 wymiarowej rzutni. Matryca widoku definiuje pozycję przeglądania widoku i przeglądania kierunku na scenę. Modelowa matryca definiuje skalę i animację trybu.

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);
}

Uzyskaj indeks atrybutu i jednolite lokalizacje po połączeniu programu Shader:

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)

W przypadku wyglądu 3D, polecam użyć Projekcja perspektywiczna a nie Ortoghic Projection.
Użyj numpy.array lub {X1}}, aby ustawić matryce.

# projection matrix
aspect, ta, near, far = self.width/self.height, np.tan(np.radians(90.0) / 2), 0.1, 50
proj = np.matrix(((1/ta/aspect, 0, 0, 0), (0, 1/ta, 0, 0), (0, 0, -(far+near)/(far-near), -1), (0, 0, -2*far*near/(far-near), 0)), np.float32)

# view matrix
view = np.matrix(((1, 0, 0, 0), (0, 0, -1, 0), (0, 1, 0, 0), (0, 0, -30, 1)), np.float32)

# model matrix
c, s = math.cos(self.angle), math.sin(self.angle)
model = scale

gl.glUniformMatrix4fv(self.uniform['u_proj'], 1, gl.GL_FALSE, proj)
gl.glUniformMatrix4fv(self.uniform['u_view'], 1, gl.GL_FALSE, view)
gl.glUniformMatrix4fv(self.uniform['u_model'], 1, gl.GL_FALSE, model)

Powyżony przykład:
(Fragment Shader tints fragmenty zależne od ich głębokości)

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
import os
import math

sourceFileDir = os.path.dirname(os.path.abspath(__file__))

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 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);
}
'''

FS = '''
#version 450
out vec4 outColor;

uniform vec3 triangleColor;

void main()
{
    float d = 1.0 - gl_FragCoord.z;
    outColor = vec4(triangleColor * d, 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 = 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)

        self.e = np.load((os.path.join(sourceFileDir,'three.npy')), mmap_mode='r')
        self.e = np.array(self.e, dtype=np.float32)
        print(self.e.shape)

        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)

        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)

        self.scaleZ = 0.000001
        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()
        print(self.right, self.left, self.top, self.bottom, self.far, self.near)
        self.far *= self.scaleZ
        self.near *= self.scaleZ
        self.angle = 0.0

        self.GLtimer = QTimer()
        self.GLtimer.setInterval(10)
        self.GLtimer.timeout.connect(self.redraw)
        self.GLtimer.start()

    def redraw(self):
        self.angle += 0.01
        self.update()

    def perspective_view(self):

        # projection matrix
        aspect, ta, near, far = self.width/self.height, np.tan(np.radians(90.0) / 2), 10, 50
        proj = np.matrix(((1/ta/aspect, 0, 0, 0), (0, 1/ta, 0, 0), (0, 0, -(far+near)/(far-near), -1), (0, 0, -2*far*near/(far-near), 0)), np.float32)

        # view matrix
        view = np.matrix(((1, 0, 0, 0), (0, 0, -1, 0), (0, 1, 0, 0), (0, 0, -30, 1)), np.float32)

        # model matrix
        c, s = math.cos(self.angle), math.sin(self.angle)
        scale = np.matrix(((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, self.scaleZ, 0), (0, 0, 0, 1)), np.float32)
        rotZ = np.array(((c, s, 0, 0), (-s, c, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), np.float32) 
        rotY = np.matrix(((0, 0, 1, 0), (0, 1, 0, 0), (-1, 0, 0, 0), (0, 0, 0, 1)), np.float32)
        trans = np.matrix(((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, (self.near - self.far)/2, 1)), np.float32)
        model = scale * trans * rotY * rotZ

        gl.glUniformMatrix4fv(self.uniform['u_proj'], 1, gl.GL_FALSE, proj)
        gl.glUniformMatrix4fv(self.uniform['u_view'], 1, gl.GL_FALSE, view)
        gl.glUniformMatrix4fv(self.uniform['u_model'], 1, gl.GL_FALSE, model)


    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.GL_DEPTH_BUFFER_BIT)
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glUseProgram(self.shaders_program)

        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)

        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.elementbuffer)

        self.perspective_view()
        gl.glUniform3f(self.uniform['triangleColor'], 1, 1, 1)
        #gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
        gl.glDrawElements(gl.GL_TRIANGLE_STRIP, self.elems.size, gl.GL_UNSIGNED_INT, None)

    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()
1
Rabbid76 19 styczeń 2020, 18:26