Spot light shining on a flat surface - python

I want to shine a nice spotlight on a flat surface. I know that lighting is done per vertex and thus have create may vertices on the surface -- see this answer. However, I am getting these -- with GL_QUADS and GL_LINE_STRIP just to check that I have done things correctly.
These are clearly rather poor. so,
What need I chance so that the spotlight appears more like a circle on the surface?
How can I draw this scene faster?
Note: I realise that the normal calculation is not strictly necessary in this case but in a general case, it would be needed. Also, I could use a display list for the surface so it was only drawn once.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
from Numeric import *
lightPosition = np.array([10, 30, 20, 1])
view_rotation = np.array([0, 0, 0])
def init():
globAmb = [0.3, 0.3, 0.3, 1.0]
lightAmb = [0.0, 0.0, 0.0, 1.0]
lightDifAndSpec = [0.7, 0.7, 0.7, 1.0]
glutInit()
glClearColor(0.0, 0.0, 0.0, 0.0)
glEnable(GL_DEPTH_TEST)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glShadeModel(GL_SMOOTH)
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb)
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDifAndSpec)
glLightfv(GL_LIGHT0, GL_SPECULAR, lightDifAndSpec)
glEnable(GL_LIGHT0)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb)
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
def display():
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
gluLookAt(0.0, 40.0, 40.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glRotatef(view_rotation[0], 1.0, 0.0, 0.0)
glRotatef(view_rotation[1], 0.0, 1.0, 0.0)
glRotatef(view_rotation[2], 0.0, 0.0, 1.0)
glPushMatrix()
pos = [0, 20, 0, 1]
direction = [0.0, -1.0, 0.0]
spotAngle = 20
glLightfv(GL_LIGHT0, GL_POSITION, pos)
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, spotAngle)
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction)
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 2)
glPushMatrix();
glDisable(GL_LIGHTING)
glTranslate(pos[0], 0.5* pos[1], pos[2])
glRotatef(-90.0, 1.0, 0.0, 0.0)
glColor3f(1.0, 1.0, 1.0)
PI = 3.141592
glutWireCone(3.0 * np.tan( spotAngle/180.0 * PI ), pos[1], 10, 6)
glEnable(GL_LIGHTING)
glPopMatrix();
draw_cube()
glPopMatrix()
glFlush ()
def reshape(w, h):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(w) / float(h), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
def keyboard(key, x, y):
if key == chr(27):
sys.exit(0)
elif key == 'w':
view_rotation[0] += 10
display()
elif key == 's':
view_rotation[0] -= 10
display()
elif key == 'a':
view_rotation[1] -= 10
display()
elif key == 'd':
view_rotation[1] += 10
display()
else:
print "Unknown %s key" %(key)
def draw_cube ():
glPushMatrix()
glRotatef(45, 0, 1, 0)
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, [183/256.0, 65/256.0, 14/256.0, 1.0]);
glMaterialfv(GL_FRONT, GL_SPECULAR, [1, 1, 1, 1]);
glMaterialfv(GL_FRONT, GL_SHININESS, [100.0]);
sz = 10
step = 1
for x in arange(-sz, sz, step):
for z in arange(-sz, sz, step):
v0 = np.array([x, sz, z])
v1 = np.array([x, sz, z+step])
v2 = np.array([x+step, sz, z+step])
v3 = np.array([x+step, sz, z])
#glBegin(GL_QUADS) # Uncomment to get the surface instead of lines.
glBegin(GL_LINE_STRIP)
n = get_normal_vector(v0, v1, v3)
glNormal(n[0], n[1], n[2])
glVertex3f(v0[0], v0[1], v0[2])
n = get_normal_vector(v1, v2, v0)
glNormal(n[0], n[1], n[2])
glVertex3f(v1[0], v1[1], v1[2])
n = get_normal_vector(v2, v3, v1)
glNormal(n[0], n[1], n[2])
glVertex3f(v2[0], v2[1], v2[2])
n = get_normal_vector(v3, v0, v2)
glNormal(n[0], n[1], n[2])
glVertex3f(v3[0], v3[1], v3[2])
glEnd()
glPopMatrix()
def get_normal_vector (v1, v2, v3):
v = np.cross(v2-v1, v3-v1)
n = np.sqrt(np.dot(v, v.conj()))
if n:
return v/n
else:
print v1
print v2
print v3
print v/n
sys.exit(-1)
glutInit(sys.argv)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowSize(800, 800)
glutInitWindowPosition(300, 0)
glutCreateWindow('Lines')
init()
glutDisplayFunc(display)
glutReshapeFunc(reshape)
glutKeyboardFunc(keyboard)
glutMainLoop()
PS: I will update an answer with the source code using a shader when I have it working...

