Moving the point of view

1,402 views
Skip to first unread message

eFFeeMMe

unread,
May 5, 2008, 9:16:19 AM5/5/08
to pyglet-users
Hello everybody. I've recently discovered pyglet and it was so
straightforward to use that I decided to try and immediately make a
RTS game with it.
In that sort of games however you want to move the camera around...
Now, I've already handled that in pygame and the amount of coordinate
conversions was huge. Pyglet however uses OpenGL for the rendering and
I was wondering if I could avoid all the absolute>screen position
conversions simply by moving the OpenGL camera parallel to the window
plane.
I've searched through the documentation for that but I couldn't find
anything. Can anybody help?

Drew Smathers

unread,
May 5, 2008, 10:27:15 AM5/5/08
to pyglet...@googlegroups.com

This is pretty simple do, but the implementation would vary depending
on how you want to move the camera. For a side-scroller, I generally
do one of the following

1. Keep the camera's position (X) always in sync with the player's position
2. Only move the camera as the player reaches the edge of the screen.

Either way, there is no camera in OpenGL, just a world matrix
transformation. You can model the position of the `camera` with a
Camera class and just take the inverse of it's position when applying
the transformation:

glTranslatef(-camera.pos.x, -camera.pos.y, -camera.pos.z)

So in your on_update for the sprite, you might do something like:

player.pos.x = newpos
camera.pos.x = player.pos.x

