OpenGL python drawing circle little detail missing? - python

I implemented a draw circle function, it's almost done, but this is how it looks like:
def drawCicrcle(x, y, z, radius, numSides):
numVertices = numSides + 2
doublePi = 2.0 * math.pi
circleVerticesX = np.array([], dtype='f')
circleVerticesY = np.array([], dtype='f')
circleVerticesZ = np.array([], dtype='f')
circleVerticesX = np.insert(circleVerticesX, 0, x)
circleVerticesY = np.insert(circleVerticesX, 0, y)
circleVerticesZ = np.insert(circleVerticesX, 0, z)
for i in range(1, numVertices):
circleVerticesX = np.append(
circleVerticesX, x + (radius * math.cos(i * doublePi / numSides)))
circleVerticesY = np.append(
circleVerticesY, y + (radius * math.sin(i * doublePi / numSides)))
circleVerticesZ = np.append(circleVerticesZ, z)
allCircleVertices = np.array([], dtype='f')
for i in range(0, numVertices):
allCircleVertices = np.insert(
allCircleVertices, i*3, circleVerticesX[i])
allCircleVertices = np.insert(
allCircleVertices, (i*3) + 1, circleVerticesY[i])
allCircleVertices = np.insert(
allCircleVertices, (i*3) + 2, circleVerticesZ[i])
vboc = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vboc)
glBufferData(GL_ARRAY_BUFFER, allCircleVertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False,
sizeof(ctypes.c_float)*9, ctypes.c_void_p(36))
glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices)
And I call in my main drawCicrcle(-0.5, 0.5, 0.0, 0.18, 360)
What am I missing?

circleVerticesX = np.array([numVertices], dtype='f') doesn't do what you expect it to do. It creates a numpy array with a single element with the value numVertices (see numpy.array).
Create a list with the vertex coordinates and create a numpy array from the list:
vertex_list = [...]
# [...]
allCircleVertices = np.array([vertex_list], dtype='f')
Function drawCicrcle:
def drawCicrcle(x, y, z, radius, numSides):
numVertices = numSides + 2
doublePi = 2.0 * math.pi
vertex_list = [x, y, z]
for i in range(1, numVertices):
vertex_list.append(x + (radius * math.cos(i * doublePi / numSides)))
vertex_list.append(y + (radius * math.sin(i * doublePi / numSides)))
vertex_list.append(z)
allCircleVertices = np.array([vertex_list], dtype='f')
vboc = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vboc)
glBufferData(GL_ARRAY_BUFFER, allCircleVertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 3*sizeof(ctypes.c_float), ctypes.c_void_p(0))
glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices)
Alternatively create an empty numpy array with numVertices*3 elements (see numpy.empty) and assign the vertex coordinates to the fields of the array:
allCircleVertices = np.array([vertex_list], dtype='f')
allCircleVertices[0:3] = [x, y, z]
# [...]
Function drawCicrcle:
def drawCicrcle(x, y, z, radius, numSides):
numVertices = numSides + 2
doublePi = 2.0 * math.pi
allCircleVertices = np.empty((numVertices*3), dtype='f')
allCircleVertices[0:3] = [x, y, z]
for i in range(1, numVertices):
vx = x + (radius * math.cos(i * doublePi / numSides))
vy = y + (radius * math.sin(i * doublePi / numSides))
allCircleVertices[i*3:i*3+3] = [vx, vy, z]
vboc = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vboc)
glBufferData(GL_ARRAY_BUFFER, allCircleVertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 3*sizeof(ctypes.c_float), ctypes.c_void_p(0))
glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices)

Related

random lines between rendered objects python