Use a fragment shader to render the spotlight. This is also the fastest way you can render the scene because you won't be increasing tessellation, yet get the highest quality lighting.
Hope this helps!

Related

How do I set the position of my object in 3d space with python OpenGL and Pygame [duplicate]

I am pretty new in using PyOpenGL and I want to load an obj file, move it, then draw a sphere and move it. I want the two objects to move separately when I use different keyboard buttons. Is it possible? (I also need the coordinate of the center of each object).
The problem is that they both move even if I use Push and Pop matrix commands
Here is my code:
rom objloader import *
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, OPENGL | DOUBLEBUF)
glMatrixMode(GL_PROJECTION)
gluPerspective(45.0, display[0]/display[1], 0.1, 100.0)
glLightfv(GL_LIGHT5, GL_POSITION, (-40, 200, 100, 0.0))
glLightfv(GL_LIGHT5, GL_AMBIENT, (0.2, 0.2, 0.2, 1.0))
glLightfv(GL_LIGHT5, GL_DIFFUSE, (0.5, 0.5, 0.5, 1.0))
glEnable(GL_LIGHT5)
glEnable(GL_LIGHTING)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH)
glMatrixMode(GL_MODELVIEW)
glTranslatef(0, 0, -5)
x = 0
y = 0
z = - 5
xx = 0
yy = 0
zz = -5
# LOAD OBJECT
obj = OBJ(sys.argv[1], swapyz=True)
sphere = gluNewQuadric() #Create new sphere
model = glGetDoublev(GL_MODELVIEW_MATRIX)
rx, ry = (0,0)
tx, ty = (0,0)
zpos = 5
rotate = move = False
clock = pygame.time.Clock()
while 1:
clock.tick(30)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Clear the screen
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN:
sys.exit()
keypress = pygame.key.get_pressed()
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glLoadIdentity()
if keypress[pygame.K_w]:
glTranslatef(0,-0.01,0)
y = y - 0.01
if keypress[pygame.K_s]:
glTranslatef(0,0.01,0)
y = y + 0.01
if keypress[pygame.K_d]:
glTranslatef(0.01,0,0)
x = x + 0.01
if keypress[pygame.K_a]:
glTranslatef(-0.01,0,0)
x = x - 0.01
if keypress[pygame.K_z]:
glTranslatef(0, 0, -0.01)
z = z - 0.01
if keypress[pygame.K_x]:
glTranslatef(0,0,0.01)
z = z + 0.01
if keypress[pygame.K_0]:
start = x, y, z
print('start is', start)
#model = glGetDoublev(GL_MODELVIEW_MATRIX)
glMultMatrixf(model)
model = glGetDoublev(GL_MODELVIEW_MATRIX)
glMultMatrixf(model)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glScalef(0.1, 0.1, 0.1)
glColor4f(0.5, 0.2, 0.2, 1)
gluSphere(sphere, 1.0, 32, 16)
glPopMatrix()
glPushMatrix()
glLoadIdentity()
if keypress[pygame.K_u]:
glTranslatef(0,-0.01,0)
yy = yy - 0.01
if keypress[pygame.K_j]:
glTranslatef(0,0.01,0)
yy = yy + 0.01
if keypress[pygame.K_k]:
glTranslatef(0.01,0,0)
xx = xx + 0.01
if keypress[pygame.K_h]:
glTranslatef(-0.01,0,0)
xx = xx - 0.01
if keypress[pygame.K_n]:
glTranslatef(0, 0, -0.01)
zz = zz - 0.01
if keypress[pygame.K_m]:
glTranslatef(0,0,0.01)
zz = zz + 0.01
if keypress[pygame.K_l]:
glRotatef(1, 0, 1, 5)
xx = xx*math.cos(rad)-y*math.sin(rad)
yy = xx*math.sin(rad)+yy*math.cos(rad)
if keypress[pygame.K_g]:
#glTranslatef(xx, yy, zz)
glRotatef(1, 0, 1, -5)
#glTranslatef(-xx, -yy, -zz)
rad = 1*180/math.pi
xx = xx*math.cos(rad)-yy*math.sin(rad)
yy = xx*math.sin(rad)+yy*math.cos(rad)
print(xx, yy, math.sin( rad))
if keypress [pygame.K_9]:
print('obj coord', xx, yy, zz)
glMultMatrixf(model)
model = glGetDoublev(GL_MODELVIEW_MATRIX)
glMultMatrixf(model)
#glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) --> se lo metti non vedi l'oggetto prima
glScalef(0.1, 0.1, 0.1)
glCallList(obj.gl_list)
glPopMatrix()
pygame.display.flip() #Update the screen
main()
The problem is that they both move even if I use Push and Pop matrix commands
The model matrix defines the position orientation and scale of a single object (mesh) in the scene. Thus you need a separate model matrix for each object:
def main():
# [...]
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, display[0]/display[1], 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -5)
model_1 = glGetDoublev(GL_MODELVIEW_MATRIX)
model_2 = model_1
# [...]
while 1:
# [...]
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
# Model 1
glPushMatrix()
glLoadIdentity()
# rotate and translate model 1
# [...]
glMultMatrixf(model_1)
model_1 = glGetDoublev(GL_MODELVIEW_MATRIX)
glScalef(0.1, 0.1, 0.1)
# draw model 1
glColor4f(0.5, 0.2, 0.2, 1)
gluSphere(sphere, 1.0, 32, 16)
glPopMatrix()
# Model 2
glPushMatrix()
glLoadIdentity()
# rotate and translate model 2
# [...]
glMultMatrixf(model_2)
model_2 = glGetDoublev(GL_MODELVIEW_MATRIX)
glScalef(0.1, 0.1, 0.1)
# draw model 1
glCallList(obj.gl_list)
glPopMatrix()
pygame.display.flip() #Update the screen

