tilting perspective view on a plane of 2D images?

132 views
Skip to first unread message

George Oliver

unread,
Mar 29, 2010, 12:31:29 AM3/29/10
to pyglet...@googlegroups.com
hi, up to now I've used pyglet just for 2D stuff with hardly any OpenGL.
What I'd like to do is tilt the plane on which my 2D sprites are drawn.
I don't know if I'm thinking of this correctly in relation to OpenGL,
but if a normal projection has the player looking straight on at the
picture plane, I'd like to rotate that angle made between the projection
and the picture plane, so the perspective is 'tilted' (sorry if I'm
getting terms wrong here!).

I'm guessing I can't just 'tilt' the 2D plane, whatever that means,
since the 2D sprites would disappear. However if it's easier to do that
with 3D sprites I'm open to that.

Here's what I'm doing so far:

* create a group to set OpenGL state for sprites

class CustomGroup(pyglet.graphics.Group):
def set_state(self):
glLoadIdentity()
glRotatef(0.0, 1.0, 0.0, 0.0)
glRotatef(0.0, 0.0, 1.0, 0.0)
glTranslatef(0.0, 0.0, 0.0)

def unset_state(self):
pass

(Though, if I try to rotate about a vector with glRotate, since the
sprites are just 2D the effect isn't what I want as expected).

* load images and make sprites, assigning to a batch and setting the
group to an instance of the class above

* in on_draw

def on_draw():
window.clear()
batch.draw()


I've tried giving the window a new on_resize, since as I understand it
the default is just a 2D projection (which I think I don't want, I'm not
sure), using this code from a nehe example:

def resize(width, height):
if height==0:
height=1
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, 1.0*width/height, 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

I think this is basically what I want; from what I understand the
gluPerspective call sets the perspective angle at 45 degrees. However
setting this to the on_resize of the window then doesn't show my batch.

In the same example the code also translates to z = -5.0, but doing the
same thing in my code (without the new resize) also hides the batch. I'm
guessing that's because of the default projection? However it doesn't
seem to help to add the new resize.

Any further advice or pointers?

Mikael Lind

unread,
Mar 29, 2010, 2:53:20 AM3/29/10
to pyglet...@googlegroups.com
On 29 March 2010 06:31, George Oliver <georgeo...@gmail.com> wrote:
> I've tried giving the window a new on_resize, since as I understand it the
> default is just a 2D projection (which I think I don't want, I'm not sure),
> using this code from a nehe example:
>
> def resize(width, height):
>    if height==0:
>        height=1
>    glViewport(0, 0, width, height)
>    glMatrixMode(GL_PROJECTION)
>    glLoadIdentity()
>    gluPerspective(45, 1.0*width/height, 0.1, 100.0)
>    glMatrixMode(GL_MODELVIEW)
>    glLoadIdentity()
>
> I think this is basically what I want; from what I understand the
> gluPerspective call sets the perspective angle at 45 degrees. However
> setting this to the on_resize of the window then doesn't show my batch.

I think your batch may be clipped since pyglet renders it at z = 0 by
default, and your near clipping plane is at 0.1. Try translating
before drawing:

glPushMatrix()
glTranslatef(0.0, 0.0, 5.0)
// draw
glPopMatrix()

> In the same example the code also translates to z = -5.0, but doing the same
> thing in my code (without the new resize) also hides the batch. I'm guessing
> that's because of the default projection? However it doesn't seem to help to
> add the new resize.

Again, I think the batch is clipped, this time since pyglet's default
orthogonal projection has near and far clipping planes of -1 and 1. I
don't know why combining the translation with the resize code doesn't
work. Can you post a minimal but complete pyglet script that
reproduces the problem?

--
Mikael Lind
http://elemel.se/

George Oliver

unread,
Mar 29, 2010, 12:12:00 PM3/29/10
to pyglet...@googlegroups.com
On 3/28/2010 11:53 PM, Mikael Lind wrote:
> don't know why combining the translation with the resize code doesn't
> work. Can you post a minimal but complete pyglet script that
> reproduces the problem?
>
>


I've made a zip of the script below that includes an image, available here:

http://sites.google.com/site/georgekoliver/Home/pyglet_perspective_test.zip?attredirects=0&d=1


The script:

import pyglet
from pyglet.gl import *

def resize(width, height):
if height==0:
height=1
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()

gluPerspective(45, 1.0*width/height, -1.0, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

window = pyglet.window.Window(640, 480)
window.on_resize=resize

batch = pyglet.graphics.Batch()

image = pyglet.image.load('crate.bmp')

crate = pyglet.sprite.Sprite(image, 100, 100, batch=batch)

@window.event
def on_draw():
window.clear()
batch.draw()

if __name__ == '__main__':
pyglet.app.run()

Commenting out the resize() and the assignment to window.on_resize shows
the image as expected, but including the resize gives me a blank window.
I've modified the gluPerspective slightly from the example I took it
from, where they had:

gluPerspective(45, 1.0*width/height, .1, 100.0)

I changed 0.1 to -1, guessing maybe that pyglet was drawing the batch at
z=0? But obviously that doesn't help (nor does keeping it at 0.1 I
should add).

The nehe example I looked at gives me hope, as it clearly shows the 2D
texture first in a straight-on view (i.e. like a regular 2D ortho
projection) but then 'tilting' in perspective when the code rotates the
cube, though maybe I'm misunderstanding that?

Incidentally that example is available here, it's lesson 07.

http://groups.google.com/group/pyglet-users/web/pyglet%20nehe.zip

Mikael Lind

unread,
Mar 29, 2010, 2:59:38 PM3/29/10
to pyglet...@googlegroups.com
On 29 March 2010 18:12, George Oliver <georgeo...@gmail.com> wrote:
> Commenting out the resize() and the assignment to window.on_resize shows the
> image as expected, but including the resize gives me a blank window. I've
> modified the gluPerspective slightly from the example I took it from, where
> they had:
>
>    gluPerspective(45, 1.0*width/height, .1, 100.0)
>
> I changed 0.1 to -1, guessing maybe that pyglet was drawing the batch at
> z=0? But obviously that doesn't help (nor does keeping it at 0.1 I should
> add).

