Skip to content

Images

  • Put a source image file anywhere in your project folder!
  • On the next build, a name.image.lx is generated next to it, pointing at it as source.
  • The generated file is only written when one does not exist, so edits you make to it are kept.
  • If another asset already references the source, no default image.lx is generated.
image = {
source = "image/bee.png"
generate_mips = "none"
format = "rgba8Unorm"
}
  • An image asset is a name.image.lx file that describes how to build a GPU image.
  • It points at one or more source files and says what to make from them.
  • Source files are .png, .jpg, .tga, .psd, .hdr, .exr and .ktx.
  • The source file is not the asset. The image.lx is the asset, and the source is its input.
  • One image.lx produces one image: a 2D image, a cube, or an array (image2D, imageCube, image2DArray).
  • A .ktx source can also produce 1D and 3D images, and arrays of those.
  • format comes from the setting assets.image.format, and is rgba8Unorm when not set.
  • generate_mips comes from the setting assets.image.generate_mips, and is none when not set.
  • .hdr and .exr sources use the config render.general.source_format instead, and are rgba32Float when not set.
  • The fields that are set decide what kind of image is built. Only one applies, checked in this order.
  • pack has entries, or no source of any kind is set: a packed 2D image, see Channel packing.
  • cube_image2D is set: a cube from one 2D image, see Cube from one image.
  • source is set: a 2D image, or whatever a .ktx source holds.
  • cube is set: a cube from six images, see Cube from six images.
  • array is set: an image array, see Image arrays.
  • format is the pixel format of the built image, by name.
  • The source is decoded and converted to this format at build time.
  • Single and two channel formats, like r8Unorm and rg8Unorm, keep that many channels of the source.
  • _srgb formats mark the data as sRGB encoded, so it is decoded to linear when sampled.
  • Data that is not a color, like normals, roughness or masks, should not use an _srgb format.
  • rgba8Unorm: 8 bits per channel, linear.
  • rgba8Unorm_srgb: 8 bits per channel, sRGB encoded color.
  • rgba16Float: half float per channel, for HDR.
  • rgba32Float: full float per channel, for HDR.
  • r8Unorm, rg8Unorm: one or two 8 bit channels.
  • Full list: PixelFormat in luxe: render.
  • Block compressed (BCn): bc1_rgba, bc3_rgba, bc4_r, bc5_rg, bc6h_uf16, bc6h_sf16, bc7_rgba.
  • bc1, bc3 and bc7 also have _srgb variants.
  • ASTC: astc4x4_rgba, astc4x4_rgba_srgb, astc6x6_rgba, astc8x8_rgba, astc4x4_hdr.
  • The source is compressed at build time.
  • :todo: confirm which builds include the BCn (all formats) and ASTC encoders. Without the BCn encoder only bc1 and bc3 are available, and packed images cannot use BCn at all.
  • An .hdr or .exr source is read as float when the format can hold it.
  • Formats that read float are the float formats, bc6h_uf16, bc6h_sf16 and astc4x4_hdr.
  • Otherwise the source is converted to 8 bit.
  • force_ldr reads the source as 8 bit even when the format is float.
  • bc6h has no alpha channel, so alpha is dropped.
  • Mips (mipmaps) are smaller copies of the image, used when it is drawn small or far away.
  • generate_mips is none or build.
  • none keeps what the source has. A .png has one level, a .ktx can carry its own mips.
  • build generates the whole chain at build time, down to 1x1.
  • build only applies to rgba8Unorm and rgba8Unorm_srgb from a single source. Other images keep one level, and a warning is logged.
  • generate_mipmaps_at_load marks the image to generate its mips when it is loaded.
  • :todo: explain when to use generate_mipmaps_at_load over generate_mips = "build".
  • generate_mips_filter decides how each level is made from the one above.
  • These are different algorithms, not quality settings. The wrong one produces broken content.
  • color: for color. An _srgb format is decoded to linear before averaging, so levels do not darken.
  • normal: for normal maps. Each texel is renormalized after averaging.
  • data: for anything that is numbers, not color, like ORM maps and masks. Averaged as is.
  • cutout: for alpha tested images, like leaves. Color, plus alpha adjusted per level to keep the coverage of level 0.
  • generate_mips_cutout is the alpha threshold cutout keeps coverage against. Match it to the material’s alpha threshold.
image = {
source = "mesh/uv_cube.glb.assets/base_color.jpg"
format = "rgba8Unorm_srgb"
generate_mips = "build"
generate_mips_filter = "color"
}
  • Channel packing builds one image from channels of several source images.
  • A common use is an ORM map: occlusion, roughness and metallic in the r, g and b channels.
  • pack is a list of entries. Each entry reads channels from one source and writes them to channels of the result.
  • fill is the starting value of every channel, as a color. Default is [0 0 0 1].
  • Each entry overwrites only the channels it names. Channels no entry writes keep the fill value.
  • from: the source image file.
  • read: which channels to read from the source, as letters from rgba. Default r.
  • write: which channels of the result to write them to. Default r.
  • read and write must be the same length, 1 to 4 letters. They pair up in order, so read = "gb", write = "rg" moves g to r and b to g.
  • A channel of the result can only be written once across all entries.
  • space: linear or srgb. srgb decodes the r, g and b channels read from this source to linear. Default linear.
