Here is the draw function which draws the parts of the car, in this function car rims is checked and flag is checked, and i need to rotate the tire rim as i move the car. Something is not working since the rims are rotated but taken out from the car model, when i press up arrow key, but the car does move.
I also initialized self.fFlag = "false" in initialize function:
def on_draw(self):
# Clears the screen and draws the car
# If needed, extra transformations may be set-up here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
for name in self.parts:
colors = self.colors
color = colors.get(name, colors["default"])
glColor3f(*color)
if (name == 'Front Driver tire rim') & (self.fFlag == "true"):
bodyFace = self.mini.group(name)
glPushMatrix()
glRotatef(45,1,0,0)
# Drawing the rim
for face in bodyFace:
if len(face) == 3:
glBegin(GL_TRIANGLES)
elif len(face) == 4:
glBegin(GL_QUADS)
else:
glBegin(GL_POLYGON)
for i in face:
glNormal3f(*self.mini.normal(i))
glVertex3f(*self.mini.vertex(i))
glEnd()
glPopMatrix()
self.fFlag == "false"
else:
bodyFace = self.mini.group(name)
for face in bodyFace:
if len(face) == 3:
glBegin(GL_TRIANGLES)
elif len(face) == 4:
glBegin(GL_QUADS)
else:
glBegin(GL_POLYGON)
for i in face:
glNormal3f(*self.mini.normal(i))
glVertex3f(*self.mini.vertex(i))
glEnd()
def on_key_release(self, symbol, modifiers):
"""Process a key pressed event.
"""
if symbol == key.UP:
# Move car forward
# TODO
glTranslatef(0,-1,0)
self.fFlag = "true"
self.on_draw()
pass
Edited: I am trying to make the car rims to rotate when i press the up arrow key, which moves the car forward.
I would highly suggest posting this to the class forum. I don't think TJ would really like to see this, and its very easy to find.
In order to rotate a part about its own center, you need to translate it to the origin, rotate it, and translate it back.
So your
glRotatef(45,1,0,0) # rotate 45 deg about x axis (thru the world origin)
needs to be preceded and followed by translations.
See the accepted answer to this question.
You're almost certainly applying the rotation and transformation in the wrong order, so that the rim is rotated about some point other than the center of the tire.
You might try doing the rotation in the MODELVIEW matrix and the translation in the PROJECTION matrix.
Related
Background
I've been toying around with pyglet when I stumbled across this guy's Minecraft clone. Github is here: https://github.com/fogleman/Minecraft
I've made some modifications (for Python 3 and some of my own preferences), and the complete code is here: modified minecraft.
The Problem
Whenver I run the code, it may sometimes not register any mouse movements or key presses. It is rare, but it can happen occasionally. I would say that out of 10 times, it'll break once.
Details
I don't even know what the culprit is, but I'll provide some snippets code.
It's unpredictable, but there are some ways to fix it. The only sure-fire way currently is to FORCE QUIT (not just quit) the application and then restart it.
I'm not sure why, and I've tried all sorts of things to try and fix it.
If it matters, I'm using macOS Mojave, Python 3.8.2, and Pyglet 1.5.14
Here's the __init__ function for the window:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Whether or not the window exclusively captures the mouse.
self.exclusive = False
# When flying gravity has no effect and speed is increased.
self.flying = False
# Strafing is moving lateral to the direction you are facing,
# e.g. moving to the left or right while continuing to face forward.
#
# First element is -1 when moving forward, 1 when moving back, and 0
# otherwise. The second element is -1 when moving left, 1 when moving
# right, and 0 otherwise.
self.strafe = [0, 0]
# Current (x, y, z) position in the world, specified with floats. Note
# that, perhaps unlike in math class, the y-axis is the vertical axis.
self.position = (0, 0, 0)
# First element is rotation of the player in the x-z plane (ground
# plane) measured from the z-axis down. The second is the rotation
# angle from the ground plane up. Rotation is in degrees.
#
# The vertical plane rotation ranges from -90 (looking straight down) to
# 90 (looking straight up). The horizontal rotation range is unbounded.
self.rotation = (0, 0)
# Which sector the player is currently in.
self.sector = None
# The crosshairs at the center of the screen.
self.reticle = None
# Velocity in the y (upward) direction.
self.dy = 0
# A list of blocks the player can place. Hit num keys to cycle.
self.inventory = [BRICK, GRASS, SAND]
# The current block the user can place. Hit num keys to cycle.
self.block = self.inventory[0]
# Convenience list of num keys.
self.num_keys = [
key._1, key._2, key._3, key._4, key._5,
key._6, key._7, key._8, key._9, key._0]
# Instance of the model that handles the world.
self.model = Model()
# The label that is displayed in the top left of the canvas.
self.label = pyglet.text.Label('', font_name='Arial', font_size=18,
x=10, y=self.height - 10, anchor_x='left', anchor_y='top',
color=(0, 0, 0, 255))
# This call schedules the `update()` method to be called
# TICKS_PER_SEC. This is the main game event loop.
pyglet.clock.schedule_interval(self.update, 1.0 / TICKS_PER_SEC)
Here's the input handlers:
def on_mouse_press(self, x, y, button, modifiers):
""" Called when a mouse button is pressed. See pyglet docs for button
amd modifier mappings.
Parameters
----------
x, y : int
The coordinates of the mouse click. Always center of the screen if
the mouse is captured.
button : int
Number representing mouse button that was clicked. 1 = left button,
4 = right button.
modifiers : int
Number representing any modifying keys that were pressed when the
mouse button was clicked.
"""
if self.exclusive:
vector = self.get_sight_vector()
block, previous = self.model.hit_test(self.position, vector)
if (button == mouse.RIGHT) or \
((button == mouse.LEFT) and (modifiers & key.MOD_CTRL)):
# ON OSX, control + left click = right click.
if previous:
self.model.add_block(previous, self.block)
if button == pyglet.window.mouse.LEFT and block:
texture = self.model.world[block]
self.model.remove_block(block)
else:
self.set_exclusive_mouse(True)
def on_mouse_motion(self, x, y, dx, dy):
""" Called when the player moves the mouse.
Parameters
----------
x, y : int
The coordinates of the mouse click. Always center of the screen if
the mouse is captured.
dx, dy : float
The movement of the mouse.
"""
if self.exclusive:
m = 0.15
x, y = self.rotation
x, y = x + dx * m, y + dy * m
y = max(-90, min(90, y))
self.rotation = (x, y)
def on_key_press(self, symbol, modifiers):
if symbol == key.W:
self.strafe[0] -= 1
if symbol == key.S:
self.strafe[0] += 1
if symbol == key.A:
self.strafe[1] -= 1
if symbol == key.D:
self.strafe[1] += 1
if symbol == key.SPACE:
if self.dy == 0:
self.dy = JUMP_SPEED
if symbol == key.ESCAPE:
self.set_exclusive_mouse(False)
if symbol == key.TAB:
self.flying = not self.flying
if symbol in self.num_keys:
index = (symbol - self.num_keys[0]) % len(self.inventory)
self.block = self.inventory[index]
And finally, here's the setup:
""" Configure the OpenGL fog properties.
"""
# Enable fog. Fog "blends a fog color with each rasterized pixel fragment's
# post-texturing color."
glEnable(GL_FOG)
# Set the fog color.
glFogfv(GL_FOG_COLOR, (GLfloat * 4)(0.5, 0.69, 1.0, 1))
# Say we have no preference between rendering speed and quality.
glHint(GL_FOG_HINT, GL_DONT_CARE)
# Specify the equation used to compute the blending factor.
glFogi(GL_FOG_MODE, GL_LINEAR)
# How close and far away fog starts and ends. The closer the start and end,
# the denser the fog in the fog range.
glFogf(GL_FOG_START, 50.0)
glFogf(GL_FOG_END, 100.0)
def setup():
""" Basic OpenGL configuration.
"""
# Set the color of "clear", i.e. the sky, in rgba.
glClearColor(0.5, 0.69, 1.0, 1)
# Enable culling (not rendering) of back-facing facets -- facets that aren't
# visible to you.
glEnable(GL_CULL_FACE)
# Set the texture minification/magnification function to GL_NEAREST (nearest
# in Manhattan distance) to the specified texture coordinates. GL_NEAREST
# "is generally faster than GL_LINEAR, but it can produce textured images
# with sharper edges because the transition between texture elements is not
# as smooth."
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
setup_fog()
def main():
window = Window(width=800, height=600, caption='Minecraft', resizable=True)
# Hide the mouse cursor and prevent the mouse from leaving the window.
setup()
if __name__ == '__main__':
main()
pyglet.app.run()
Here's texture.png:
Here's an example of what's happening (the black circles means I've clicked the mouse, and at the end, I was rapidly pressing W):
gif
What I've Done
Here is what I've done so far:
Looked at the Pyglet Docs
Researched on google with various phrasing and keywords
It sounds like it could be a Mac related issue. Here is a bug report on something similar happening with Mac: https://github.com/pyglet/pyglet/issues/225
One thing I would try is just try a barebones setup and see if the problems persists with the minimal code. If this still occurs, there is most likely a bug in the Mac/Pyglet interaction. If the basic sample works, there might be a bug in the Minecraft example.
import pyglet
window = pyglet.window.Window()
#window.event
def on_draw():
print('on_draw')
window.clear()
#window.event
def on_mouse_motion(x, y, dx, dy):
print('on_mouse_motion', x, y, dx, dy)
#window.event
def on_key_press(symbol, modifiers):
print('on_key_press', symbol, modifiers)
pyglet.app.run()
The crtaj() function (the main drawing function) takes two global matrices, "T" and "P", applies transformations on the global vertices "vrhovi" using the two matrices and stores the transformed vertices into "novivrhovi", and then draws the polygon using the transformed vertices "novivrhovi" and global "poligoni" (describes the connections of vertices). When the key "up" is pressed, the matrices "T" and "P" are updated. What i want, is to draw on every one of these updates, but after the initial draw the screen goes blank after first "up" is pressed. I am 100% certain my transformations are okay, because pressing the key up once gives matrices for which i have tried to set to be initial , and it draws it correctly so no reason not to draw correctly when using default initial and pressing up, because the result is the same and the function even prints correct vertices every time I press "up" but just doesn't show anything.
#window.event
def on_draw():
glScalef(150,150,150)
glTranslatef(sum(xkord)/2,sum(ykord)/2,0)
window.clear()
crtaj()
#window.event
def on_key_press(key, modifiers):
global vrhovi
if (key == pyglet.window.key.UP):
ociste[0][0]=ociste[0][0]+1
transform()
on_draw()
#main draw
def crtaj():
glBegin(GL_LINE_LOOP)
global T
global P
global vrhovi
global poligoni
#calculate new vertices of polygon-->novivrhovi
novivrhovi = []
for vrh in vrhovi:
novivrh = vrh.copy()
novivrh.append(1)
novivrh = np.matrix(novivrh)
novivrh = novivrh.dot(T)
novivrh = novivrh.dot(P)
novivrh = novivrh.tolist()
novivrhovi.append(novivrh[0])
print("N O V I V R H O V I")
print(novivrhovi)
#draw the poligon
for poligon in poligoni:
index0 = poligon[0]-1
index1 = poligon[1]-1
index2 = poligon[2]-1
glVertex4f(novivrhovi[index0][0],novivrhovi[index0][1],novivrhovi[index0][2],novivrhovi[index0][3])
glVertex4f(novivrhovi[index1][0],novivrhovi[index1][1],novivrhovi[index1][2],novivrhovi[index1][3])
glVertex4f(novivrhovi[index2][0],novivrhovi[index2][1],novivrhovi[index2][2],novivrhovi[index2][3])
glEnd()
pyglet.app.run()
but after the initial draw the screen goes blank after first "up" is pressed.
The Legacy OpenGL matrix operations like glScalef and glTranslatef do not just set a matrix, they define a new matrix and multiply the current matrix by the new matrix.
OpenGL is a state engine, states are kept until they are changed again, even beyond frames. Hence in your application the current matrix is progressively scaled and translated.
Load the Identity matrix at the begin of on_draw:
#window.event
def on_draw():
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glScalef(150,150,150)
glTranslatef(sum(xkord)/2,sum(ykord)/2,0)
window.clear()
crtaj()
PyGlet sets by default an Orthographic projection projection matrix to window space. See pyglet.window. If you want a different projection, it can be set by glOrtho:
#window.event
def on_draw():
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, window.width, window.height, 0, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glScalef(150,150,150)
glTranslatef(sum(xkord)/2,sum(ykord)/2,0)
window.clear()
crtaj()
I have an application where I crop parts of an image and save them in OpenCv 4 using Python, first drawing rectangles before saving (SSCCE below). Some of the images are very large, so it is helpful to zoom in on them before selecting regions to crop.
The problem is once you've zoomed on an image, the mouse cursor permanently toggles to the interactive hand. Then clicking/dragging only serves to translate the position of the image in the window (unless I go back out to full size, but then I can't draw rectangles on the zoomed-in image).
So my question is once I've zoomed in, how can I get from this:
back to this:
So I can get back to drawing rectangles on the zoomed in image? I'd love to be able to right click to get back to the pointer (some magic with cv2.EVENT_RBUTTONDOWN), but maybe there is some built-in way to do it I'm just ignorant of?
One thing that sort of works is when I changed my program so that it is right button presses/releases that draws the rectangles, so then there is no longer any interference with the native left-click navigation. The problem is I can draw more precise rectangles when I have an arrow than when I have a hand. So while this is a hack I can use as a workaround, it would be really nice if I could toggle back to the arrow for drawing rectangles while zoomed in.
SSCE
import cv2
import numpy as np
#Insert your path to file here:
input_path = r'C:/image0000.bmp'
image = cv2.imread(input_path, cv2.IMREAD_GRAYSCALE)
(im_h, im_w) = image.shape
max_d = np.max([im_h, im_w])
line_width = int(np.ceil(max_d/1000))
image_to_show = image.copy() # np.copy(image)
mouse_pressed = False
s_x = s_y = e_x = e_y = -1
def mouse_callback(event, x, y, flags, param):
global image_to_show, s_x, s_y, e_x, e_y, mouse_pressed
if event == cv2.EVENT_LBUTTONDOWN:
mouse_pressed = True
s_x, s_y = x, y
image_to_show = np.copy(image)
elif event == cv2.EVENT_MOUSEMOVE:
if mouse_pressed:
image_to_show = np.copy(image)
cv2.rectangle(image_to_show, (s_x, s_y),
(x, y), (255, 255, 255), line_width)
elif event == cv2.EVENT_LBUTTONUP:
mouse_pressed = False
e_x, e_y = x, y
print(s_x, s_y, e_x, e_y)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.setMouseCallback('image', mouse_callback)
while True:
cv2.imshow('image', image_to_show)
k = cv2.waitKey(1)
if k == 27:
break
cv2.destroyAllWindows()
In MFC framework, I use GetWindowHandle and SetClassLong (), then use SendMessage to this window and force it to refresh
HWND hWnd = (HWND)cvGetWindowHandle ("SrcView");
if (event == CV_EVENT_RBUTTONDOWN || flag == CV_EVENT_FLAG_RBUTTON)
SetClassLongPtr (hWnd, GCLP_HCURSOR, (LONG_PTR)pDlgMain->m_cursorDrag);
else
SetClassLongPtr (hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor(NULL, IDC_ARROW));
SendMessage (hWnd, WM_SETCURSOR, NULL, NULL);
Maybe find the corresponded ones of these three functions in python may be helpful.
Is it possible to draw convexity polygon with Pyglet?
If yes, how can I draw it? I only know n vertex and their 2D coordinates.
You could use the primitive GL_POLYGON (or even try GL_LINE_LOOP).
Check documentation...
https://pyglet.readthedocs.io/en/pyglet-1.2-maintenance/api/pyglet/pyglet.graphics.html
http://pyglet.readthedocs.io/en/pyglet-1.3-maintenance/programming_guide/graphics.html
... and an example
Pyglet GL_QUADS and GL_POLYGON not working properly
Yes, cou can do it.
Just take the following code snippets to get a feeling for the functionality.
Play a little bit with the modes:
GL_POLYGON,
GL_TRIANGLES,
GL_TRIANGLE_FAN and
GL_TRIANGLE_STRIP.
Left mouse click button increases points in window. First drawing is shown after clicking three times. Del-Button clears the window.
GL_POLYGON and GL_TRIANGLE_FAN behave in the same way, the first point is the anchor point of the convex polygon and is used for every drawn triangle from the points list.
GL_TRIANGLE takes 3 points for drawing a triangle, then the next 3 points and so on.
With GL_TRIANGLE_STRIP you can draw every complex structure. But there you have be careful for the given points. Sometimes, you have to visit a point more than one time.
The first triangle is drawn by points 1-3.
The second triangle is drawn by points 2-4, then 3-5, 4-6 and so on.
import pyglet
from pyglet.window import key
global n
global vertices
global colors
window = pyglet.window.Window()
n = 0
vertices = []
colors = []
polygon = None
main_Batch = pyglet.graphics.Batch()
#window.event
def on_draw():
window.clear()
main_Batch = pyglet.graphics.Batch()
if n > 2:
polygon = main_Batch.add(n, pyglet.gl.GL_POLYGON, None,
('v2i', vertices),
('c3B', colors))
main_Batch.draw()
#window.event
def on_key_press(symbol, modifiers):
if symbol == key.DELETE:
global n;
global vertices
global colors
vertices = []
colors = []
n = 0
#window.event
def on_mouse_press(x, y, button, modifiers):
if button == pyglet.window.mouse.LEFT:
global n
vertices.append(x)
vertices.append(y)
n = n + 1
colors.append(255)
colors.append(255)
colors.append(255)
pyglet.app.run()
I'm making a 2D game. I want to be able to render a texture on the screen after rotating it a certain amount around a centre point. Basically this is for a level rotation around a player. The player position being the rotation point and the direction of the player as the angle. This code wont work:
def draw_texture(texture,offset,size,a,rounded,rotation,point):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity() #Loads model matrix
glColor4f(1,1,1,float(a)/255.0)
glTranslatef(point[0],point[1],0)
glRotatef(rotation,0,0,1)
glBindTexture(GL_TEXTURE_2D, texture)
if rounded == 0:
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex2i(*offset) #Top Left
glTexCoord2f(0.0, 1.0)
glVertex2i(offset[0],offset[1] + size[1]) #Bottom Left
glTexCoord2f(1.0, 1.0)
glVertex2i(offset[0] + size[0],offset[1] + size[1]) #Bottom, Right
glTexCoord2f(1.0, 0.0)
glVertex2i(offset[0] + size[0],offset[1]) #Top, Right
glEnd()
else:
#Nothing important here
glEnd()
Any way to get it working? Thank you.
try reversing
glTranslatef(point[0],point[1],0)
and
glRotatef(rotation,0,0,1)
you're translating to the player, but then rotating about the origin (not the player)
Illustration from the red book:
Unless you have a good reason to do otherwise, I'd leave the drawing code alone, and just change the camera angle. Probably the easiest way to do that is use gluLookAt. In your case, you'll apparently be looking at the player's position, and just change the "up direction", which is given in the last two parameters.