I am making a very basic 3d engine. When I render 2 or more objects, it draws lines between them. I do not know why this happens, as I coded the pen to go up after drawing every triangle. A strange thing is that when I draw a background line, each object also draws lines to the background line. I am confused. There is only 1 reason I could think of; it uses the last point of the other object as the first point of the first triangle of the main object. However, it does not seem like this is the case, as it is even happening with a simple line in the background as well.
from turtle import*
from time import*
from math import*
wn=Screen()
speed(0)
ht()
pu()
wn.tracer(0,0)
fov=200
camx=0
camy=0
camz=-5
xoff=0
yoff=0
zoff=0
xrot=pi*2
yrot=pi
zrot=pi
def goto3d(x,y,z):
rotxx=x
rotxy=y*cos(yrot)-z*sin(yrot)
rotxz=y*sin(yrot)+z*cos(yrot)
rotyx=rotxx*cos(xrot)+rotxz*sin(xrot)
rotyy=rotxy
rotyz=rotxz*cos(xrot)-rotxx*sin(xrot)
rotzx=rotyx*cos(zrot)-rotyy*sin(zrot)
rotzy=rotyx*sin(zrot)+rotyy*cos(zrot)
rotzz=rotyz
transx=rotzx-xoff
transy=rotzy-yoff
transz=rotzz-zoff
newx=fov*transx/transz
newy=fov*transy/transz
if transz<0.1 or newx<=-200 or newy<=-200 or newx>=200 or newy>=200:
return
goto(newx,newy)
def triangle(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z):
goto3d(p1x,p1y,p1z)
pd()
goto3d(p2x,p2y,p2z)
goto3d(p3x,p3y,p3z)
goto3d(p1x,p1y,p1z)
pu()
def face(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z,p4x,p4y,p4z,r,g,b,a):
fillcolor(r,g,b,a)
begin_fill()
triangle(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z)
end_fill()
begin_fill()
triangle(p2x,p2y,p2z,p3x,p3y,p3z,p4x,p4y,p4z)
end_fill()
def bbox(x,y,z,w,h,l,r,g,b,a):
x+=camx
y+=camy
z+=camz
face(x+-w,y+h,z+l,x+w,y+h,z+l,x+-w,y+-h,z+l,x+w,y+-h,z+l,r,g,b,a)
face(x+-w,y+h,z+-l,x+w,y+h,z+-l,x+-w,y+-h,z+-l,x+w,y+-h,z+-l,r,g,b,a)
face(x+-w,y+h,z+l,x+-w,y+h,z+-l,x+-w,y+-h,z+l,x+-w,y+-h,z+-l,r,g,b,a)
face(x+w,y+h,z+l,x+w,y+h,z+-l,x+w,y+-h,z+l,x+w,y+-h,z+-l,r,g,b,a)
face(x+-w,y+-h,z+l,x+-w,y+-h,z+-l,x+w,y+-h,z+l,x+w,y+-h,z+-l,r,g,b,a)
face(x+-w,y+h,z+l,x+-w,y+h,z+-l,x+w,y+h,z+l,x+w,y+h,z+-l,r,g,b,a)
def box(x,y,z,w,h,l,r,g,b):
if w>=2 or h>=2 or l>=2:
bbox(x-(w/4),y-(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x+(w/4),y-(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x+(w/4),y+(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x-(w/4),y+(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x-(w/4),y-(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x+(w/4),y-(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x+(w/4),y+(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
bbox(x-(w/4),y+(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
else:
bbox(x,y,z,w,h,l,r,g,b,.5)
def render():
goto(-200,-5)
pd()
goto(200,-5)
pu()
### ||| objects go here ||| ###
### ||| format is box(x,y,z,width,height,length,r,g,b) ||| ###
box(2,0,-5,2,2,2,0,255,255)
box(0,0,0,1,1,1,255,0,0)
def tl():
global xrot
xrot-=pi/40
def tr():
global xrot
xrot+=pi/40
def f():
global camx
global camz
camz+=.3*cos(-xrot)
camx+=-(.3*sin(-xrot))
def b():
global camx
global camz
camz+=-(.3*cos(-xrot))
camx+=.3*sin(-xrot)
wn.onkey(tl,'Left')
wn.onkey(tr,'Right')
wn.onkey(f,'Up')
wn.onkey(b,'Down')
wn.listen()
while True:
clear()
render()
update()
When I render 2 or more objects, it draws lines between them. I do not
know why this happens
The problem happens even when you only have one object -- comment out your first (small blue) box and just move the second (large red) one:
The problem is in goto3d() and triangle() as goto3d() has a failure situation (which it tests for) that it doesn't signal back to triangle() so it goes ahead and continues drawing.
Below is my rework of your code to patch this issue (and translate the code into Python ;-)
from turtle import Screen, Turtle
from math import pi, sin, cos
fov = 200
camx = 0
camy = 0
camz = -5
xoff = 0
yoff = 0
zoff = 0
xrot = pi * 2
yrot = pi
zrot = pi
def goto3d(x, y, z):
rotxx = x
rotxy = y * cos(yrot) - z * sin(yrot)
rotxz = y * sin(yrot) + z * cos(yrot)
rotyx = rotxx * cos(xrot) + rotxz * sin(xrot)
rotyy = rotxy
rotyz = rotxz * cos(xrot) - rotxx * sin(xrot)
rotzx = rotyx * cos(zrot) - rotyy * sin(zrot)
rotzy = rotyx * sin(zrot) + rotyy * cos(zrot)
rotzz = rotyz
transx = rotzx - xoff
transy = rotzy - yoff
transz = rotzz - zoff
if transz < 0.1:
return False
newx = fov * transx/transz
newy = fov * transy/transz
if not -200 < newx < 200 or not -200 < newy < 200:
return False
turtle.goto(newx, newy)
return True
def triangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z):
if goto3d(p1x, p1y, p1z):
turtle.pendown()
turtle.begin_fill()
goto3d(p2x, p2y, p2z)
goto3d(p3x, p3y, p3z)
goto3d(p1x, p1y, p1z)
turtle.end_fill()
turtle.penup()
def face(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z, p4x, p4y, p4z, color):
turtle.fillcolor(color)
triangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z)
triangle(p2x, p2y, p2z, p3x, p3y, p3z, p4x, p4y, p4z)
def bbox(x, y, z, w, h, l, color):
x += camx
y += camy
z += camz
face(x - w, y + h, z + l, x + w, y + h, z + l, x - w, y - h, z + l, x + w, y - h, z + l, color)
face(x - w, y + h, z - l, x + w, y + h, z - l, x - w, y - h, z - l, x + w, y - h, z - l, color)
face(x - w, y + h, z + l, x - w, y + h, z - l, x - w, y - h, z + l, x - w, y - h, z - l, color)
face(x + w, y + h, z + l, x + w, y + h, z - l, x + w, y - h, z + l, x + w, y - h, z - l, color)
face(x - w, y - h, z + l, x - w, y - h, z - l, x + w, y - h, z + l, x + w, y - h, z - l, color)
face(x - w, y + h, z + l, x - w, y + h, z - l, x + w, y + h, z + l, x + w, y + h, z - l, color)
def box(x, y, z, w, h, l, color):
if w >= 2 or h >= 2 or l >= 2:
# transparent_color = (*color, 0.2)
transparent_color = color
bbox(x - w/4, y - h/4, z - l/4, w/4, h/4, l/4, transparent_color)
bbox(x + w/4, y - h/4, z - l/4, w/4, h/4, l/4, transparent_color)
bbox(x + w/4, y + h/4, z - l/4, w/4, h/4, l/4, transparent_color)
bbox(x - w/4, y + h/4, z - l/4, w/4, h/4, l/4, transparent_color)
bbox(x - w/4, y - h/4, z + l/4, w/4, h/4, l/4, transparent_color)
bbox(x + w/4, y - h/4, z + l/4, w/4, h/4, l/4, transparent_color)
bbox(x + w/4, y + h/4, z + l/4, w/4, h/4, l/4, transparent_color)
bbox(x - w/4, y + h/4, z + l/4, w/4, h/4, l/4, transparent_color)
else:
# transparent_color = (*color, 0.5)
transparent_color = color
bbox(x, y, z, w, h, l, transparent_color)
def render():
turtle.clear()
turtle.goto(-200, -5)
turtle.pendown()
turtle.goto(200, -5)
turtle.penup()
### ||| objects go here ||| ###
### ||| format is box(x, y, z, width, height, length, (r, g, b)) ||| ###
box(2, 0, -5, 2, 2, 2, (0, 255, 255))
box(0, 0, 0, 1, 1, 1, (255, 0, 0))
screen.update()
screen.ontimer(render)
def tl():
global xrot
xrot -= pi/40
def tr():
global xrot
xrot += pi/40
def f():
global camx, camz
camz += 0.3 * cos(-xrot)
camx += -(0.3 * sin(-xrot))
def b():
global camx, camz
camz += -(0.3 * cos(-xrot))
camx += 0.3 * sin(-xrot)
screen = Screen()
screen.tracer(0)
screen.colormode(255)
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
screen.onkey(tl, 'Left')
screen.onkey(tr, 'Right')
screen.onkey(f, 'Up')
screen.onkey(b, 'Down')
screen.listen()
render()
screen.mainloop()
I disabled transparency as my system doesn't support it, but you can uncomment the appropriate lines to put it back.

Stellar chart with Python

I came across this article. I wonder if it is possible to make a stellar chart with Python? (see picture).
I have had a look at the matplotlib and seaborn galleries, but apparently they do not have any built in function to create such a chart (neither radar charts).
Is there any way to draw a chart like this easily using Python?
Following is a rendition of a StellarChart, as per your specifications.
It is derived from a SpiderChart (a RadarChart) build with tkinter to answer an earlier question
You can see them both side by side hereunder:
It takes a list of tuples('label', score), with the score expressed as a percentage (value in the interval [0, 100]).
The number of data points adjusts to the data provided.
The scale of the chart can be adjusted.
import math
import tkinter as tk
class SpiderChart(tk.Canvas):
"""a canvas that displays datapoints as a SpiderChart
"""
width=500
height=500
def __init__(self, master, datapoints, concentrics=10, scale=200):
super().__init__(master, width=self.width, height=self.height)
self.scale = scale
self.center = self.width // 2, self.height // 2
self.labels = tuple(d[0] for d in datapoints)
self.values = tuple(d[1] for d in datapoints)
self.num_pts = len(self.labels)
self.concentrics = [n/(concentrics) for n in range(1, concentrics + 1)]
self.draw()
def position(self, x, y):
"""use +Y pointing up, and origin at center
"""
cx, cy = self.center
return x + cx, cy - y
def draw_circle_from_radius_center(self, radius):
rad = radius * self.scale
x0, y0 = self.position(-rad, rad)
x1, y1 = self.position(rad, -rad)
return self.create_oval(x0, y0, x1, y1, dash=(1, 3))
def draw_label(self, idx, label):
angle = idx * (2 * math.pi) / self.num_pts
d = self.concentrics[-1] * self.scale
x, y = d * math.cos(angle), d * math.sin(angle)
self.create_line(*self.center, *self.position(x, y), dash=(1, 3))
d *= 1.1
x, y = d * math.cos(angle), d * math.sin(angle)
self.create_text(*self.position(x, y), text=label)
def draw_polygon(self):
points = []
for idx, val in enumerate(self.values):
d = (val / 100) * self.scale
angle = idx * (2 * math.pi) / self.num_pts
x, y = d * math.cos(angle), d * math.sin(angle)
points.append(self.position(x, y))
self.create_polygon(points, fill='cyan')
def draw(self):
self.draw_polygon()
for concentric in self.concentrics:
self.draw_circle_from_radius_center(concentric)
for idx, label in enumerate(self.labels):
self.draw_label(idx, label)
class StellarChart(SpiderChart):
"""a canvas that displays datapoints as a StellarChart
"""
def draw_polygon(self):
points = []
da = math.pi / self.num_pts
b = .05 * self.scale
for idx, val in enumerate(self.values):
d = (val / 100) * self.scale
angle = idx * (2 * math.pi) / self.num_pts
x, y = d * math.cos(angle), d * math.sin(angle)
points.append(self.position(x, y))
xb, yb = b * math.cos(angle + da), b * math.sin(angle+da)
points.append(self.position(xb, yb))
self.create_polygon(points, width=3, outline='red', fill='pink', join=tk.ROUND)
data = [('stamina', 70), ('python-skill', 100), ('strength', 80), ('break-dance', 66), ('speed', 45), ('health', 72), ('healing', 90), ('energy', 12), ('libido', 100)]
root = tk.Tk()
stellar = StellarChart(root, data)
stellar.pack(side=tk.LEFT)
spider = SpiderChart(root, data)
spider.pack(side=tk.LEFT)
root.mainloop()
The Plotly library includes a starchart: https://plotly.com/python/radar-chart/

How do I use roll, pitch and yaw to fuse in with my 3-D points points to make a 3-D surface?

I have a array of 3-D points in a way like that each 24 set of 3-D points are on a same plane and they form roughly a circle. I am trying to add the data of roll, pitch and yaw to the dataset such that each 24 set of point after applying the rotation angles about the axis formulates the circle in such a way that it appears to be in a tube form which is bending. The code that I am using formulates this into a surface using OpenGL. Data collected is from a IMU travelled inside a pipe.
The problem I am facing is as I apply this data to create this tube diagrammed, until rotation along Z-axis(which is roll) everything seems to be fine but when I multiply the rotation matrix along x and y axis the output is skewed and completely wrong. Can anyone point what I am doing wrong in my code
This is the code I have made for rotation
import numpy as np
roll = np.load("tube_roll.npy")
pitch = np.load("tube_pitch.npy")
yaw = np.load("tube_yaw.npy")
data = np.load("three_d.npy")
def matrix_angle(angle, a, b, c, d, e):
cos = np.cos(angle)
sin = np.sin(angle)
zer = np.zeros((angle.shape[0], 3,3))
zer[:, a[0], a[1]] = 1
zer[:, b[0], b[1]] = cos
zer[:, c[0], c[1]] = -sin
zer[:, d[0], d[1]] = sin
zer[:, e[0], e[1]] = cos
return zer
rot_along_x = matrix_angle(yaw, [0, 0], [1, 1], [1, 2], [2, 1], [2, 2])
rot_along_y = matrix_angle(pitch, [1, 1], [0, 0], [2, 0], [0, 2], [2, 2])
rot_along_z = matrix_angle(roll, [2, 2], [0, 0], [0, 1], [1, 0], [1, 1])
a = []
for j in range(0, len(rot_along_z)):
b = []
for i in range(0, 24):
dd = np.dot(rot_along_z[j], data[j, i, :])
dd = np.dot(rot_along_y[j], dd)
dd = np.dot(rot_along_x[j], dd)
b.append(dd)
a.append(b)
a = np.array(a)
np.save("three_data.npy", a)
And this is what I am using for making the 3-D view.
import OpenGL.GL as gl
import OpenGL.arrays.vbo as glvbo
from PyQt5.Qt import *
import numpy as np
import math
import sys
VS = '''
attribute vec3 position;
attribute vec3 a_Color;
uniform mat4 u_proj;
uniform mat4 u_view;
uniform mat4 u_model;
out vec3 g_color;
void main() {
gl_Position = u_proj * u_view * u_model * vec4(position, 1.0);
g_color = a_Color;
}
'''
FS = '''
#version 450
in vec3 g_color;
out vec4 outColor;
void main()
{
float d = 1.0 - gl_FragCoord.z;
outColor = vec4(g_color * d, 1.0);
}
'''
class CreateTubeWindow(QMainWindow):
def __init__(self, *args):
super(CreateTubeWindow, self).__init__()
self.setWindowTitle('3-D Pipeline View')
self.plot = GLPlotWidget3D(self)
self.setCentralWidget(self.plot)
[_, w] = Sb.screen_size()
self.setGeometry(w[2]/2-50, w[3]/2-50, w[2]/2-50, w[3]/2-50)
self.plot.show()
self.show()
class GLPlotWidget3D(QGLWidget):
def __init__(self, *args):
# QGLWidget.__init__(self)
super(GLPlotWidget3D, self).__init__()
self.parent_s = args[0]
self.parent_s = self.parent_s
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.x = 0
self.y = 0
self.vxb, self.vyb = 0, 0
self.count = 0
# self.showMaximized()
# self.show()
def initializeGL(self):
vs = Sb.compile_vertex_shader(VS)
fs = Sb.compile_fragment_shader(FS)
self.shaders_program_tube = Sb.link_shader_program(vs, fs)
self.attrib = {a: gl.glGetAttribLocation(self.shaders_program_tube, a) for a in ['position', 'a_Color']}
self.uniform = {u: gl.glGetUniformLocation(self.shaders_program_tube, u) for u in
['u_model', 'u_view', 'u_proj']}
self.roll = np.load('tube_roll.npy')
self.pitch = np.load('tube_pitch.npy')
self.yaw = np.load('tube_yaw.npy')
self.e = np.load("three_data.npy")
self.e = np.array(self.e, dtype=np.float32)
self.color = np.zeros((self.e.shape[0]*self.e.shape[1], 3), dtype=np.float32)
self.color.fill(1.0)
self.elems = self.elements_array(self.e.shape[0], self.e.shape[1])
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.colorbuffer = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.colorbuffer)
gl.glBufferData(gl.GL_ARRAY_BUFFER, self.color, gl.GL_DYNAMIC_DRAW)
self.scaleZ = 30/self.e[:, :, 2].max()
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()
self.far *= self.scaleZ
self.near *= self.scaleZ
self.angle = 0.962
self.angle_y = 133.544
self.zoom = True
self.zoom_c = 90.0
self.zoom_cv = 0.0
def perspective_view(self):
# projection matrix
aspect, ta, near, far = self.width / self.height, np.tan(np.radians(self.zoom_c) / 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)
cy, sy = math.cos(self.angle_y), math.sin(self.angle_y)
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(((cy, 0, sy, 0), (0, 1, 0, 0), (-sy, 0, cy, 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_tube)
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()
loc = self.attrib['a_Color']
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.colorbuffer)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
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 mouseMoveEvent(self, e):
if self.zoom:
v = self.x-e.x()
if v > 2:
self.angle -= 0.01
elif v < -2:
self.angle += 0.01
self.x = e.x()
w = self.y-e.y()
if w > 2:
self.angle_y += 0.01
elif w < -2:
self.angle_y -= 0.01
self.y = e.y()
else:
if e.x() > self.zoom_cv:
self.zoom_c -= 1
else:
self.zoom_c += 1
self.zoom_cv = e.x()
self.update()
def keyPressEvent(self, k):
if k.key() == 16777249:
self.zoom = False
def keyReleaseEvent(self, k):
if k.key() == 16777249:
self.zoom = True
def wheelEvent(self, w):
e = w.angleDelta().y()
if e > 0:
self.zoom_c -= 1
else:
self.zoom_c += 1
self.update()
def elements_array(self, a, b):
ring_c = b
slice_c = a
my_si = np.arange(slice_c - 1)
my_elems = np.repeat(ring_c * my_si, 2)
temp = np.empty(2 * my_si.size, my_si.dtype)
temp[0::2] = my_si
temp[1::2] = my_si + 1
my_ri = np.arange(ring_c + 1)
my_ie = np.expand_dims(my_ri % ring_c, axis=1)
my_si = temp * ring_c + my_ie
my_elems = np.vstack((my_elems, my_si))
N = my_elems.shape[1] // (slice_c - 1)
return my_elems.reshape((my_elems.shape[0], -1, N)).swapaxes(0, 1).reshape(
(np.prod(my_elems.shape), -1)).squeeze()
if __name__ == '__main__':
app = QApplication(sys.argv)
editor = CreateTubeWindow()
sys.exit(app.exec_())
What I feel is I am doing something wrong with my rotation matrix as the output of rotation along Z-axis seems wrong as it's initially in a sort of 2-D plane but as we go further matrix multiplication increased the value of x and y coordinate also which should not happen.
Also below are the data file used
https://drive.google.com/file/d/177knYTSmlWcC1RQjcXf-CKICWr09MU_i/view?usp=sharing
Either use numpy.matmul for matrix multiplications:
rot_mat = np.matmul(rot_along_x, np.matmul(rot_along_y, rot_along_z))
or use the matrix multiplication (#) operator (see array ):
rot_mat = rot_along_z # rot_along_y # rot_along_x
Use numpy.dot to transform the vertices:
a = np.array([[np.dot(v, rot_mat) for v in row] for row in data])

flip texture when drawing it pyopengl

I recently downloaded a batch rendering program that uses pyOpenGl and pygame. I want to edit the draw function such that there is the ability to flip a texture when drawing it. This is the code for the batch rendering program.
import numpy
from OpenGL import GL
from OpenGL.GL import shaders
import ctypes
def setup_shaders(vpMatrix):
global shaderProgram, vshader, fshader
global texCoordAttribute, positionAttribute
vshader = shaders.compileShader('''#version 440
layout (location = 0) uniform mat4 vpMatrix;
layout (location = 0) in vec2 vPosition;
layout (location = 1) in vec2 vTexCoord0;
//layout (location = 2) in vec4 vVertColor;
out vec2 texCoord0;
//out vec4 vertColor;
void main(void) {
gl_Position = vpMatrix * vec4(vPosition, 0.0, 1.0);
texCoord0 = vTexCoord0;
}''', GL.GL_VERTEX_SHADER)
fshader = shaders.compileShader('''#version 440
in vec2 texCoord0;
//in vec4 vertColor;
layout (location = 1) uniform sampler2D u_texture0;
void main(void) {
gl_FragColor = texture2D(u_texture0, texCoord0);
}''', GL.GL_FRAGMENT_SHADER)
shaderProgram = shaders.compileProgram(vshader, fshader)
texCoordAttribute = GL.glGetAttribLocation(shaderProgram, 'vTexCoord0')
positionAttribute = GL.glGetAttribLocation(shaderProgram, 'vPosition')
texUniform = GL.glGetUniformLocation(shaderProgram, 'u_texture0')
GL.glEnableVertexAttribArray(positionAttribute)
GL.glEnableVertexAttribArray(texCoordAttribute)
GL.glUseProgram(shaderProgram)
GL.glUniformMatrix4fv(
GL.glGetUniformLocation(shaderProgram, 'vpMatrix'),
1,
False,
vpMatrix,
)
GL.glUniform1i(texUniform, 0)
# TODO: cleanup (delete shaders)
class GLTexture:
def __init__(self, textureId, width, height):
self.texture = textureId
self.width, self.height = width, height
def delete(self):
GL.glDeleteTextures([self.texture])
class GLTextureRegion:
def __init__(self, glTexture, subX, subY, subWidth, subHeight):
self.texture = glTexture
#self.tx, self.ty = subX, subY
self.tw, self.th = subWidth, subHeight
self.normalizedCoords = (
subX / glTexture.width, subY / glTexture.height,
(subX + subWidth) / glTexture.width, subY / glTexture.height,
subX / glTexture.width, (subY + subHeight) / glTexture.height,
(subX + subWidth) / glTexture.width, (subY + subHeight) / glTexture.height,
)
def write_tex_coords(self, aj):
nc = self.normalizedCoords
aj[4 * 0 + 2] = nc[0]
aj[4 * 0 + 3] = nc[1]
aj[4 * 1 + 2] = nc[2]
aj[4 * 1 + 3] = nc[3]
aj[4 * 2 + 2] = nc[4]
aj[4 * 2 + 3] = nc[5]
aj[4 * 3 + 2] = nc[6]
aj[4 * 3 + 3] = nc[7]
def write_vertices(self, aj, x, y):
aj[4 * 0 + 0] = x
aj[4 * 0 + 1] = y
aj[4 * 1 + 0] = x + self.tw
aj[4 * 1 + 1] = y
aj[4 * 2 + 0] = x
aj[4 * 2 + 1] = y + self.th
aj[4 * 3 + 0] = x + self.tw
aj[4 * 3 + 1] = y + self.th
def update_array(self, vboData, arrayIndex, x, y):
aj = vboData[arrayIndex]
self.write_vertices(aj, x, y)
self.write_tex_coords(aj)
def delete(self):
'''deletes the underlying texture'''
self.texture.delete()
class Batch:
def __init__(self, maxQuads = 10000):
self.maxQuads = maxQuads
self.vboIndices = GL.glGenBuffers(1)
GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, self.vboIndices)
vidA = []
for i in range(maxQuads):
vidA.extend([
4 * i + 0,
4 * i + 2,
4 * i + 1,
4 * i + 2,
4 * i + 1,
4 * i + 3
])
self.vboIndexData = numpy.array(vidA, numpy.ushort)
del vidA
GL.glBufferData(
GL.GL_ELEMENT_ARRAY_BUFFER,
self.vboIndexData,
GL.GL_STATIC_DRAW,
)
self.vbo = GL.glGenBuffers(1) # texture coords & vertices
GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbo)
self.vboData = numpy.zeros((maxQuads, 4 * 4), numpy.float32)
GL.glBufferData(
GL.GL_ARRAY_BUFFER,
self.vboData,
GL.GL_DYNAMIC_DRAW
)
self.currentTexture = None
self.objectIndex = 0
def begin(self):
GL.glBindBuffer(
GL.GL_ARRAY_BUFFER,
self.vbo,
)
if self.currentTexture:
GL.glBindTexture(
GL.GL_TEXTURE_2D,
self.currentTexture.texture,
)
GL.glEnable(GL.GL_TEXTURE_2D)
GL.glActiveTexture(GL.GL_TEXTURE0)
def draw(self, textureRegion, x, y, flip = False):
if self.currentTexture != textureRegion.texture:
self.flush()
self.currentTexture = textureRegion.texture
GL.glBindTexture(
GL.GL_TEXTURE_2D,
textureRegion.texture.texture,
)
elif self.objectIndex >= self.maxQuads:
self.flush()
textureRegion.update_array(
self.vboData,
self.objectIndex,
x, y
)
self.objectIndex += 1
def end(self):
self.flush()
def flush(self):
if not self.objectIndex:
return
GL.glVertexAttribPointer(
texCoordAttribute,
2,
GL.GL_FLOAT,
GL.GL_TRUE,
4 * self.vboData.itemsize,
ctypes.c_void_p(2 * self.vboData.itemsize)
)
GL.glVertexAttribPointer(
positionAttribute,
2,
GL.GL_FLOAT,
GL.GL_FALSE,
4 * self.vboData.itemsize,
ctypes.c_void_p(0)
)
GL.glBufferSubData(
GL.GL_ARRAY_BUFFER,
0,
16 * self.objectIndex * self.vboData.itemsize,
self.vboData,
)
GL.glDrawElements(
GL.GL_TRIANGLES,
6 * self.objectIndex,
GL.GL_UNSIGNED_SHORT,
ctypes.c_void_p(0),
)
self.objectIndex = 0
def delete(self):
GL.glDeleteBuffers(1, [self.vbo])
GL.glDeleteBuffers(1, [self.vboIndices])
So far I have tried a few things involving glscalef(as suggested by answers I found on the internet) however I couldn't get it to have any effect on the textures. Is there a way to make this work within the draw function or do I have to try another method entirely?
You can "flip" y component of the texture coordinate in the vertex shader:
void main(void) {
// [...]
texCoord0 = vec2(vTexCoord0.x, 1.0 - vTexCoord0.y);
}
If you want to "flip" individually textures, then you to flip the texture coordinate attributes. Pass either True or False to the argument flipY:
class GLTextureRegion:
# [...]
def write_tex_coords(self, aj, flipY):
nc = self.normalizedCoords
for i in range(4):
aj[i*4 + 2] = nc[i*2]
aj[i*4 + 3] = 1-nc[i*2 + 1] if flipY else nc[i*2 + 1]
# [...]
def update_array(self, vboData, arrayIndex, x, y, flipY):
aj = vboData[arrayIndex]
self.write_vertices(aj, x, y)
self.write_tex_coords(aj, flipY)
Alternatively you can scale the texture coordinates by in the vertex shader by a uniform. Initialize the uniform by
layout (location = 0) uniform mat4 vpMatrix;
layout (location = 1) uniform vec2 uTexCoordScale;
layout (location = 0) in vec2 vPosition;
layout (location = 1) in vec2 vTexCoord0;
out vec2 texCoord0;
void main(void)
{
gl_Position = vpMatrix * vec4(vPosition, 0.0, 1.0);
texCoord0 = uTexCoordScale * vTexCoord0;
}
Initialize the uniform uTexCoordScale by (1.0, 1.0) and change it to (1.0, -1.0) if you want to "flip" the texture.

Problem making Sphere using PyOpenGL and PyQt5 [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I am trying to make sphere with OpenGL in Python but only single red dot appears in the center of screen. My code is as follow
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
try:
glUseProgram(self.shader)
glBindVertexArray(self.vao)
glDrawArrays(GL_POINTS, 0, int(self.buff_size/3))
finally:
glBindVertexArray(0)
glUseProgram(0)
def geometry(self):
self.vao = glGenVertexArrays(1)
self.vbo = glGenBuffers(1)
lats = 180
longs = 360
r = 0.5
data = []
for i in range(lats):
lat0 = np.pi * (-0.5 + (i - 1) / lats)
z0 = np.sin(lat0)
zr0 = np.cos(lat0)
lat1 = np.pi * (-0.5 + i / lats)
z1 = np.sin(lat1)
zr1 = np.cos(lat1)
for j in range(longs):
lng = 2 * np.pi * (j - 1) / longs
x_cord = np.cos(lng)
y = np.sin(lng)
data.extend([x_cord * zr0, y * zr0, z0])
data.extend([r * x_cord * zr0, r * y * zr0, r * z0])
data.extend([x_cord * zr1, y * zr1, z1])
data.extend([r * x_cord * zr1, r * y * zr1, r * z1])
data_input = np.array(data, dtype=np.float32)
self.buff_size = len(data_input)
vertex_size = int(data_input.nbytes / self.buff_size) * 3
glUseProgram(self.shader)
glBindVertexArray(self.vao)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, data_input.nbytes, data_input, GL_DYNAMIC_DRAW)
self.vertex_position = glGetAttribLocation(self.shader, 'position')
glVertexAttribPointer(self.vertex_position, 3, GL_FLOAT, GL_FALSE, vertex_size, None)
glEnableVertexAttribArray(self.vertex_position)
glDisableVertexAttribArray(self.vertex_position)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glUseProgram(0)
Shader for my program is:
self.vertex_shader = shaders.compileShader(
"""
#version 330
in vec3 pos;
uniform mat4 movement;
void main()
{
gl_Position = movement * vec4(pos, 1.0);
}
"""
, GL_VERTEX_SHADER
)
self.fragment_shader = shaders.compileShader(
"""
#version 330
out vec4 gl_FragColor;
void main()
{
gl_FragColor = vec4(1.0,0.0,0.5,1.0);
}
"""
, GL_FRAGMENT_SHADER
)
self.shader = shaders.compileProgram(self.vertex_shader, self.fragment_shader)
I don't know where I'm having issue. I also tried using indices with GL_ELEMENT_ARRAY_BUFFER and glDrawElements as GL_QUAD_STRIP but no success. If you know how I can fix this then please share. Thanks
The name of the vertex attribute is pos:
in vec3 pos;
So the argument to glGetAttribLocation has to be 'pos' rather than 'position':
self.vertex_position = glGetAttribLocation(self.shader, 'position')
self.vertex_position = glGetAttribLocation(self.shader, 'pos')
If the specification and enable state is stored in the Vertex Array Object. If you glDisableVertexAttribArray(self.vertex_position), this state is stored to the self.vao. Remove it:
glBindVertexArray(self.vao)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
glBufferData(GL_ARRAY_BUFFER, data_input.nbytes, data_input, GL_DYNAMIC_DRAW)
self.vertex_position = glGetAttribLocation(self.shader, 'pos')
glVertexAttribPointer(self.vertex_position, 3, GL_FLOAT, GL_FALSE, vertex_size, None)
glEnableVertexAttribArray(self.vertex_position)
#glDisableVertexAttribArray(self.vertex_position) # <--- DELETE
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
A matrix unfiorm be default is initialized with all fields 0.
uniform mat4 movement;
If you do not need the uniform, then remove it. Or initialize it by the Identity matrix.
glUseProgram(self.shader)
ident4x4 = np.identity(4, np.float32)
self.movement_loc = glGetUniformLocation(self.shader, 'movement')
glUniformMatrix4fv(self.movement_loc, 1, GL_FALSE, ident4x4)
Alternatively you can use a view and perspective projection matrix (self.width and self.height are the width and height of the window):
# projection matrix
aspect, ta, near, far = self.width/self.height, np.tan(np.radians(90.0) / 2), 0.1, 10
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, 1, 0, 0), (0, 0, 1, 0), (0, 0, -3, 1)), np.float32)
glUniformMatrix4fv(self.movement_loc, 1, GL_FALSE, view * proj)

Categories