image = {
format = "rgba8Unorm"
generate_mipmaps_at_load = true
pack = [
{
from = "mesh/DamagedHelmet/DamagedHelmet.glb.assets/occlusion.jpg"
read = "r"
write = "r"
space = "linear"
}
{
from = "mesh/DamagedHelmet/DamagedHelmet.glb.assets/metallic_roughness.jpg"
read = "gb"
write = "gb"
space = "linear"
}
]
}
  • The result is the size of the largest source.
  • pack_size sets a minimum size. A larger source still wins.
  • Sources smaller than the result are resized to fit, filtered in linear space when space is srgb.
  • With no sources and no pack_size, the result is 4x4.
  • The packed image has one level, generate_mips = "build" does not apply.
  • Packed images can be rgba8Unorm, rgba8Unorm_srgb, rgba16Float, rgba32Float, or a compressed format.
  • An image.lx with no source and no pack entries is a packed image with nothing written.
  • The result is every texel set to fill.
image = {
fill = [0 0 1 1]
pack_size = [4 4]
}
  • Some asset types generate images and their image.lx as part of their own import.
  • The generated image.lx is only written when one does not exist, so edits to it are kept.
  • A name.noise.lx bakes a noise field to a .png, or a .ktx volume for grid3d.
  • It writes a name.image.lx for the result, using the same import defaults as a dropped image.
  • For a .ktx volume, the format is set to match what was written: r8Unorm or rgba8Unorm.
  • See Noise for the noise fields.
  • An .aseprite or .ase file generates a name.aseprite.lx next to it, with output = "atlas".
  • The aseprite.lx builds frame images, an image asset for them, and anims from the file.
  • output decides the frame images: atlas, sheet or loose.
  • atlas: frames packed into one image, with a name.atlas.lx describing each frame rect.
  • sheet: frames in uniform cells on one image, in rows.
  • loose: one .png per frame, in a name.frames folder.
  • One .anim.lx is written per tag in the file, or one for the whole file when there are no tags.
  • source: the .aseprite or .ase file.
  • max_size: the largest the packed image can be. Default [1024 1024].
  • crop: default true.
  • For atlas only: layout (rows or pack), allow_trim, allow_rotate, padding, extrude, border.
  • The first slice with a pivot sets the pivot of every frame in the atlas.
  • :todo: explain crop.
  • asset.aseprite.auto_import: generate the aseprite.lx for files nothing references yet. Default true.
  • asset.aseprite.source_reimport: generate it even when the file is referenced. Default false.
  • Tag a source file no_source_reimport to never generate one for it.
  • A cube map (imageCube) is six square faces, one per axis direction.
  • It can be built from one 2D image, from six images, or read from a .ktx cube.
  • cube_image2D is a single source laid out as a whole cube, like an HDR environment.
  • cube_image2D_shape is the layout of that source.
  • latlong: an equirectangular panorama, 2:1.
  • cross_h, cross_v: a horizontal (4:3) or vertical (3:4) cross.
  • strip_h, strip_v: six faces in a row or a column.
  • octant: a square octahedral layout.
  • auto: picked from the aspect ratio, in the order above. Fails when nothing matches.
  • cube_image2D_face_size resizes each face. 0 keeps the size the layout gives.
image = {
cube_image2D = "env/the_sky_is_on_fire_2k.exr"
cube_image2D_shape = "latlong"
format = "rgba16Float"
}
  • cube is a list of six source images, one per face.
  • The order is +x, -x, +y, -y, +z, -z.
  • Each face is authored as the view along its axis, with +y up for the side faces.
  • Every face must be the same size.
  • Faces are read as 8 bit rgba, unless the cube is convolved.
  • Convolution prefilters a cube for lighting, as irradiance or radiance.
  • convolution is an object on the image.lx with these fields.
  • type: none, irradiance or radiance.
  • irradiance: diffuse lighting, one value per direction. Default face size 64.
  • radiance: specular lighting, with rougher reflections across the mip chain.
  • It applies to a cube_image2D source, a six image cube, or a .ktx cube source.
  • A six image cube must have square faces to be convolved.
  • Convolved sources are read as float.
  • face_size: size of each output face. 0 uses the default for the type.
  • mip_count: number of radiance mips. :todo: explain what 0 gives.
  • lighting_model: phong, phong_brdf, blinn or blinn_brdf. Default phong_brdf.
  • gloss_scale, gloss_bias: default 10 and 1. :todo: explain.
  • exclude_base: default false. :todo: explain.
  • octahedral: output an octahedral 2D image with a one texel gutter instead of a cube. One mip level.
image = {
cube_image2D = "env/the_sky_is_on_fire_2k.exr"
cube_image2D_shape = "latlong"
format = "rgba16Float"
convolution = {
type = "radiance"
face_size = 512
octahedral = true
}
}
  • An image array (image2DArray) is several 2D images of the same size, as one image with layers.
  • array is a list of source images, one per layer, in order.
  • Every layer must be the same size.
  • Layers are read as 8 bit rgba.
  • A .ktx (KTX version 1) source is used as it is, without decoding.
  • It can hold 1D, 2D, 3D and cube images, arrays of them, and its own mips.
  • format must name the format the .ktx data is already in.
  • A .ktx source with convolution set must be a cube.