Issue
I have created these triangles to form the greyscale surface of 2-D line plot. Now when I am rotating it using mouse wheel event, there is a gap between the top and bottom line and I want to remove it. Also the program run very slow after using this for loop in greyscale function. Can anyone suggest me any method or way to optimize this and make it work correctly?
code:-
import OpenGL.GL as gl
import OpenGL.arrays.vbo as glvbo
from PyQt5.Qt import *
import numpy as np
import sys
import copy
VS1 = '''
#version 450
layout(location = 0) in vec2 position;
uniform float right;
uniform float bottom;
uniform float left;
uniform float top;
void main() {
const float far = 1.0;
const float near = -1.0;
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.x, position.y, 0., 1.);
}
'''
FS1 = '''
#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);
}
'''
VS = '''
#version 450
attribute vec2 position;
attribute vec3 a_Color;
uniform float right;
uniform float bottom;
uniform float left;
uniform float top;
out vec3 g_color;
void main() {
const float far = 1.0;
const float near = -1.0;
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.x, position.y, 0., 1.);
g_color = a_Color;
}
'''
FS = '''
#version 450
// Output variable of the fragment shader, which is a 4D vector containing the
// RGBA components of the pixel color.
in vec3 g_color;
out vec4 outColor;
void main()
{
outColor = vec4(g_color, 1.0);
}
'''
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
class GLPlotWidget(QGLWidget):
def __init__(self, *args):
super(GLPlotWidget, self).__init__()
self.width, self.height = 100, 100
self.we = np.load('two.npy', mmap_mode='r')
self.e = copy.deepcopy(self.we[:, :, :])
self.right, self.left, self.top, self.bottom = self.e[0, -1, 0], self.e[
0, 0, 0], self.e[0, :, 1].max(), self.e[-1, :, 1].min()
self.vbo = glvbo.VBO(self.e)
self.count = self.vbo.shape[1]
self.scroll = 0
self.number_of_arm = 24
self.linerange = [(self.e[li, :, 1].max(), self.e[-li, :, 1].min()) for li in range(self.vbo.shape[0])]
self.showMaximized()
def initializeGL(self):
vs = compile_vertex_shader(VS1)
fs = compile_fragment_shader(FS1)
self.shaders_program_plot = link_shader_program(vs, fs)
self.greyscale_data()
def greyscale_data(self):
self.color = np.zeros((self.e.shape[1] * (self.e.shape[0]), 3), dtype=np.float32)
for i in range(0, 24):
a = self.e[i, :, 1].min()
b = self.e[i, :, 1].max()
c = np.interp(self.e[i, :, 1], (a, b), (0.15, 0.85))
self.color[self.e.shape[1] * i:self.e.shape[1] * (i + 1), 0] = c
self.color[self.e.shape[1] * i:self.e.shape[1] * (i + 1), 1] = c
self.color[self.e.shape[1] * i:self.e.shape[1] * (i + 1), 2] = c
self.elems = []
b = self.e.shape[1] # number of points per line
a = self.e.shape[0] # total number of arms
for i in range(0, a):
if i < a-1:
for j in range(0, b - 1):
self.elems += [j + b * i, j + b * i + 1, j + b * (i + 1)]
self.elems += [j + b * (i + 1), j + b * (i + 1) + 1, j + b * i + 1]
else:
for j in range(0, b - 1):
self.elems += [j + b * i, j + b * i + 1, j]
self.elems += [j, j + 1, j + b * i + 1]
self.elems = np.array(self.elems, dtype=np.int32)
# print(self.elems[0:100])
vs = compile_vertex_shader(VS)
fs = compile_fragment_shader(FS)
self.shaders_program = link_shader_program(vs, fs)
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.colorbuffer = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.colorbuffer)
gl.glBufferData(gl.GL_ARRAY_BUFFER, self.color, gl.GL_DYNAMIC_DRAW)
def ortho_view(self, i):
right = gl.glGetUniformLocation(i, "right")
gl.glUniform1f(right, self.right)
left = gl.glGetUniformLocation(i, "left")
gl.glUniform1f(left, self.left)
top = gl.glGetUniformLocation(i, "top")
gl.glUniform1f(top, self.top)
bottom = gl.glGetUniformLocation(i, "bottom")
gl.glUniform1f(bottom, self.bottom)
def greyscale(self):
gl.glUseProgram(self.shaders_program)
self.ortho_view(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 = gl.glGetAttribLocation(self.shaders_program, 'position')
gl.glEnableVertexAttribArray(loc)
gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, stride, offset)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.elementbuffer)
loc = gl.glGetAttribLocation(self.shaders_program, 'a_Color')
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.colorbuffer)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
loc_top1 = gl.glGetUniformLocation(self.shaders_program, "top")
loc_bottom1 = gl.glGetUniformLocation(self.shaders_program, "bottom")
for i in range(0, 24):
size = self.top - self.bottom
top, bottom = self.top + self.scroll, self.bottom + self.scroll
if self.linerange[i][0] - self.scroll < self.bottom:
top, bottom = top - size, bottom - size
gl.glUniform1f(loc_top1, top)
gl.glUniform1f(loc_bottom1, bottom)
a = int(i * self.elems.size)
b = int((i+1) * self.elems.size)
c = int(self.elems.size/24)
# gl.glDrawElements(gl.GL_TRIANGLE_STRIP, self.elems.size, gl.GL_UNSIGNED_INT, None)
gl.glDrawRangeElements(gl.GL_TRIANGLE_STRIP, a, b, self.elems.size, gl.GL_UNSIGNED_INT, None)
def paintGL(self):
self.resizeGL(self.width, self.height)
gl.glClearColor(1, 1, 1, 0)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glEnable(gl.GL_DEPTH_TEST)
self.vbo.bind()
gl.glEnableVertexAttribArray(0)
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, gl.GL_FALSE, 0, None)
gl.glUseProgram(self.shaders_program_plot)
self.ortho_view(self.shaders_program_plot)
uni_color = gl.glGetUniformLocation(self.shaders_program_plot, "triangleColor")
loc_top = gl.glGetUniformLocation(self.shaders_program_plot, "top")
loc_bottom = gl.glGetUniformLocation(self.shaders_program_plot, "bottom")
for i in range(0, self.vbo.data.shape[0]):
size = self.top - self.bottom
top, bottom = self.top + self.scroll, self.bottom + self.scroll
if self.linerange[i][0] - self.scroll < self.bottom:
top, bottom = top - size, bottom - size
gl.glUniform1f(loc_top, top)
gl.glUniform1f(loc_bottom, bottom)
gl.glUniform3f(uni_color, 0, 0, 0)
gl.glLineWidth(1)
gl.glDrawArrays(gl.GL_LINE_STRIP, i * self.count, self.count)
self.vbo.unbind()
self.greyscale()
# gl.glUseProgram(0)
def resizeGL(self, width, height):
self.width, self.height = width, height
gl.glViewport(0, 0, width, height)
def wheelEvent(self, *args, **kwargs):
event = args[0]
scroll_scale = 0.01
size = self.top - self.bottom
if event.angleDelta().y() > 0:
self.scroll = self.scroll - size * scroll_scale
if self.scroll < 0:
self.scroll += size
else:
self.scroll = self.scroll + size * scroll_scale
if self.scroll > size:
self.scroll -= size
self.update()
def main():
app = QApplication(sys.argv)
editor = GLPlotWidget()
editor.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
data file:- https://drive.google.com/file/d/1y6w35kuMguR1YczK7yMJpXU86T6qtGSv/view?usp=sharing
Solution
Add a straight line at the at the bin and the end of the data.
Compute the minimum and the maximum of the original data, the y scale of the data and the average offset from one line to another:
origshape = self.e.shape[:]
origmin, origmax = self.e[0, :, 1].max(), self.e[-1, :, 1].min()
origsize = origmax - origmin
origoffset = origsize / origshape[0]
Compute a new minimum and maximum with an certain offset (origoffset/2
) and add a straight line at the begin and the end. Copy the first and last line and change the y component of the new lines by newmax
respectively newmin
newmin, newmax = origmin - origoffset/2, origmax + origoffset/2
self.first = self.e[0,:,:].copy().reshape((1, *origshape[1:]))
self.last = self.e[-1,:,:].copy().reshape((1, *origshape[1:]))
self.first[:,:,1] = newmax
self.last[:,:,1] = newmin
self.e = np.concatenate((self.first, self.e, self.last))
New constructor of GLPlotWidget
:
class GLPlotWidget(QGLWidget):
def __init__(self, *args):
super(GLPlotWidget, self).__init__()
self.width, self.height = 100, 100
self.we = np.load('two.npy', mmap_mode='r')
self.e = copy.deepcopy(self.we[:, :, :])
origshape = self.e.shape[:]
origmin, origmax = self.e[-1, :, 1].min(), self.e[1, :, 1].max()
origsize = origmax - origmin
origoffset = origsize / origshape[0]
newmin, newmax = origmin - origoffset/2, origmax + origoffset/2
self.first = self.e[0,:,:].copy().reshape((1, *origshape[1:]))
self.last = self.e[-1,:,:].copy().reshape((1, *origshape[1:]))
self.first[:,:,1] = newmax
self.last[:,:,1] = newmin
self.e = np.concatenate((self.first, self.e, self.last))
self.right, self.left, self.top, self.bottom = self.e[0, -1, 0], self.e[
0, 0, 0], self.e[0, :, 1].max(), self.e[-1, :, 1].min()
self.vbo = glvbo.VBO(self.e)
self.count = self.vbo.shape[1]
self.scroll = 0
self.number_of_arm = 24
self.linerange = [(self.e[li, :, 1].max(), self.e[-li, :, 1].min()) for li in range(self.vbo.shape[0])]
self.showMaximized()
Answered By - Rabbid76
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.