Consider a circle (𝑥 − 40) 2 + (𝑦 − 40) 2 = 400. Rotate it along X- axis counter clockwise 30 degree & translate it along Z- axis for +20 units

Write a PYOpenGL code for this operation.
I am able to draw the circle but my code for rotating and translating is not working. The code is executing but not giving the correct result. Help me with the rotation and translation part of the question.
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from math import *
def circle():
posx, posy = 40,40
sides = 80
radius = 20
glBegin(GL_POLYGON)
for i in range(100):
cosine= radius * cos(i*2*pi/sides) + posx
sine = radius * sin(i*2*pi/sides) + posy
glVertex2f(cosine,sine)
glEnd()
def iterate():
glViewport(0, 0, 3000, 3000)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# glMatrixMode(GL_MODELVIEW)
# glLoadIdentity()
# glTranslatef(0, 0, -3)
# glRotatef(50, 1, 0, 0)
# glRotatef(70, 0, 1, 0)
glOrtho(0.0, 500, 0.0, 500, 0.0, 1.0)
glMatrixMode (GL_MODELVIEW)
glLoadIdentity()
def showScreen():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
iterate()
glColor3f(1.0, 0.0, 3.0)
circle()
glutSwapBuffers()
glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(400, 400)
glutInitWindowPosition(200, 200)
wind = glutCreateWindow("OpenGL Coding Practice")
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMainLoop()
When you transalte the circle along the z axis or rotate the circle it is clipped by the near (= 0) and far plane (= 1) of the Orthographic projection.
Change the distance to the near and far plane (e.g. -100 and 100):
glOrtho(0.0, 500, 0.0, 500, 0.0, 1.0)
glOrtho(0.0, 500, 0.0, 500, -100, 100)
iterate function:
def iterate():
glViewport(0, 0, 3000, 3000)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, 500, 0.0, 500, -100, 100)
glMatrixMode (GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, 20)
glRotatef(30, 1, 0, 0)

python opengl with glfw mouse wheel zoom too further.the camera cover data object