-1 is an invalid near clip plane for a perspective projection. (You
can't look at something that's in or behind your eye.)

> The nehe example I looked at gives me hope, as it clearly shows the 2D
> texture first in a straight-on view (i.e. like a regular 2D ortho
> projection) but then 'tilting' in perspective when the code rotates the
> cube, though maybe I'm misunderstanding that?

I've changed your script a little so that it shows something on the screen.

Changes:

- Position the sprite at (0, 0) instead of (100, 100).
- Translate 1000 units into the screen before drawing the batch.
- Change the near and far clip planes to to 0.1 and 10000.

The changed script:

import pyglet
from pyglet.gl import *

def resize(width, height):
if height==0:
height=1
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()

gluPerspective(45, 1.0*width/height, 0.1, 10000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()

window = pyglet.window.Window(640, 480)
window.on_resize=resize

batch = pyglet.graphics.Batch()

image = pyglet.image.load('crate.bmp')

crate = pyglet.sprite.Sprite(image, 0, 0, batch=batch)

@window.event
def on_draw():
window.clear()
glPushMatrix()
glTranslatef(0, 0, -1000)
batch.draw()
glPopMatrix()

if __name__ == '__main__':
pyglet.app.run()

--
Mikael Lind
http://elemel.se/

George Oliver

unread,
Mar 29, 2010, 3:26:22 PM3/29/10
to pyglet...@googlegroups.com
On 3/29/2010 11:59 AM, Mikael Lind wrote:
>
> I've changed your script a little so that it shows something on the screen.
>
>


Wow, that really helps, thanks! Another mistake I realized I was making
was setting glLoadIdentity in the set_state of the CustomGroup.

In experimenting it seems like I can substitute a glLoadIdentity in
place of the Pop/Push of the matrix, like:

@window.event
def on_draw():
window.clear()
glLoadIdentity()
glTranslatef(-W_W/2, -W_H/2, -1000)
batch.draw()

Is that doing the same thing by resetting the matrix, or is that not
recommended?


Mikael Lind

unread,
Mar 29, 2010, 3:37:02 PM3/29/10
to pyglet...@googlegroups.com
On 29 March 2010 21:26, George Oliver <georgeo...@gmail.com> wrote:
> In experimenting it seems like I can substitute a glLoadIdentity in place of
> the Pop/Push of the matrix, like:
>
> @window.event
> def on_draw():
>    window.clear()
>    glLoadIdentity()
>    glTranslatef(-W_W/2, -W_H/2, -1000)
>    batch.draw()
>
> Is that doing the same thing by resetting the matrix, or is that not
> recommended?

That depends on what you want to do. Read The Fine Manual. :-)

Reply all
Reply to author
Forward
0 new messages