I've actually developed some abstractions for camera (and lights) in
pyglet-based library I'm hacking on for use in 3D games
(http://miru.enterthefoo.com/tip). This might be useful for your
application as you can define a side-scroller track (2) over a camera
and renderable object, which is described here:
http://miru.enterthefoo.com/tip/#camera-tracks


--
\\\\\/\"/\\\\\\\\\\\
\\\\/ // //\/\\\\\\\
\\\/ \\// /\ \/\\\\
\\/ /\/ / /\/ /\ \\\
\/ / /\/ /\ /\\\ \\
/ /\\\ /\\\ \\\\\/\
\/\\\\\/\\\\\/\\\\\\
d.p.s

eFFeeMMe

unread,
May 5, 2008, 4:57:10 PM5/5/08
to pyglet-users
On 5 Mag, 16:27, "Drew Smathers" <drew.smath...@gmail.com> wrote:
>
> This is pretty simple do, but the implementation would vary depending
> on how you want to move the camera. For a side-scroller, I generally
> do one of the following
>
> 1. Keep the camera's position (X) always in sync with the player's position
> 2. Only move the camera as the player reaches the edge of the screen.
>
> Either way, there is no camera in OpenGL, just a world matrix
> transformation. You can model the position of the `camera` with a
> Camera class and just take the inverse of it's position when applying
> the transformation:
>
> glTranslatef(-camera.pos.x, -camera.pos.y, -camera.pos.z)
>
> So in your on_update for the sprite, you might do something like:
>
> player.pos.x = newpos
> camera.pos.x = player.pos.x
>
> I've actually developed some abstractions for camera (and lights) in
> pyglet-based library I'm hacking on for use in 3D games
> (http://miru.enterthefoo.com/tip). This might be useful for your
> application as you can define a side-scroller track (2) over a camera
> and renderable object, which is described here:http://miru.enterthefoo.com/tip/#camera-tracks

Err, thanks for the help but attaching a camera to something is simple
enough, what I'm having problems with is actually the camera having
any effect at all on the position of the viewport =p Doesn't
pyglet(and OpenGL in general) render stuff on a plane(I think)? What I
need is to see a translated portion of that plane. I looked around a
little bit more and it seems that what I'm looking for is something
like:
pyglet.gl.glViewport(camera.x, camera.y, window._width,
window._height)
It seems to work when I put it in the window's on_resize event(it
shows a different portion of the screen), but not when called by
itself(in the camera update function, for example).
Thanks again!

Brian Jorgensen

unread,
May 5, 2008, 6:40:44 PM5/5/08
to pyglet...@googlegroups.com
There is an easy way to do what you want, but glViewport doesn't do what you're looking for. It is used to specify what part of the window to render to, and you can't use it to move the camera around. glOrtho can be used the way you're thinking, but no one would do it that way in practice. Drew's suggestion is actually the right way to do it, you're probably just unfamiliar with some of the terminology used by OpenGL. You can use a pre-made camera class if you want, but here is some simple example code that will do what you want and might help you to understand OpenGL better:

# in case you don't know, this line lets you use
# glViewport instead of pyglet.gl.glViewport, etc.

from pyglet.gl import *

# some people think you shouldn't import
# the entire gl namespace, but it makes it
# easier when you're learning OpenGL and
# pyglet at the same time...


def on_resize(width, height):

   
# set up the windowing transform so
    # it draws to the entire window

    glViewport(0, 0, width, height)
   
    glMatrixMode(GL_PROJECTION)

    glLoadIdentity()

    # to center the camera, you want
    # the left edge to be at -width/2
    # and the right edge at width/2

    w =
window._width/2
    h =
window._height/2

   
# now, glOrtho specifies the size of the
    #
'viewport' in the sense you were thinking,
    # i.e. the 'size' covered by the camera

    glOrtho(-w, w, -h, h, -1.0, 1.0)

    # now, the camera is centered in the window
    # and we can move it around when we draw
    # the scene...

def on_draw():

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    # position the camera, per Drew's advice...
    # the 'size' will be whatever you set with
    # glOrtho in the resize handler...

    glTranslatef(-camera.pos.x,
                 -camera.pos.y,
                 -camera.pos.z)

    # now draw your scene

    for surface in scene:

        # (push and pop let you save
        #  the camera position between
        #  drawing each object)

        glPushMatrix()
        glTranslatef(surface.pos.x,
                     surface.pos.y,
                     surface.pos.z)
        surface.draw()
        glPopMatrix()


Hope that helps,
Brian

John Harrison

unread,
May 6, 2008, 12:30:05 PM5/6/08
to pyglet-users


On May 5, 8:27 am, "Drew Smathers" <drew.smath...@gmail.com> wrote:
>
> Either way, there is no camera in OpenGL, just a world matrix
> transformation. You can model the position of the `camera` with a
> Camera class and just take the inverse of it's position when applying
> the transformation:
>
> glTranslatef(-camera.pos.x, -camera.pos.y, -camera.pos.z)

Can someone explain to me why people keep repeating that OpenGL has no
concept of a camera? What is wrong with the gluLookAt(camera_x,
camera_y, camera_z, look_x, look_y, look_z, up_x, up_y, up_z)
command? Doesn't that do exactly what the op is asking for by letting
you draw your world ignorant of what the viewpoint is (if you want)
and simply position a camera within it? I use this in a 3d game of
mine and it works just fine.

Brian Fisher

unread,
May 6, 2008, 12:46:40 PM5/6/08
to pyglet...@googlegroups.com
why do people say OpenGL has no camera? because the official line from OpenGL says there is no camera:
http://www.opengl.org/resources/faq/technical/viewing.htm

What they mean is there is no variable or storage space for a camera position or direction - just matrices. Like you have noticed though, changing the transform in glMatrixMode(GL_MODELVIEW) and in particular using gluLookAt in that mode lets you manage your own camera position and direction and make OpenGL respect that data.

Brian Jorgensen

unread,
May 6, 2008, 1:07:48 PM5/6/08
to pyglet...@googlegroups.com
gluLookAt is fine for a stationary camera, but it is kind of clumsy otherwise. Also gluLookAt is unnecessary for a 2d game, as the OP was asking about.

Drew Smathers

unread,
May 6, 2008, 1:59:40 PM5/6/08
to pyglet...@googlegroups.com
On Tue, May 6, 2008 at 12:30 PM, John Harrison <johnha...@gmail.com> wrote:
>
>
>
> On May 5, 8:27 am, "Drew Smathers" <drew.smath...@gmail.com> wrote:
> >
> > Either way, there is no camera in OpenGL, just a world matrix
> > transformation. You can model the position of the `camera` with a
> > Camera class and just take the inverse of it's position when applying
> > the transformation:
> >
> > glTranslatef(-camera.pos.x, -camera.pos.y, -camera.pos.z)
>
> Can someone explain to me why people keep repeating that OpenGL has no
> concept of a camera?

Because it doesn't.

> What is wrong with the gluLookAt(camera_x,
> camera_y, camera_z, look_x, look_y, look_z, up_x, up_y, up_z)
> command?

Nothing. It's just more complex than glTranslatef for something like an RTS.

> Doesn't that do exactly what the op is asking for by letting
> you draw your world ignorant of what the viewpoint is (if you want)
> and simply position a camera within it? I use this in a 3d game of
> mine and it works just fine.
>

Ok.

John Harrison

unread,
May 6, 2008, 7:20:27 PM5/6/08
to pyglet-users


On May 6, 11:07 am, "Brian Jorgensen" <brian.jorgen...@gmail.com>
wrote:
> gluLookAt is fine for a stationary camera, but it is kind of clumsy
> otherwise. Also gluLookAt is unnecessary for a 2d game, as the OP was asking
> about.

I've never noticed that. I tell it where the "camera" (I guess I
can't call it that because obviously OpenGL has no concept of such a
thing, right?) is, what to look at, and which way is up. Am I missing
something?

