drawTransparent
← All Butter documentationParameters
drawTransparent(drawItem: Function)
drawItemA function that describes how to draw an item that has transparency
Drawing with transparency is one of the hardest things to encompass in a 3D system. In order for blending to work correctly on semi-transparent objects, they need to be drawn from the back to the front. You may be used to this concept, called the "painter's algorithm," in 2D mode, but it can be foreign when working in 3D.
The p5.transparency addon creates methods to make this easier to do. In Butter, this addon is loaded by default, so these methods are always available.
The primary tool it provides is the drawTransparent function. Instead of manually figuring out how to draw your items in a back-to-front order (which is extra hard when you consider a 3D rotation effect might be applied to your component!), it orders and draws your items for you. Here's how to use it:
- Translate to where you want to draw your item
- Call
drawTransparent(function() { ... }), passing it a function that will draw your item
Then, it waits until all your items have been queued up to be drawn, it sorts them, and then it executes them in back-to-front order.
Here is an example that makes use of it:
let img
let layers
let spread
async function setup() {
img = await loadImageOrVideo('')
layers = createSlider(1, 100, 50, 1)
spread = createSlider(50, 500, 200, 1)
createCanvas(windowWidth, windowHeight, WEBGL)
}
function draw() {
clear()
orbitControl()
imageMode(CENTER)
for (let i = 0; i < layers.value(); i++) {
const t = 1 - i/layers.value()
push()
translate(0, 0, (t - 0.5) * spread.value())
tint(255, 255 * (5 / (5 + layers.value())))
drawTransparent(() => {
image(
img,
0, 0, width/2, height/2,
0, 0, img.width, img.height,
COVER
)
})
pop()
}
}

If you were to remove the drawTransparent call, it would look like this. Note how from one side it blends correctly, but from the other, the semitransparent items in front incorrectly block the ones behind.
let img
let layers
let spread
async function setup() {
img = await loadImageOrVideo('')
layers = createSlider(1, 100, 50, 1)
spread = createSlider(50, 500, 200, 1)
createCanvas(windowWidth, windowHeight, WEBGL)
}
function draw() {
clear()
orbitControl()
imageMode(CENTER)
for (let i = 0; i < layers.value(); i++) {
const t = 1 - i/layers.value()
push()
translate(0, 0, (t - 0.5) * spread.value())
tint(255, 255 * (5 / (5 + layers.value())))
image(
img,
0, 0, width/2, height/2,
0, 0, img.width, img.height,
COVER
)
pop()
}
}

Here are some usage tips:
- Try not to modify your variables within your
drawTransparentfunction. Since the order they get called will depend on your viewpoint, it may lead to unexpected results. - If you share a resource like a framebuffer that you need to redraw per item, do the redrawing inside the
drawTransparentfunction. Otherwise, the item may not get drawn right after the resource has been updated, and by the time it does get drawn, the resource may have been rewritten already. Updating the resource inside the function ensures that each item will have the right content available to draw with, no matter the order.
Also see drawTwoSided for single items that have internal front and back sides.