Images
Importing an image
Section titled “Importing an image”- Put a source image file anywhere in your project folder!
- On the next build, a
name.image.lxis generated next to it, pointing at it assource. - 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.lxis generated.
image = { source = "image/bee.png" generate_mips = "none" format = "rgba8Unorm"}Shape of an image
Section titled “Shape of an image”- An image asset is a
name.image.lxfile 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,.exrand.ktx. - The source file is not the asset. The
image.lxis the asset, and the source is its input. - One
image.lxproduces one image: a 2D image, a cube, or an array (image2D,imageCube,image2DArray). - A
.ktxsource can also produce 1D and 3D images, and arrays of those.
Import defaults
Section titled “Import defaults”formatcomes from the settingassets.image.format, and isrgba8Unormwhen not set.generate_mipscomes from the settingassets.image.generate_mips, and isnonewhen not set..hdrand.exrsources use the configrender.general.source_formatinstead, and arergba32Floatwhen not set.
Choosing what to build
Section titled “Choosing what to build”- The fields that are set decide what kind of image is built. Only one applies, checked in this order.
packhas entries, or no source of any kind is set: a packed 2D image, see Channel packing.cube_image2Dis set: a cube from one 2D image, see Cube from one image.sourceis set: a 2D image, or whatever a.ktxsource holds.cubeis set: a cube from six images, see Cube from six images.arrayis set: an image array, see Image arrays.
Formats
Section titled “Formats”formatis 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
r8Unormandrg8Unorm, keep that many channels of the source. _srgbformats 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
_srgbformat.
Common formats
Section titled “Common formats”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:
PixelFormatinluxe: render.
Compressed formats
Section titled “Compressed formats”- Block compressed (BCn):
bc1_rgba,bc3_rgba,bc4_r,bc5_rg,bc6h_uf16,bc6h_sf16,bc7_rgba. bc1,bc3andbc7also have_srgbvariants.- 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
bc1andbc3are available, and packed images cannot use BCn at all.
HDR sources
Section titled “HDR sources”- An
.hdror.exrsource is read as float when the format can hold it. - Formats that read float are the float formats,
bc6h_uf16,bc6h_sf16andastc4x4_hdr. - Otherwise the source is converted to 8 bit.
force_ldrreads the source as 8 bit even when the format is float.bc6hhas 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_mipsisnoneorbuild.nonekeeps what the source has. A.pnghas one level, a.ktxcan carry its own mips.buildgenerates the whole chain at build time, down to 1x1.buildonly applies torgba8Unormandrgba8Unorm_srgbfrom a singlesource. Other images keep one level, and a warning is logged.generate_mipmaps_at_loadmarks the image to generate its mips when it is loaded.- :todo: explain when to use
generate_mipmaps_at_loadovergenerate_mips = "build".
Mip filters
Section titled “Mip filters”generate_mips_filterdecides 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_srgbformat 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_cutoutis the alpha thresholdcutoutkeeps 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
Section titled “Channel packing”- 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.
packis a list of entries. Each entry reads channels from one source and writes them to channels of the result.fillis 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
fillvalue.
Pack entries
Section titled “Pack entries”from: the source image file.read: which channels to read from the source, as letters fromrgba. Defaultr.write: which channels of the result to write them to. Defaultr.readandwritemust be the same length, 1 to 4 letters. They pair up in order, soread = "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:linearorsrgb.srgbdecodes the r, g and b channels read from this source to linear. Defaultlinear.
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" } ]}Pack size and formats
Section titled “Pack size and formats”- The result is the size of the largest source.
pack_sizesets a minimum size. A larger source still wins.- Sources smaller than the result are resized to fit, filtered in linear space when
spaceissrgb. - 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.
A solid color
Section titled “A solid color”- An
image.lxwith 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]}Images from other assets
Section titled “Images from other assets”- Some asset types generate images and their
image.lxas part of their own import. - The generated
image.lxis only written when one does not exist, so edits to it are kept.
- A
name.noise.lxbakes a noise field to a.png, or a.ktxvolume forgrid3d. - It writes a
name.image.lxfor the result, using the same import defaults as a dropped image. - For a
.ktxvolume, the format is set to match what was written:r8Unormorrgba8Unorm. - See Noise for the noise fields.
Aseprite
Section titled “Aseprite”- An
.asepriteor.asefile generates aname.aseprite.lxnext to it, withoutput = "atlas". - The
aseprite.lxbuilds frame images, an image asset for them, and anims from the file. outputdecides the frame images:atlas,sheetorloose.atlas: frames packed into one image, with aname.atlas.lxdescribing each frame rect.sheet: frames in uniform cells on one image, in rows.loose: one.pngper frame, in aname.framesfolder.- One
.anim.lxis written per tag in the file, or one for the whole file when there are no tags.
Aseprite settings
Section titled “Aseprite settings”source: the.asepriteor.asefile.max_size: the largest the packed image can be. Default[1024 1024].crop: defaulttrue.- For
atlasonly:layout(rowsorpack),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.
Aseprite import settings
Section titled “Aseprite import settings”asset.aseprite.auto_import: generate theaseprite.lxfor files nothing references yet. Defaulttrue.asset.aseprite.source_reimport: generate it even when the file is referenced. Defaultfalse.- Tag a source file
no_source_reimportto never generate one for it.
Cube maps
Section titled “Cube maps”- 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
.ktxcube.
Cube from one image
Section titled “Cube from one image”cube_image2Dis a single source laid out as a whole cube, like an HDR environment.cube_image2D_shapeis 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_sizeresizes each face.0keeps the size the layout gives.
image = { cube_image2D = "env/the_sky_is_on_fire_2k.exr" cube_image2D_shape = "latlong" format = "rgba16Float"}Cube from six images
Section titled “Cube from six images”cubeis 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.
Environment convolution
Section titled “Environment convolution”- Convolution prefilters a cube for lighting, as irradiance or radiance.
convolutionis an object on theimage.lxwith these fields.type:none,irradianceorradiance.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_image2Dsource, a six imagecube, or a.ktxcubesource. - A six image
cubemust have square faces to be convolved. - Convolved sources are read as float.
Convolution fields
Section titled “Convolution fields”face_size: size of each output face.0uses the default for the type.mip_count: number of radiance mips. :todo: explain what0gives.lighting_model:phong,phong_brdf,blinnorblinn_brdf. Defaultphong_brdf.gloss_scale,gloss_bias: default10and1. :todo: explain.exclude_base: defaultfalse. :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 }}Image arrays
Section titled “Image arrays”- An image array (
image2DArray) is several 2D images of the same size, as one image with layers. arrayis a list of source images, one per layer, in order.- Every layer must be the same size.
- Layers are read as 8 bit rgba.
KTX sources
Section titled “KTX sources”- 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.
formatmust name the format the.ktxdata is already in.- A
.ktxsource withconvolutionset must be a cube.