Gary Herron

unread,
May 6, 2008, 7:45:26 PM5/6/08
to pyglet...@googlegroups.com

No, you are not missing anything, quite the opposite in fact. The
concept of "camera" is in your head, and you use low-level operations in
OpenGL to implement it.

Your code probably looks something like this: You represent the camera
(in your mind and your program) with several parameters, like position,
direction of view, angle of view, and up vector. Then you pass those
various parameters to OpenGL via calls to gluLookAt and glFrustum, or
gluPerspective and so forth, and OpenGL computes and stores a couple of
4x4 matrices in response.

Whether or not you store those parameters in an object called a "camera"
is a programming decision you make, but certainly you can't call the 4x4
matrices built by OpenGL a "camera". OpenGL just provides you with
all the low-level matrix manipulation tools needed to implement a camera
in your code.

Gary Herron


> >
>

Brian Jorgensen

unread,
May 6, 2008, 8:47:12 PM5/6/08
to pyglet...@googlegroups.com
Thanks Gary, that's a good way to put it, and John, you're definitely not missing anything. I just remember that when I was getting started with OpenGL (like the OP), I had lots of inaccurate expectations of the library calls, and this caused me some unnecessary confusion.

Whoops, I didn't mean to say that gluLookAt was only good for "stationary" cameras. I meant to say that gluLookAt is perfect when you know the eye point and a look at point (or direction vector) in advance. But you often have a camera which is more naturally represented by an eye point and an orientation, such as a first-person cam or a chase cam. If you know a bit of 3D math, you can easily calculate a look at vector from the rotation and pass this to gluLookAt, but you're probably doing extra work.

If you have the orientation stored as euler angles, you might as well apply the rotation directly. If you have it stored as a UVW basis, gluLookAt would just unnecessarily recalculate it using your W (the look at vector). If you're using something else, like quaternions, you're probably building your own view matrix already. In the event that you're already using a rotated view vector to represent your orientation, then great, use gluLookAt and save some lines of code.

It'd be fair to say that this is mostly pedantic. I guess my point is just that gluLookAt isn't the swiss army knife of OpenGL cameras, and that in practice, it ends up being of limited use.

Brian

eFFeeMMe

unread,
May 7, 2008, 10:08:54 AM5/7/08
to pyglet-users
Thanks, that was useful!
A small problem I have though is that up to now I was using a batch of
sprites,
whereas I'll have to draw them one by one now.

Do I have to do
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
on each window draw event?

EDIT: just using glTranslatef on the camera seems to make sprites be
drawn in the right place, even with batches, I don't seem to need to
push and pop matrices for each image. Is this correct?

On May 6, 12:40 am, "Brian Jorgensen" <brian.jorgen...@gmail.com>
wrote:
> On Mon, May 5, 2008 at 2:57 PM, eFFeeMMe <francesco.mastell...@gmail.com>

Drew Smathers

unread,
May 7, 2008, 11:01:56 AM5/7/08
to pyglet...@googlegroups.com
On Wed, May 7, 2008 at 10:08 AM, eFFeeMMe
<francesco....@gmail.com> wrote:
>
> Thanks, that was useful!
> A small problem I have though is that up to now I was using a batch of
> sprites,
> whereas I'll have to draw them one by one now.
>
> Do I have to do
> glMatrixMode(GL_MODELVIEW)
> glLoadIdentity()
> on each window draw event?
>

