Pyglet/OpenGL point sprites - python

I decided to use pyglet and opengl to make a 3D FPS game. I am trying to create a Doom-like effect where certain images are kept 2D (always face the camera) in a 3D environment. A few google searches later, and I come across point sprites. Currently trying to implement these. Here is my code:
playerimg = pyglet.image.load(r"img\front.png").texture
glBindTexture(GL_TEXTURE_2D, playerimg.id)
glEnable(GL_POINT_SPRITE)
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)
x,y,z = 0,1,0
glBegin(GL_POINTS)
glVertex3f(x+2,y,z)
glVertex3f(x,y,z)
glVertex3f(x,y+2,z)
glVertex3f(x+2,y+2,z)
glEnd()
I get no errors when I use this code, however, the image does not appear anywhere on screen. I have already implemented (camera) movement and rotation, but I never see the image.

Related

HOW i can generate cubes random in pygame?

i need code
How can a randomly generated 3dcube using just pygame be created from the top of the screen and then fall from the top to the bottom of the screen
please help me
using python pygame
As mentioned by #The_spider , pygame is a 2D Game engine. It cannot load 3D files or do any 3D stuff. A few recommended modules would be Panda3d and Ursina(which is a simplified version of Panda3d) install them via pip.
If you really need to use pygame, you'll have to save an image of the cube at every angle and Blit it on the screen using an extremely complicated algorithm. Moreover, it will be extremely slow. Thus, use a python 3D game engine.

Moviepy - Crop video with frame (region of interest) moving from left to right with time

I'm working on creating GIF from video clips automatically on the server using MoviePy. The library helped in various transformations and trimming of video to create GIFs.
In my current project, I have a video clip with lots of moving objects making it difficult to do automatic tracking of the region of interest.
(A quick gif below shows the scene, though the background there can be easy to eliminate and do the tracking of object. But let's say tracking object is out of scope of the project).
As shown in the gif below the red rectangle is the region of interest which moves from left to right with time.
I want to crop that region and create a GIF.
I'm using MoviePy where I cropped a rectangle from a video to create a gif. But the rectangle is fixed at its original coordinates position. I'm looking for a way to move that rectangle with time and crop it to create a GIF.
clip = (VideoFileClip("my_video.mp4")
.subclip((1,10.1),(1,14.9))
.resize(0.5)
.crop(x1=145,y1=110,x2=400,y2=810))
clip.write_gif("my_gif.gif")
How to add time factor so that this coordinates change with the time.
Any suggestions welcome.
You're looking for the scroll function in moviepy. The docs for it are lacking, but they are here, and the source code here.
moviepy.video.fx.all.scroll(clip, h=None, w=None, x_speed=0, y_speed=0, x_start=0, y_start=0, apply_to='mask')
Parameters:
clip; the clip to be acted upon
h and w which determine the height and width of the final clip
x_speed and y_speed which determine the speed of scrolling. Not sure what these are measured in, so you may have to investigate the source code, or just trial and error it.
x_start and y_start which is the distances from (0,0) that it starts scrolling at.
apply_to; something to do with masks, you won't need it!
Final code:
clip = (VideoFileClip("my_video.mp4")
.subclip((1,10.1),(1,14.9))
.resize(0.5)
.crop(x1=145,y1=110,x2=400,y2=810))
# You won't need to set `w` and `h` if you are separately cropping it
new_clip = clip.scroll(w=clip.w, h=var, x_speed=speed, y_start=height_to_top_of_wanted_bit)
new_clip.set_duration(1.0 / speed)
new_clip.write_gif("my_gif.gif")
Note, this code is not tested.

Procedural GL textures

Background
I'm working in python/pyglet to create a procedurally generated terrain.
I'm visualizing it with pyglet by running a lambda function for each x and y coordinate on the screen and then painting that pixel in the color I want it.
This is not very optimal.
I have a sneaking suspicion that there is a way to create a rectangular object and tell the GL engine to render a texture upon it, giving the GL engine a lambda function that will return the color in exchange for an x and y coordinate.
Pseudo pyglet example
def get_color(pos):
x, y = pos
color = x * y % 255
return [color, color, color]
width = 1680
height = 1024
win = window.Window(fullscreen=False, vsync=True, width=width, height=height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0, win.width, 0, win.height)
glTextureMapper(get_color)
win.clear()
points = [0, 0, width, 0, width, height, 0, height]
pyglet.graphics.draw(int(len(points) / 2), GL_QUADS, ('v2f', points))
TLDR Question
How do I color a polygon using a lambda function? Is this a shader?
Pyglet examples are preferred, but examples in any language are welcome
This is probably not a complete answer, but might get you a bit further.
Also keep in mind that I've never worked much with textures at all weirdly enough.
What you might be able to do, is create a texture-group for any set of quads, and add them into a batch. Because I'm not entirely sure why you need a lambda function?
class TextureGroup(pyglet.graphics.Group):
def set_state(self):
glEnable(texture.target)
glBindTexture(texture.target, texture.id)
def unset_state(self):
glDisable(texture.target)
vertice_mem = {}
batch = pyglet.graphics.Batch()
texture_group = TextureGroup()
vertice_list = batch.add(2, pyglet.gl.GL_QUADS, None, ('v2f', points))
vertice_mem[(x,y)] = vertex_list
This is one way to optimize how textures are added to certain faces and also add those faces into a batch rendering them a lot faster and more dynamic.
If you need to update the vertices, you can always access the vertice_list.vertices and change the x,y pair for that particular face.
You can use the custom group to create certain textures "on the fly", or on this case pre-rendered certain textures which you could stitch together to create "procedural" textures.
What #Ripi2 says is also a good tip, read up on how procedural memory mapping works and what it actually is. Most graphics you see in sand-box games are actual clever re-use of textures to create the illusion of on-demand graphics.
The last and final tip is that you will most likely need to look into shaders, they are by far the fastest way to auto-generate "textures" by manipulating and creating turbulence in textures, else will be heavily taxing on your system because you will need to iterate over the pixel area in some way.
But again, this is not my area of experience - only a fellow travelers bits and pieces of information gathered over the years.
As pointed out strictly speaking OpenGL cannot draw rectangles (quads), but you can always use a diagonal between two corners to make two triangles. (There can be some differences in interpolation between corners, but they probably won't affect you.)
And while I'm being pedantic, you're not coloring pixels, you're colouring points on your 3D terrain object surface. (I'm assuming you want the terrain to keep the same colors when viewed from any angle or distance.)
OK, what I hope will be the real answer. Is your procedural terrain generation coloring done once, or does it change dynamically?
If you only create and color the terrain once, use a texture map. You'll need to learn how to assign texture coordinates at the corners of the terrain (TL;DR: they'll be (0.0,0.0), (1.0,0.0), (1.0,1.0), (0.0, 1.0) ) and how to use glTexImage2D to transfer an image to the GPU.
Texture maps are just 2D raster images. Pyglet should be able to handle this for you, if not either Pillow or the Python Imaging Library packages.
If you want the terrain to change colors on the fly, you need a fragment shader, a small function written in OpenGL Shading Language that executes every time the terrain is drawn. And due to the way OpenGL works you'll also have to write a vertex shader that handles the 3D coordinate transformations.
This will mean more thinking and coding that the texture map approach. But everything in OpenGL (or DirectX, or RenderMan, …) is done with shaders these days, so you might as well start learning. And shaders let you do any kind of procedural modelling and animation, not just colors. For example, you could dynamically generate your terrain heights as well as colors.
Hope this helps.

