Tuesday, March 17

Better texture support in Lepton

Now that Lepton 0.9a is out the door, it's time to think about the next steps in the particle engine's evolution. In particular, there are two main features I'd like to work on for the next release:
  • Greatly improved texture support
  • Interpolating particle attributes from a specific starting state to an ending state.

The former will be addressed with "texturizers". These will have the following functionality:
  • Handle the requisite loading of textures into the graphics card
  • Perform necessary texture-related state changes before rendering particles in a group
  • Computing texture coordinates for each active particle in the group
  • Restore the texture state to what is was prior to rendering the group

Here's a tentative interface for a texturizer:
class Texturizer:

def set_state(self):
"""This method sets the appropriate
OpenGL state for rendering. It is called
immediately before rendering a group of particles.

def restore_state(self):
"""Restores the OpenGL state to what it was
before the call to set_state().
It is called after rendering a group of particles.

def tex_dimension(self):
"""The number of texture coordinates per vertex,
either 2 or 3

def generate_tex_coords(self, group, coord_array):
"""Generate texture coordinates for all active
particles in the group, placing them in the
cooresponding places in coord_array, an
array of floats.

Each particle gets four texture positions
cooresponding to its lower left, lower right, upper
right and upper left corners respectively.
The number of coordinates per texture position is
determined by the value of tex_dimension.

The texturizer will be instantiated by the user for use with a renderer. The arguments needed to instantiate the texturizer will vary depending on the type of texturizer. Most will accept one or more texture objects (probably borrow some pyglet code for those) and other ancillary arguments to control specific features. Here's an example of how you might use a simple texturizer:
my_texture = Texture('amazing_image.png')
particles = ParticleGroup(
controllers=[...controllers go here..],

This would simply apply the same texture derived from the image file amazing_image.png to each particle in the group. By default it would perform bilinear filtering to scale the texture and would clamp at the edges (i.e., it would not tile).

Here are some ideas for different texturizers:

Could apply one or more texture images to a group of particles. The images would be packed into a single texture atlas and the texturizer would select them by varying the texture coordinates per particle. The images could be applied sequentially (i.e., round-robin) to each particle in a group, or randomly. It may also be possible to apply weights to each sprite image to have some applied more often than others.

Could apply a sequence of images to all particles in a group, like above the image frames would be packed into a single texture object in OpenGL. The animation frame assigned to each particle would be based on that particle's age. It would have an option for packing the frames into a 3D texture, so you could smoothly interpolate between the frames on the hardware. This would allow smooth animation with fewer frames.

Could apply multiple textures to all particles in a group simultaneously. This would allow various effects by blending multiple textures together. One usage would be to have a large base texture that may also be tiled. The base texture could stay stationary relative to the particles. A second "splat" texture would be applied to each particle to show the base texture at that particle's position. As particles moved they would reveal different parts of the base texture. The splat texture could have sharp or fuzzy edges depending on the desired effect. This could be used for various simple animation techniques, or different stylized rendering.

Labels: ,


Post a Comment

<< Home