Generally, you should only have to set the matrix mode in on_resize.
I generally use glLoadIdentity on each draw, otherwise this adds onto
previous transformations - which is certainly not what you want.

If you are just writing a 2d game, the base window class takes care of
most of this for you, so you might want to just subclass like:

class MyWindow(pyglet.window.Window):
def on_draw(self):
glLoadIdentity()
glTranslatef(-camera_x, -camera_y, -camera_z)


> EDIT: just using glTranslatef on the camera seems to make sprites be
> drawn in the right place, even with batches, I don't seem to need to
> push and pop matrices for each image. Is this correct?

The textures are blitted to an absolute position, so you should not
need to push/pop matrices for each image.

eFFeeMMe

unread,
May 7, 2008, 11:24:50 AM5/7/08
to pyglet-users
Alright, everything works fine now(I was already subclassing Window).
Thanks a lot to everybody for the help!

On May 7, 5:01 pm, "Drew Smathers" <drew.smath...@gmail.com> wrote:
> On Wed, May 7, 2008 at 10:08 AM, eFFeeMMe
>

eFFeeMMe

unread,
May 16, 2008, 2:46:38 PM5/16/08
to pyglet-users
Hello, I'm still working on that little RTS project.

I've managed to make a Map class, which stores information about the
terrain, and produces OpenGL output based on it. So far I've randomly
generated stuff like height and tile color, but I wanted to be able to
load those from a file, possibly an image. The problem is, I have no
clue how to use the output from ImageData.get_data.

My code so far:
def heightMapFromImage(self, image):
imageData = image.get_image_data()
data = imageData.get_data('RGB', imageData.width * 3)

def heightFromHeightMap(self, heightMap):
iii = min(len(heightMap), self.width)
jjj = min(len(heightMap[0]), self.height)

for i in range(iii):
for j in range(jjj):
t = self.getTile(iii, jjj)
t.height = heightMap[iii][jjj]

In the second function, heightMap is supposed to be a bidimensional
array containing integers. How do I get those integers out of the
string get_data returns me?

eFFeeMMe

unread,
May 17, 2008, 8:10:20 AM5/17/08
to pyglet-users
Whoops, the code in the previous message should have these two lines:
t = self.getTile(iii, jjj)
t.height = heightMap[iii][jjj]
Changed to:
t = self.getTile((i, j))
t.height = heightMap[i][j]

By the way, I lowered my hopes a little and will save height stuff for
a future RTS. Right now I'd be happy with a map made out of a few big
quads(for minor culling), with a repeating texture. I know how to use
textures with glBegin and glEnd 'tags', but how do I go about mapping
textures onto vertex lists or indexed vertex lists(which by the way
I'd like to know how to make, since I couldn't find examples anywhere,
and I looked a lot)?

eFFeeMMe

unread,
May 17, 2008, 8:59:43 AM5/17/08
to pyglet-users
YET more questions! I'm such a noob. =p

Why does this flicker?

indexed_vertex_list = pyglet.graphics.vertex_list_indexed(6,
(0, 1, 2, 3,
2, 3, 4, 5),
('v2i', (10, 25,
30, 45,
60, 30,
40, 10,
80, 20,
70, 0)
),
('c3B', (0, 0, 255,
0, 255, 0,
255, 0, 0,
0, 255, 0,
0, 0, 255,
0, 255, 0))
)

indexed_vertex_list.draw(pyglet.gl.GL_QUADS)

Alex Holkner

unread,
May 17, 2008, 10:34:49 PM5/17/08
to pyglet...@googlegroups.com
On Sat, May 17, 2008 at 10:59 PM, eFFeeMMe
<francesco....@gmail.com> wrote:
>
> YET more questions! I'm such a noob. =p
>
> Why does this flicker?
>
> indexed_vertex_list = pyglet.graphics.vertex_list_indexed(6,
> (0, 1, 2, 3,
> 2, 3, 4, 5),
> ('v2i', (10, 25,
> 30, 45,
> 60, 30,
> 40, 10,
> 80, 20,
> 70, 0)
> ),
> ('c3B', (0, 0, 255,
> 0, 255, 0,
> 255, 0, 0,
> 0, 255, 0,
> 0, 0, 255,
> 0, 255, 0))
> )
>
> indexed_vertex_list.draw(pyglet.gl.GL_QUADS)

