Creating New Textures from Scratch
The PNMImage Class
This class is how Panda3D handles regular images (.gif, .jpg, and the like).
This class allows you to manipulate individual pixels of the image. You can load
existing images using the function
filename is the path to the image file. Or, you can create a brand new image
from scratch, by passing the x, y size to the constructor.
myImage = PNMImage() myImage.read("testImg.png") myEmptyImage = PNMImage(256, 256)
You can get the size of the image you have read using the
Although you cannot change the size of an image directly, you can rescale an
image by filtering it into a larger or smaller PNMImage:
fullSize = PNMImage(Filename("testImg.png")) reduced = PNMImage(256, 256) reduced.gaussianFilterFrom(1.0, fullSize)
You can get individual RGB values using the
get_blue(x, y) or
get_blue_val(x, y) methods, where x and y are
the coordinates of the pixel to sample (the upper-left corner is
whereas the lower-right corner is
size.x - 1, size.y - 1).
The difference between these functions is that the regular getters functions
return a number between 0.0 and 1.0, while the ones marked with “val” return
their raw value as an integer. For example, if your image uses 8-bit-per-channel
get_green_val() will return 255 for a fully
green pixel whereas calling
get_green() will return 1.0.
You can also get all the RGB information at the same time using
get_xel(x, y) and
get_xel_val(x, y), which return a 3-component
vector containing the red, green and blue channels, respectively.
# The pixel at 0,0 is red and we're using 8-bit color myImage.getRedVal(0, 0) # Returns 255 myImage.getRed(0, 0) # Returns 1 colors = myImage.getXelVal(0,0) # Returns (255,0,0) colorVal = myImage.getXel(0,0) # Returns (1,0,0)
The methods for setting pixel information are
set_red(x, y, value),
set_green(x, y, value),
set_blue(x, y, value),
set_xel(x, y, color), or
set_red_val(x, y, value),
set_green_val(x, y, value),
set_blue_val(x, y, value),
set_xel_val(x, y, color).
The same as above applies regarding the dichotomy between the regular setters
and the ones marked with “val”. You can also fill an image with a color by using
fill(r, g, b) and
fill_val(r, g, b).
myImage.setGreenVal(0, 0, 255) # If pixel (0, 0) was red before, now it is yellow myImage.setBlue(0, 0, 1) # Pixel (0, 0) is now white gray = Vec3(0.5, 0.5, 0.5) # Both of these set the origin to gray myImage.setXelVal(0, 0, gray * 255) myImage.setXel(0, 0, gray) # Makes every pixel red myImage.fillVal(255, 0, 0) # Makes every pixel green myImage.fill(0, 1, 0)
There are also gets and sets for the alpha channel using the same interface as
above. However, if you use them on an image that doesn’t have an alpha channel
you will cause a crash. To see if an image has an alpha channel use
has_alpha() which returns True if there is an alpha channel
and False otherwise. You can add an alpha channel using
add_alpha(). You can also remove it using
You can also make an image grayscale using
To set or get a grayscale value, you can use
set_gray(). (Using these functions on a color image will just
affect the value in the blue channel.) If you want to get the grayscale
value of a pixel regardless of whether the image is a grayscale or a color
image, you can use
get_bright(x, y), which works
equally well on color or on grayscale images. If you want to weight the colors
get_bright(x, y, r, g, b), where r, g, b are
the weights for the respective channels.
There are several other useful functions in the class, which are described on
PNMImage page in the API Reference.
Storing a Texture into an Image
Texture class does not allow for pixel manipulation. But the
PNMImage class does. Therefore, if you want to change the image in a
Texture object you must call
which saves the image of the texture into the given image object.
myImage = PNMImage() myTexture = loader.loadTexture("myTex.jpg") # After this call, myImage now holds the same image as the texture myTexture.store(myImage)
Loading a PNMImage into a Texture
Once you have changed all the data in the image you can now load it into a
texture using the texture’s
load(myImage) method, where
myImage is the PNMImage to make the texture from.
# Assume we already have myImage which is our modified PNMImage myTexture = Texture("texture name") # This texture now contains the data from myImage myTexture.load(myImage)
Remember however, that most graphics cards require that the dimensions of
texture have to be a power of two.
PNMImage does not have this
restriction and Panda will not automatically scale the image when you put it
into a texture.