i have two questions.
I's normal in most cases when i use mouse wheel to zoom in.Once I zoom in to a certain level,it will zoom in farther.(near the center)
When the object(line or triangle) through the screan,some part of the object will be covered.
as shown below
Here's my code.I don't know how should i change it.
Mouse scroll function: scroll_callback
the camera cover data: how to set the camera boundary
from math import pi
from threading import Thread
import glfw
import glm
import numpy as np
from OpenGL.GL import *
from OpenGL.GL.shaders import compileShader, compileProgram
gl_shape = {'lines': GL_LINES, 'line_strip': GL_LINE_STRIP, 'triangles': GL_TRIANGLES,
'triangle_strip': GL_TRIANGLE_STRIP}
gl_draw = {'seldom': GL_STATIC_DRAW, 'often': GL_DYNAMIC_DRAW, 'always': GL_STREAM_DRAW}
class MyOpenGL(Thread):
instances = {}
first_instance = {}
def __new__(cls, *args, **kwargs):
instance = kwargs.get('instance')
if instance not in cls.instances:
cls.instances[instance] = super().__new__(cls)
cls.first_instance[instance] = True # 判断是否是第一次创建
return cls.instances[instance]
def __init__(self, title: str = 'opengl_title', instance: str = None, draw_axis=True, axis_len=1.0):
super().__init__()
if not self.__class__.first_instance.get(instance): # 判断是否是第一次创建
return
self.__class__.first_instance[instance] = False
self.vertex_src = """
# version 330
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_color;
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
out vec3 v_color;
void main()
{
gl_Position = projection * view * model * vec4(a_position, 1.0);
v_color = a_color;
}
""" # vec4(a_position, 1); 1指物体大小,越大越小
self.fragment_src = """
# version 330
in vec3 v_color;
out vec4 out_color;
void main()
{
out_color = vec4(v_color, 1.0);
}
"""
self.width = 1280
self.height = 720
self.eye = glm.vec3(0, 0, 3) # 眼睛的位置(默认z轴的正方向)
self.target = glm.vec3(0, 0, 0) # 瞄准方向的参考点(默认在坐标原点)
self.up = glm.vec3(0, 1, 0) # 定义对观察者而言的上方(默认y轴的正方向)
self.near = 0.1
self.far = 100
self.radians = glm.radians(45)
self.projection = glm.perspective(self.radians, self.width / self.height, self.near, self.far)
self.view = glm.lookAt(self.eye, self.target, self.up)
self.pan_start = None
self.orbit_start = None
self.pivot_world = None
self.draw_axis = draw_axis
self.axis_len = axis_len
self.title = title
self.window = None
self.program = None
self.vao = {}
self.to_bind_data = {}
self.vao_draw_args = {}
self.vao_index = 1
self.data_change = False
def glfw_init(self, title='opengl_title'):
if not glfw.init():
print("Cannot initialize GLFW")
exit()
self.window = glfw.create_window(self.width, self.height, title, None, None)
if not self.window:
glfw.terminate()
glfw.make_context_current(self.window)
def draw_axis_func(self, length=1.0):
axis = np.array([
length, 0.0, 0.0, 1.0, 0.0, 0.0,
-length, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, length, 0.0, 0.0, 1.0, 0.0,
0.0, -length, 0.0, 0.0, 1.0, 0.0,
0.0, 0.0, length, 0.0, 0.0, 1.0,
0.0, 0.0, -length, 0.0, 0.0, 1.0,
], np.float32)
self.vao['default_axis'] = glGenVertexArrays(1)
self.vao_draw_args['default_axis'] = glDrawArrays, (GL_LINES, 0, int(len(axis) / 6))
glBindVertexArray(self.vao['default_axis'])
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, axis.nbytes, axis, GL_STATIC_DRAW)
glEnableVertexAttribArray(0) # 准备设置glsl。即vertex_src中的layout(location = 0)的属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, axis.itemsize * 6, ctypes.c_void_p(0))
glEnableVertexAttribArray(1) # 准备设置glsl。即vertex_src中的layout(location = 1)的属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, axis.itemsize * 6, ctypes.c_void_p(12))
def depth(self, x, y):
depth_buffer = glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)
depth_ = float(depth_buffer[0][0])
if depth_ == 1:
pt_drag = glm.vec3(0, 0, 0)
clip_pos = self.projection * self.view * glm.vec4(pt_drag, 1)
ndc_pos = glm.vec3(clip_pos) / clip_pos.w
if -1 < ndc_pos.z < 1:
depth_ = ndc_pos.z * 0.5 + 0.5
return depth_
# def update_fps_counter(self):
# """ 显示帧率 update_fps_counter(window)"""
# self.previous_seconds = self.__dict__.get('previous_seconds') or 0
# self.fps = self.__dict__.get('previous_seconds') or 0
# self.frame_count = self.__dict__.get('previous_seconds') or 0
# current_seconds = glfw.get_time()
# elapsed_seconds = current_seconds - self.previous_seconds
# if elapsed_seconds > 0.25:
# self.previous_seconds = current_seconds
# self.fps = self.frame_count / elapsed_seconds
# print(self.fps)
# self.frame_count = 0
# self.frame_count += 1
def window_size_callback(self, window, width, height):
glViewport(0, 0, width, height)
# 旋转速度随窗口变化而变化
self.width, self.height = width, height
self.projection = glm.perspective(self.radians, width / height, self.near, self.far)
def mouse_button_callback(self, window, button, action, mods):
x_pos, y_pos = glfw.get_cursor_pos(window)
y_pos = self.height - y_pos
if button == glfw.MOUSE_BUTTON_RIGHT and action == glfw.PRESS:
self.pan_start = glm.vec3(x_pos, y_pos, self.depth(x_pos, y_pos))
if button == glfw.MOUSE_BUTTON_LEFT and action == glfw.PRESS:
self.orbit_start = glm.vec3(x_pos, y_pos, self.depth(x_pos, y_pos))
self.pivot_world = glm.vec3(0, 0, 0)
def cursor_pos_callback(self, window, x_pos, y_pos):
y_pos = self.height - y_pos
# get view matrix and viewport rectangle
view, inv_view = self.view, glm.inverse(self.view)
view_rect = glm.vec4(0, 0, self.width, self.height)
if glfw.get_mouse_button(window, glfw.MOUSE_BUTTON_RIGHT) == glfw.PRESS:
# get drag start and end
wnd_from = self.pan_start
wnd_to = glm.vec3(x_pos, y_pos, self.pan_start[2])
self.pan_start = wnd_to
# get projection and window matrix
inv_proj = glm.inverse(self.projection)
inv_wnd = glm.translate(glm.mat4(1), glm.vec3(-1, -1, -1))
inv_wnd = glm.scale(inv_wnd, glm.vec3(2 / view_rect[2], 2 / view_rect[3], 2))
inv_wnd = glm.translate(inv_wnd, glm.vec3(view_rect[0], view_rect[1], 0))
# calculate drag start and world coordinates
pt_h_world = [inv_view * inv_proj * inv_wnd * glm.vec4(*pt, 1) for pt in [wnd_from, wnd_to]]
pt_world = [glm.vec3(pt_h) / pt_h.w for pt_h in pt_h_world]
# calculate drag world translation
world_vec = pt_world[1] - pt_world[0]
# translate view position and update view matrix
inv_view = glm.translate(glm.mat4(1), world_vec * -1) * inv_view
view = glm.inverse(inv_view)
elif glfw.get_mouse_button(window, glfw.MOUSE_BUTTON_LEFT) == glfw.PRESS:
# get the drag start and end
wnd_from = self.orbit_start
wnd_to = glm.vec3(x_pos, y_pos, self.orbit_start[2])
self.orbit_start = wnd_to
# calculate the pivot, rotation axis and angle
pivot_view = glm.vec3(view * glm.vec4(*self.pivot_world, 1))
orbit_dir = wnd_to - wnd_from
# get the projection of the up vector to the view port
# TODO
# calculate the rotation components for the rotation around the view space x axis and the world up vector
orbit_dir_x = glm.vec2(0, 1)
orbit_vec_x = glm.vec2(0, orbit_dir.y)
orbit_dir_up = glm.vec2(1, 0)
orbit_vec_up = glm.vec2(orbit_dir.x, 0)
# calculate the rotation matrix around the view space x axis through the pivot
rot_pivot_x = glm.mat4(1)
if glm.length(orbit_vec_x) > 0.5:
axis_x = glm.vec3(-1, 0, 0)
angle_x = glm.dot(orbit_dir_x, glm.vec2(orbit_vec_x.x / (view_rect[2] - view_rect[0]),
orbit_vec_x.y / (view_rect[3] - view_rect[1]))) * pi
rot_mat_x = glm.rotate(glm.mat4(1), angle_x, axis_x)
rot_pivot_x = glm.translate(glm.mat4(1), pivot_view) * rot_mat_x * glm.translate(glm.mat4(1),
-pivot_view)
# calculate the rotation matrix around the world space up vector through the pivot
rot_pivot_up = glm.mat4(1)
if glm.length(orbit_vec_up) > 0.5:
axis_up = glm.vec3(0, 0, 1)
angle_up = glm.dot(orbit_dir_up, glm.vec2(
orbit_vec_up.x / (view_rect[2] - view_rect[0]),
orbit_vec_up.y / (view_rect[3] - view_rect[1]))) * pi
rot_mat_up = glm.rotate(glm.mat4(1), angle_up, axis_up)
rot_pivot_up = glm.translate(
glm.mat4(1), self.pivot_world) * rot_mat_up * glm.translate(glm.mat4(1), -self.pivot_world)
# transform and update view matrix
view = rot_pivot_x * view * rot_pivot_up
self.view = view
def scroll_callback(self, window, x_offset, y_offset):
x, y = glfw.get_cursor_pos(window)
y = self.height - y
view_rect = glm.vec4(0, 0, self.width, self.height)
# get view, projection and window matrix
proj, inv_proj = self.projection, glm.inverse(self.projection)
view, inv_view = self.view, glm.inverse(self.view)
inv_wnd = glm.translate(glm.mat4(1), glm.vec3(-1, -1, -1))
inv_wnd = glm.scale(inv_wnd, glm.vec3(2 / view_rect[2], 2 / view_rect[3], 2))
inv_wnd = glm.translate(inv_wnd, glm.vec3(view_rect[0], view_rect[1], 0))
wnd = glm.inverse(inv_wnd)
# get world space position on view ray
pt_wnd = glm.vec3(x, y, 1.0)
# pt_world = glm.unProject(pt_wnd, view, proj, vp_rect)
pt_h_world = inv_view * inv_proj * inv_wnd * glm.vec4(*pt_wnd, 1)
pt_world = glm.vec3(pt_h_world) / pt_h_world.w
# get view position
eye = glm.vec3(inv_view[3])
# get "zoom" direction and amount
ray_cursor = glm.normalize(pt_world - eye)
# translate view position and update view matrix
inv_view = glm.translate(glm.mat4(1), ray_cursor * y_offset) * inv_view
# return new view matrix
self.view = glm.inverse(inv_view)
def set_data(self, data, data_name=None, frequency=None, shape=None, indices=None):
if data_name is None:
data_name = self.vao_index
self.vao_index += 1
# print(data_name)
self.to_bind_data[data_name] = (data, frequency, shape, indices)
return data_name
def bind_data(self):
if not self.to_bind_data:
return
for data_name in list(self.to_bind_data.keys()):
self.vao[data_name] = glGenVertexArrays(1)
data, frequency, shape, indices = self.to_bind_data[data_name]
glBindVertexArray(self.vao[data_name])
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
glBufferData(GL_ARRAY_BUFFER, sum(len(i) for i in data) * 4, None, gl_draw.get(frequency, GL_STATIC_DRAW))
offset = 0
for d in data:
glBufferSubData(GL_ARRAY_BUFFER, offset, d.nbytes, d)
offset += d.nbytes
if indices is not None:
ebo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
length = sum(len(i) for i in indices) * 4
glBufferData(GL_ELEMENT_ARRAY_BUFFER, length, None, gl_draw.get(frequency, GL_STATIC_DRAW))
offset = 0
for i, sub_arr in enumerate(indices):
arr = (ctypes.c_uint32 * sub_arr.nbytes)(*(sub_arr + 4 * i))
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, sub_arr.nbytes, arr)
offset += sub_arr.nbytes
prop = glDrawElements, (gl_shape.get(shape, GL_LINE_STRIP), length, GL_UNSIGNED_INT, None)
else:
# 最后一个参数为画几个点
prop = glDrawArrays, (gl_shape.get(shape, GL_LINE_STRIP), 0, sum(int(len(d) / 6) for d in data))
self.vao_draw_args[data_name] = prop
glEnableVertexAttribArray(0) # 准备设置glsl。即vertex_src中的layout(location = 0)的属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * 6, ctypes.c_void_p(0))
glEnableVertexAttribArray(1) # 准备设置glsl。即vertex_src中的layout(location = 1)的属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 4 * 6, ctypes.c_void_p(12)) # 3*arr.itemsize
self.to_bind_data.pop(data_name)
def draw_data(self):
for n in self.vao:
glBindVertexArray(self.vao[n])
self.vao_draw_args[n][0](*self.vao_draw_args[n][1])
# print(self.vao_draw_args[n][0],self.vao_draw_args[n][1])
def run(self):
self.glfw_init(self.title)
if self.draw_axis:
self.draw_axis_func(self.axis_len)
glfw.set_window_size_callback(self.window, self.window_size_callback)
glfw.set_mouse_button_callback(self.window, self.mouse_button_callback)
glfw.set_cursor_pos_callback(self.window, self.cursor_pos_callback)
glfw.set_scroll_callback(self.window, self.scroll_callback)
self.program = compileProgram(compileShader(self.vertex_src, GL_VERTEX_SHADER),
compileShader(self.fragment_src, GL_FRAGMENT_SHADER))
glUseProgram(self.program)
# 设置模型坐标,和glUniformMatrix4fv不能写成一行,写成一行会无法展示,可能是因为用的指针地址
mat = glm.mat4()
glUniformMatrix4fv(glGetUniformLocation(self.program, 'model'), 1, GL_FALSE, glm.value_ptr(mat))
while not glfw.window_should_close(self.window):
glUniformMatrix4fv(glGetUniformLocation(self.program, 'projection'), 1, GL_FALSE,
glm.value_ptr(self.projection))
glUniformMatrix4fv(glGetUniformLocation(self.program, 'view'), 1, GL_FALSE, glm.value_ptr(self.view))
glClearColor(0.2, 0.3, 0.3, 1.0) # 在glClear后会显示为glClearColor中的颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.bind_data()
self.draw_data()
glfw.poll_events()
glfw.swap_buffers(self.window)
glfw.terminate()
print('glfw close')
result = [
np.array([0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.5, 0.4, 0.0, 1.0, 0.0, 0.0,
0.4, 0.4, 0.0, 1.0, 0.0, 0.0, 0.4, 0.5, 0.0, 1.0, 0.0, 0.0], dtype=np.float32),
np.array([-0.5, -0.5, 0.0, 0.0, 1.0, 0.0, -0.5, -0.4, 0.0, 0.0, 1.0, 0.0,
-0.4, -0.4, 0.0, 0.0, 1.0, 0.0, -0.4, -0.5, 0.0, 0.0, 1.0, 0.0], dtype=np.float32),
np.array([0.2, 0.2, 0.0, 0.0, 0.0, 1.0, 0.2, 0.1, 0.0, 0.0, 0.0, 1.0,
0.1, 0.1, 0.0, 0.0, 0.0, 1.0, 0.1, 0.2, 0.0, 0.0, 0.0, 1.0], dtype=np.float32)
]
ins = [np.array([2, 3, 1, 3, 0, 1], dtype=np.uint32), np.array([2, 3, 1, 3, 0, 1], dtype=np.uint32),
np.array([2, 3, 1, 3, 0, 1], dtype=np.uint32)]
line = [
np.array([0.1, 0.1, 0.1, 0.0, 1.0, 0.0, 0.2, 0.2, 0.2, 0.0, 1.0, 0.0,
0.3, 0.3, 0.3, 0.0, 1.0, 0.0, 0.4, 0.4, 0.4, 0.0, 1.0, 0.0,
0.5, 0.2, 0.3, 0.0, 1.0, 0.0, 0.5, 0.3, 0.4, 0.0, 1.0, 0.0,
0.6, 0.4, 0.5, 0.0, 1.0, 0.0, 0.6, 0.6, 0.6, 0.0, 1.0, 0.0], dtype=np.float32)
]
ogl = MyOpenGL()
ogl.start()
ogl.set_data(result, data_name=f'j', frequency='always', shape='triangles', indices=ins)
ogl.set_data(line, data_name=f'l', frequency='always')