You'll need to provide a more complete example.

Alex.

eFFeeMMe

unread,
May 18, 2008, 6:18:22 AM5/18/08
to pyglet-users
Yay, I fixed it! Well, since I was just testing out OpenGL functions,
I thought that making new vertex lists on each draw event wasn't so
bad. I moved the vertex list outside the event and now it seems to
work alright. Now, how do I go about textures?

Thanks in advance!

Drew Smathers

unread,
May 18, 2008, 6:35:35 PM5/18/08
to pyglet...@googlegroups.com
On Sun, May 18, 2008 at 6:18 AM, eFFeeMMe
<francesco....@gmail.com> wrote:
>
> Yay, I fixed it! Well, since I was just testing out OpenGL functions,
> I thought that making new vertex lists on each draw event wasn't so
> bad. I moved the vertex list outside the event and now it seems to
> work alright. Now, how do I go about textures?

http://pyglet.org/doc/1.1/programming_guide/opengl_imaging.html

eFFeeMMe

unread,
May 19, 2008, 9:37:06 AM5/19/08
to pyglet-users
With this in the __init__ method of my window:
self.grassTexture = pyglet.resource.texture('grass.jpg')
self.grassTextureGroup =
pyglet.graphics.TextureGroup(self.grassTexture)

And this in the generateMesh method of my map(you can guess what it
does):
self.mesh.add_indexed(numTiles, GL_QUADS, self.root.grassTextureGroup,
indexData,
('v2i', vertexPositionData),
('c3B', vertexColorData))

All that shows is... http://i31.tinypic.com/xfdqa8.png
Which is the average color of the grass texture(I suppose) applied
onto the terrain. Why?

On May 19, 12:35 am, "Drew Smathers" <drew.smath...@gmail.com> wrote:
> On Sun, May 18, 2008 at 6:18 AM, eFFeeMMe
>

eFFeeMMe

unread,
May 21, 2008, 11:38:37 AM5/21/08
to pyglet-users
Alright. The map color is not the average color of the texture, but
rather the color of the top left pixels. I think this means I should
translate the texture above the terrain. How do I do that using
TextureGroups?

On May 19, 3:37 pm, eFFeeMMe <francesco.mastell...@gmail.com> wrote:
> With this in the __init__ method of my window:
> self.grassTexture = pyglet.resource.texture('grass.jpg')
> self.grassTextureGroup =
> pyglet.graphics.TextureGroup(self.grassTexture)
>
> And this in the generateMesh method of my map(you can guess what it
> does):
> self.mesh.add_indexed(numTiles, GL_QUADS, self.root.grassTextureGroup,
> indexData,
>                                  ('v2i', vertexPositionData),
>                                  ('c3B', vertexColorData))
>
> All that shows is...http://i31.tinypic.com/xfdqa8.png

Alex Holkner

unread,
May 21, 2008, 7:34:52 PM5/21/08
to pyglet...@googlegroups.com
On 5/22/08, eFFeeMMe <francesco....@gmail.com> wrote:
>
> Alright. The map color is not the average color of the texture, but
> rather the color of the top left pixels. I think this means I should
> translate the texture above the terrain. How do I do that using
> TextureGroups?
>
>
> On May 19, 3:37 pm, eFFeeMMe <francesco.mastell...@gmail.com> wrote:
> > With this in the __init__ method of my window:
> > self.grassTexture = pyglet.resource.texture('grass.jpg')
> > self.grassTextureGroup =
> > pyglet.graphics.TextureGroup(self.grassTexture)
> >
> > And this in the generateMesh method of my map(you can guess what it
> > does):
> > self.mesh.add_indexed(numTiles, GL_QUADS, self.root.grassTextureGroup,
> > indexData,
> > ('v2i', vertexPositionData),
> > ('c3B', vertexColorData))
> >
> > All that shows is...http://i31.tinypic.com/xfdqa8.png
> > Which is the average color of the grass texture(I suppose) applied
> > onto the terrain. Why?

You're not supplying any texture coordinates.

Alex.

eFFeeMMe