Pygame screen blur

So I am making a game with multiple parts using pygame and it has a "drunk" component to it. My goal is to make it so that the more "drunk" the player is, the screen will look more blurry accordingly.
Here is a hack provided for blurring a surface
But that does not work for the whole screen, which is what I need.
How could I go about blurring the entire screen?
How could I go about blurring the entire screen?
When you do pygame.display.set_mode() (or some other function to get the game screen*), what you get back is a Surface.
If you're following the tutorials, you've probably stored it in a variable named screen. Just use that as your surface.
Or you can always just draw to an off-screen surface, transform that, and blit to the screen from the transformed version.
Also, you might want to consider using surfarray; you can probably do a much better blur than just anti-aliased pixelization with about the same amount of code and less CPU work…
* The game screen may be the whole monitor screen, for a full-screen game, or the window, for a windowed game. Either way, if that's the thing you want to blur, that's the Surface you use. If you wanted to blur the entire monitor screen from a windowed game, that wouldn't be possible, because you don't have a handle to that… but from comments, that isn't what you want.

How do I clear a pygame alpha layer efficiently?

I'm trying to write a 2D game using python / pygame that blits several layers on top of one another every screen refresh. My basic setup is (from bottom to top):
Background: surface (non-transparent), scrolls at a different rate than rest
Midground: SRCALPHA transparent surface (static)
Player / Sprites / Enemies: sprite group
Forground: SRCALPHA transparent surface (static)
Right now, I'm blitting these four layers one on top of another every screen. The background scrolls at a different rate than the other three layers, which is why I have it separate from midground. As I have the game structured now, it runs on my fairly modest laptop at 60fps.
-BUT- I'm having trouble with the sprite group, which I'm blitting directly to the screen. Having to adjust the rect for every sprite according to my current viewport seems like an ugly way to program things, and I'd like a more elegant solution.
I'd love to blit the sprites to another transparent surface which I could manage, but therin lies my problem: I can't find a way of clearing a transparent layer that doesn't half my performance. Some of the setups I've tried:
I've tried filling the layer with a white surface with blend mode rgba_sub (surf.fill((255,255,255,255), area, BLEND_RGBA_SUB)) -- this is super, super slow
I've tried surface.copy() of a blank surface - this is faster, but still halves my fps
I've tried combining the sprites with the midground layer and using pygame.sprite.LayeredUpdates to update the sprites. This has no effect on performance, but does not work where the midground is transparent. I get trails of sprites over the background layer.
The best solution I've found so far is my current setup of drawing sprites directly to the screen. It looks great, runs fast, but is a pain to manage, as I have to make sure each sprites' rect is adjusted according to the viewport every frame. Its also making collision detection difficult.
Is there another quick way to clear a pygame transparent surface? Quick as in, can be done 60+ times a second? Alternately, is there a setup for my layers that would still accomplish the same effect?
I figured out a fast way of clearing a sprites only transparent layer by applying Peter's solution selectively to the layer:
for s in self.level.sprites:
spritelayer.fill((0), s.rect)
This seems to be working fine (erasing everything each frame) and still runs at 60fps.
The Surface.fill() will clear all R, G, B, and A values.
>>> img = pygame.image.load("hasalpha.png")
>>> print img.get_at((300, 300))
(238, 240, 239, 255)
>>> surface.fill(0)
>>> print img.get_at((300, 300))
(0, 0, 0, 0)
It sounds like this will do what you are describing. If you are trying to do something more specific with the alpha values the pygame.surfarray.pixel functions can give you directly editable values. That will be quick, but requires numpy as a dependency.

Categories