Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working with Panda3d and recently switched my game to isometric rendering. I moved the virtual camera accordingly and set an orthographic lens. Then I implemented the classes "Map" and "Canvas".

A canvas is a dynamically generated mesh: a flat quad. I'm using it to render the ingame graphics. Since the game itself is still set in a 3d coordinate system I'm planning to rely on these canvases to draw sprites. I could have named this class "Tile" but as I'd like to use it for non-tile sketches (enemies, environment) as well I thought canvas would describe it's function better.

Map does exactly what it's name suggests. Its constructor receives the number of rows and columns and then creates a standard isometric map. It uses the canvas class for tiles. I'm planning to write a map importer that reads a file to create maps on the fly.

Here's the canvas implementation:

class Canvas:
def __init__(self, texture, vertical=False, width=1,height=1):

    # create the mesh         
    format=GeomVertexFormat.getV3t2()
    format = GeomVertexFormat.registerFormat(format)
    vdata=GeomVertexData("node-vertices", format,  Geom.UHStatic)

    vertex = GeomVertexWriter(vdata, 'vertex')
    texcoord = GeomVertexWriter(vdata, 'texcoord')

    # add the vertices for a flat quad
    vertex.addData3f(1, 0, 0)
    texcoord.addData2f(1, 0)
    vertex.addData3f(1, 1, 0)
    texcoord.addData2f(1, 1)
    vertex.addData3f(0, 1, 0)
    texcoord.addData2f(0, 1)
    vertex.addData3f(0, 0, 0)
    texcoord.addData2f(0, 0)

    prim = GeomTriangles(Geom.UHStatic)
    prim.addVertices(0, 1, 2)
    prim.addVertices(2, 3, 0)

    self.geom = Geom(vdata)
    self.geom.addPrimitive(prim)

    self.node = GeomNode('node')
    self.node.addGeom(self.geom)

    # this is the handle for the canvas
    self.nodePath=NodePath(self.node)

    self.nodePath.setSx(width)
    self.nodePath.setSy(height)

    if vertical:
        self.nodePath.setP(90)

    # the most important part: "Drawing" the image
    self.texture=loader.loadTexture(""+texture+".png")
    self.nodePath.setTexture(self.texture)

Now the code for the Map class

class Map:
def __init__(self,rows,columns,size):
    self.grid=[]
    for i in range(rows):
        self.grid.append([])
        for j in range(columns):

            # create a canvas for the tile. For testing the texture is preset
            tile=Canvas(texture="../assets/textures/flat_concrete",width=size,height=size)
            x=(i-1)*size
            y=(j-1)*size

            # set the tile up for rendering
            tile.nodePath.reparentTo(render)
            tile.nodePath.setX(x)
            tile.nodePath.setY(y)

            # and store it for later access
            self.grid[i].append(tile)

And finally the usage

    def loadMap(self):
        self.map=Map(10, 10, 1)

this function is called within the constructor of the World class. The instantiation of world is the entry point to the execution.

The code is pretty straightforward and runs good. Sadly the output is not as expected:

isometric ?

Please note: The problem is not the white rectangle, it's my player object. The problem is that although the map should have equal width and height it's stretched weirdly. With orthographic rendering I expected the map to be a perfect square.

What did I do wrong ?

UPDATE:

I've changed the viewport. This is how I set up the orthographic camera:

    lens = OrthographicLens()
    lens.setFilmSize(40, 20)
    base.cam.node().setLens(lens)

You can change the "aspect" by modifying the parameters of setFilmSize. I don't know exactly how they are related to window size and screen resolution but after testing a little the values above seem to work for me.

Now everything is rendered correctly as long as I don't resize the window. Every change of the window's size as well as switching to fullscreen destroys the correct rendering. I know that implementing a listener for resize events is not in the scope of this question. However I wonder why I need to make the Film's height two times bigger than its width. My window is quadratic !

Can you tell me how to find out correct setting for the FilmSize ?

UPDATE 2:

I can imagine that it's hard to envision the behaviour of the game. At first glance the obvious solution is to pass the window's width and height in pixels to setFilmSize. There are two problems with that approach.

  1. The parameters for setFilmSize are ingame units. You'll get a way to big view if you pass the pixel size
  2. For some strange reason the image is distorted if you pass equal values for width and height.

Here's the output for setFilmSize(800,800) definitely wrong You'll have to stress your eyes but you'll see what I mean

share|improve this question
    
Possibly something wrong with you Viewport setup. –  bobenko Jan 19 '12 at 12:16
    
thank you, it works. I've changed the parameters of lens.setFilmSize and with a little experimenting the map is now quadratic. How can I automate this ? The game will run fullscreen eventually and then there will be different aspect ratios. –  lhk Jan 19 '12 at 12:26
    
i do not not know how exactly in python it works, but in general you have to make some listener or handler onWindowResize, that changes viewport parameters automatically, according to your new resolution. I suppose Canvas class contains such functionality. –  bobenko Jan 19 '12 at 12:28
    
I've called lens.setFilmSize(40, 20) to get rid of the stretching. Now I wonder: Why do I need this FilmSize with a quadratic window ? I would have guessed that the parameters mirror the windows size –  lhk Jan 19 '12 at 12:29
    
setFilmSize as I understand sets aspect ratio of the camera, and it is up to you to select what aspect ratio to select 4:3, 1:1, 16:9 etc. –  bobenko Jan 19 '12 at 12:38

1 Answer 1

setFilmSize doesn't set the aspect ratio, it sets the size of your screen, like glOrthof in OpenGL.

More specifically, it sets the the resolution of the viewport. 3D coordinates are arbritary, so it should look good if you set it to the same value as the window's size. (So 1 unit will be equal to 1 pixel.)

This isn't a hard and fast rule of course. If you have a 3D setting such that 1 unit is 1 foot, then setting your film size to 800x600 will give a 800ft x 600ft view in your scene.

share|improve this answer
    
your answer appears unnecessarily aggressive: "If you care to search just a little". If you've read my code it will be obvious to you that I've heavily relied on the panda3d manual. Moreover if you'd really read my question you should know that the problem is not that simple. According to your answer "That is, the resolution of the viewport. But as 3D coordinates are arbritary, it should be nice if you set it to the same value as the window's size." the film should have equal width and height for a quadratic window. In fact that was my initial setup and it doesn't work. –  lhk Jan 19 '12 at 16:27
    
I've found out that setFilmSize(40,20) gives right results for a quadratic window. Even if you consider different pixel "densities" this doesn't seem right. –  lhk Jan 19 '12 at 16:28
    
I figure that on a 1600*1050 resolution on a 16/9 screen a quadratic window results in a not exactly quadratic pixel rectangle for a quadratic window. Still that doesn't explain it –  lhk Jan 19 '12 at 16:31
    
I admit that I've used aspect ratio too losely. However in the end setFilmSize does determine the aspect ratio. You just need to divide its parameters to get it. An aspect ratio of 2 for a quadratic window can't be right. –  lhk Jan 19 '12 at 16:40
    
If you want a quadratic window, Set the window size to 800x800 and the FilmSize to 800x800 too. Thats not hard. And sorry if i was aggressive. FilmSize is NOT aspect ratio, FilmSize is the size of the screen that the window will show. Its good for you to set the FilmSize as the same than the Window Size, if you want to 1unit of your scene to be 1 pixel on the screen. –  Gustavo Maciel Jan 19 '12 at 18:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.