PyQT5 OpenGL zoom

So I wanted to make a zoom functionality in PyQT. And from answer 8.040 I implemented it as such:
class GLWindow(QOpenGLWidget):
def __init__(self, parent=None):
super(GLWindow, self).__init__(parent)
self.object = 0
self.zoomFactor = 1.0
self.setFocusPolicy(Qt.WheelFocus)
self.lastPos = QPoint()
and
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(-2 * self.zoomFactor, +2 * self.zoomFactor, +2 * self.zoomFactor, -2 * self.zoomFactor, 4.0, 15.0)
gl.glMatrixMode(gl.GL_MODELVIEW)
Now at the start of the program if I change the self.zoomFactor to let's say 2.0, it has the desired effect of a zoom, but I can't seem to resize it while running.
def wheelEvent(self, event):
"""http://doc.qt.io/qt-5/qwheelevent.html"""
scroll = event.angleDelta()
if scroll.y() > 0: # up
self.zoomFactor += 0.1
self.resizeGL(self.width(), self.height())
self.update()
pass
else: # down
pass
The above code is how I tried it already, without the desired effect. It catches the upwards zoom and calls the resizeGL function, but won't zoom in/out.
Got the answer. It does work. The resizeGL only updates when resizing the window, so we have to use it in another method.
Maybe it will help someone else:
def paintGL(self, coordinates=None):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glTranslate(0.0, 0.0, -50.0)
glScale(0.1 * self.zoomFactor, 0.1 * self.zoomFactor, 0.1 * self.zoomFactor)
glRotate(self.rotX, 1.0, 0.0, 0.0)
glRotate(self.rotY, 0.0, 1.0, 0.0)
glRotate(self.rotZ, 0.0, 0.0, 1.0)
glTranslate(-0.5, -0.5, -0.5)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertVBO)
glDrawElements(GL_QUADS, len(self.edges), GL_UNSIGNED_INT, self.edges)
glDisableClientState(GL_VERTEX_ARRAY)
glPopMatrix()
def wheelEvent(self, event):
scroll = event.angleDelta()
if scroll.y() > 0:
self.zoomFactor += 0.1
self.update()
else:
self.zoomFactor -= 0.1
self.update()
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glEnable(GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
self.zoomFactor = 1.0
To zoom in/zoom out you must call glScale() function before render shape instead resizeGL()

Loading from Assimp(Pyassimp) to pyglet - bad results

So I'm learning OpenGL using pyglet and I'm importing some models from Blender using Assimp ( port: Pyassimp). So the scene is really basic, it is just 2 cubes and I'm saving it in blend format.In the next piece of code I'm just trying to draw one cube simply using its vertex positions, nothing else.
self.scene = pyassimp.load(FILENAME, pyassimp.postprocess.aiProcess_Triangulate) # Load the scene
self.vertices = numpy.array((), dtype=GLfloat)
for v in self.scene.meshes[1].vertices:
self.vertices = numpy.append(self.vertices, v)
self.vbo = pyglet.graphics.vertexbuffer.create_buffer(self.vertices.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
self.vbo.bind()
self.vbo.set_data(self.vertices.ctypes.data)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0)
And next piece of code is the draw event:
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_DEPTH_TEST)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glLightfv(GL_LIGHT0, GL_POSITION, self.lightfv(1.0, 1.0, 1.0, 1.0))
glLightfv(GL_LIGHT0, GL_AMBIENT, self.lightfv(0.0, 0.0, 0.0, 1.0))
glLightfv(GL_LIGHT0, GL_DIFFUSE, self.lightfv(1.0, 1.0, 1.0, 1.0))
glLightfv(GL_LIGHT0, GL_SPECULAR, self.lightfv(1.0, 1.0, 1.0, 1.0))
glTranslated(0, 10, -25)
glRotatef(self.rotation, 0, 1, 0)
glDrawArrays(GL_TRIANGLES, 0, len(self.model.vertices))
Finally the result:
You have to loop over the faces of the mesh, read the vertex index from there and then draw the faces.
See the C example of assimp. It's quite simple, shows how to do and can very easy be ported to python.
https://github.com/assimp/assimp/blob/master/samples/SimpleOpenGL/Sample_SimpleOpenGL.c
For pyglet you can use the following snipped:
for node in self.scene.rootnode.children:
glPushMatrix()
glMultMatrixf((GLfloat * 16)(*node.transformation.transpose().flatten()))
for mesh in node.meshes:
for face in mesh.faces:
num_indices = len(face)
if num_indices == 1:
mode = GL_POINTS
elif num_indices == 2:
mode = GL_LINES
elif num_indices == 3:
mode = GL_TRIANGLES
else:
mode = GL_POLYGON
pyglet.graphics.draw_indexed(len(mesh.vertices), mode, face, ('v3f', mesh.vertices.flatten()))
glPopMatrix()

Categories