unread,
May 22, 2008, 9:18:48 AM5/22/08
to pyglet-users
And you're not supplying an useful answer... I know that it's what I
need to do but how do I do such a thing using the TextureGroup class
pyglet provides?

On 22 Mag, 01:34, "Alex Holkner" <alex.holk...@gmail.com> wrote:

Drew Smathers

unread,
May 22, 2008, 12:00:45 PM5/22/08
to pyglet...@googlegroups.com
On Thu, May 22, 2008 at 9:18 AM, eFFeeMMe
<francesco....@gmail.com> wrote:
>
> And you're not supplying an useful answer...

That's rude. I think you've gotten plenty of help with your questions
on this thread.

> I know that it's what I
> need to do but how do I do such a thing using the TextureGroup class
> pyglet provides?

What you're asking is really not a question specific to pyglet, but to
OpenGL. And it sounds like you're really trying to jump into advanced
usage, when for your use case could likely be covered by using higher
level abstractions provided by pyglet:

http://pyglet.org/doc/1.1/programming_guide/displaying_images.html#sprites

eFFeeMMe

unread,
May 22, 2008, 2:33:08 PM5/22/08
to pyglet-users
*sigh* I'm not trying to be rude, sorry. 'Just not used to the time it
takes for people to reply in here. The point is, I don't think mapping
a texture over a polygon is that big a deal. I know how to do it in
the usual procedural approach to OpenGL rendering (glBegin etc.), but
how can it be done when the vertex data is inside a list and the
texture is enabled through TextureGroups?

By the way, in 2d RTS games there has always been the little problem
of realistically displaying terrain of different heights, which if
handled in 2d would require way too many sprites(and I'm no artist).
The solution is rendering terrain in 3d, all else in 2d. The problem
is that there's no point in having curved terrain when all you see is
a green blob, and I was hoping that a texture, mapped onto the terrain
mesh, would appear deformed and give the idea of height.

On May 22, 6:00 pm, "Drew Smathers" <drew.smath...@gmail.com> wrote:
> On Thu, May 22, 2008 at 9:18 AM, eFFeeMMe
>
> <francesco.mastell...@gmail.com> wrote:
>
> > And you're not supplying an useful answer...
>
> That's rude.  I think you've gotten plenty of help with your questions
> on this thread.
>
> > I know that it's what I
> > need to do but how do I do such a thing using the TextureGroup class
> > pyglet provides?
>
> What you're asking is really not a question specific to pyglet, but to
> OpenGL.  And it sounds like you're really trying to jump into advanced
> usage, when for your use case could likely be covered by using higher
> level abstractions provided by pyglet:
>
> http://pyglet.org/doc/1.1/programming_guide/displaying_images.html#sp...

eFFeeMMe

unread,
May 23, 2008, 10:19:26 AM5/23/08
to pyglet-users
Just an update: I worked out the heightmap stuff and used a grid to
display height differences.
Screenshot: http://i30.tinypic.com/1zmcdac.png

I'd still very much like to know how to map a texture onto the batch-
stored terrain, however!

riq

unread,
May 23, 2008, 10:30:20 AM5/23/08
to pyglet...@googlegroups.com
On Fri, May 23, 2008 at 11:19 AM, eFFeeMMe <francesco....@gmail.com> wrote:

Just an update: I worked out the heightmap stuff and used a grid to
display height differences.
Screenshot: http://i30.tinypic.com/1zmcdac.png

I'd still very much like to know how to map a texture onto the batch-
stored terrain, however!

Hi,
this example might help you:

http://los-cocos.googlecode.com/svn/trunk/samples/demo_flag3d.py

(The example shows how to render a texture on a grid)

Although it is not a 100% pyglet, it will be relatively easy to remove the 'cocos' part from it.
Hope this helps.

riq.


--
ser humano
http://monodiario.blogspot.com

eFFeeMMe

unread,
May 23, 2008, 12:14:13 PM5/23/08
to pyglet-users
Helps a lot, thank you!

On May 23, 4:30 pm, riq <ricardoques...@gmail.com> wrote:
> On Fri, May 23, 2008 at 11:19 AM, eFFeeMMe <francesco.mastell...@gmail.com>
Reply all
Reply to author
Forward
0 new messages