discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

volumetric color

JB
Jordan Brown
Wed, Dec 24, 2025 1:02 AM

Today's OpenSCAD color processing does face coloring.  It is perfectly
possible to have the six faces of a cube have six different colors, and
if you union two shapes of different colors there's nothing known about
the color of the overlap area.

That scheme is fine, more or less, for visualization, but it doesn't
work well for actual 3D printing where you need to know what color (or
material) the interior of a shape is to be.

What you need is volumetric color, so that there are no overlapping
shapes and you always know what color the interior of a shape is.

I mentioned this need as part of a discussion of color semantics, and
one of the responses was that we didn't know how to do volumetric
color.  I'd done an OpenSCAD demonstration of volumetric color and was
pretty sure that it was straightforward to come up with appropriate
processing, so I said I'd recreate that proof-of-concept for discussion.

And here it is.

Note:  this is not the most efficient possible implementation.  It
re-evaluates the model many times, when it really only needs to be
evaluated once.  There should probably be a few more render()s scattered
around to try to get subtrees to be cached.  But it looks like it works.

Implementations of hull(), minkowski(), et cetera, and of the 2D
operations, left as an exercise for the reader.

Here's the result of this particular model, both in assembled form and
exploded by color:

// Volumetric color proof of concept
// Jordan Brown, openscad@jordan.maileater.net

// There are four relevant modules in this POC:
// col - replacement for color()
// uni - replacement for union()
// dif - replacement for difference()
// int - replacement for intersection()

// In this POC, the list of possible colors needs to be known in advance;
// in a built-in implementation it would either be collected during the
// evaluation phase or managed entirely dynamically.  It would be
// straightforward to build a version of this POC that would be
// driven by an external script that would first run it in a
// "list colors" mode and would then run it once for each color.

// Similarly, in this POC the model is encapsulated in a module main(),
// while in a built-in implementation the final "step through the colors"
// loop would be implied and the model could be at the top level.

// This POC steps through the colors, generating the parts for one color,
// then the next, then the next.  A built-in implementation could do
// that, or could do roughly the same operations across all colors at once.

// The model.  A couple of unions, a difference, and an intersection
// to do a cutaway so that you can see the internal colors.
module main() {
int() {
uni() {
col("green") rotate([90,0,0]) cylinder(h=30, d=5, center=true);
dif() {
uni() {
col("red") cube(10);
col("blue") sphere(10);
}
cylinder(h=30, d=5, center=true);
}
}
rotate(-45) translate([0,-20,-20]) cube([40,40,40]);
}
}

// And now the infrastructure...

// Set the color of the children, like color().
// In this POC, this really operates by skipping anything that
// isn't the desired color, and then coloring during the per-color
// pass at the end, but there are other variations.
module col(c) {
union() {  // work around #6456.
// $color=undef means that we want all colors - in particular,
// for the second-and-later children of dif() and int().
if (is_undef($color) || c == $color) {
children();
}
}
}

// Union the children.
// What this does is to draw the first child, then draw the second child
// less the first child, then the third less the first and second, and
// so on.  Note that the negative components have $color=undef so that
// the entire subassembly, of all colors, gets subtracted out.
module uni() {
for (i=[0:1:$children-1]) {
// Add this child, less the children before it.  Note that
// because of col() processing this might be only part
// of the logical subtree, but that's OK; what's important
// is that we mask it all colors of the previous children.
difference() {
children(i);
children([0:1:i-1], $color=undef);
}
}
}

// Difference the children.
// The only novel thing that this does is to set $color=undef
// for the second-and-later children, so that all colors are
// subtracted away from the first child.  Again, because of
// col() processing the first child might only be a fraction of
// the logical subtree; it'll all get reassembled in the final
// multiple passes.
module dif() {
difference() {
children(0);
children([1:$children-1], $color=undef);
}
}

// Intersect the children.
// Think of this as taking the first child, and subtracting
// parts of it that are not in common with the later children.
// That neatly answers the question of what color the result
// should be, and makes everything consistent:  the first child's
// color wins.
module int() {
intersection_for(i=[0:1:$children-1]) {
if (i == 0) {
children(i);
} else {
$color = undef;
children(i);
}
}
}

// As noted above, this list of colors needs to be
// known in advance; in a built-in implementation (or even
// in a script-driven userspace implementation) this list
// would be dynamically derived.
colors = [ "red", "green", "blue" ];

// Build the model.
for (c = colors) {
$color=c;
color(c) render() main();
}

// Build an exploded set so that you can see
// what the individual colored parts look like.
for (i = [ 0:len(colors)-1 ]) {
c = colors[i];
$color=c;
translate([20+i*20,0,0]) color(c) render() main();
}

Today's OpenSCAD color processing does face coloring.  It is perfectly possible to have the six faces of a cube have six different colors, and if you union two shapes of different colors there's nothing known about the color of the overlap area. That scheme is fine, more or less, for visualization, but it doesn't work well for actual 3D printing where you need to know what color (or material) the interior of a shape is to be. What you need is volumetric color, so that there are no overlapping shapes and you always know what color the interior of a shape is. I mentioned this need as part of a discussion of color semantics, and one of the responses was that we didn't know how to do volumetric color.  I'd done an OpenSCAD demonstration of volumetric color and was pretty sure that it was straightforward to come up with appropriate processing, so I said I'd recreate that proof-of-concept for discussion. And here it is. Note:  this is not the most efficient possible implementation.  It re-evaluates the model many times, when it really only needs to be evaluated once.  There should probably be a few more render()s scattered around to try to get subtrees to be cached.  But it looks like it works. Implementations of hull(), minkowski(), et cetera, and of the 2D operations, left as an exercise for the reader. Here's the result of this particular model, both in assembled form and exploded by color: // Volumetric color proof of concept // Jordan Brown, openscad@jordan.maileater.net // There are four relevant modules in this POC: // col - replacement for color() // uni - replacement for union() // dif - replacement for difference() // int - replacement for intersection() // In this POC, the list of possible colors needs to be known in advance; // in a built-in implementation it would either be collected during the // evaluation phase or managed entirely dynamically. It would be // straightforward to build a version of this POC that would be // driven by an external script that would first run it in a // "list colors" mode and would then run it once for each color. // Similarly, in this POC the model is encapsulated in a module main(), // while in a built-in implementation the final "step through the colors" // loop would be implied and the model could be at the top level. // This POC steps through the colors, generating the parts for one color, // then the next, then the next. A built-in implementation could do // that, or could do roughly the same operations across all colors at once. // The model. A couple of unions, a difference, and an intersection // to do a cutaway so that you can see the internal colors. module main() { int() { uni() { col("green") rotate([90,0,0]) cylinder(h=30, d=5, center=true); dif() { uni() { col("red") cube(10); col("blue") sphere(10); } cylinder(h=30, d=5, center=true); } } rotate(-45) translate([0,-20,-20]) cube([40,40,40]); } } // And now the infrastructure... // Set the color of the children, like color(). // In this POC, this really operates by skipping anything that // isn't the desired color, and then coloring during the per-color // pass at the end, but there are other variations. module col(c) { union() { // work around #6456. // $color=undef means that we want all colors - in particular, // for the second-and-later children of dif() and int(). if (is_undef($color) || c == $color) { children(); } } } // Union the children. // What this does is to draw the first child, then draw the second child // less the first child, then the third less the first and second, and // so on. Note that the negative components have $color=undef so that // the entire subassembly, of all colors, gets subtracted out. module uni() { for (i=[0:1:$children-1]) { // Add this child, less the children before it. Note that // because of col() processing this might be only part // of the logical subtree, but that's OK; what's important // is that we mask it all colors of the previous children. difference() { children(i); children([0:1:i-1], $color=undef); } } } // Difference the children. // The only novel thing that this does is to set $color=undef // for the second-and-later children, so that all colors are // subtracted away from the first child. Again, because of // col() processing the first child might only be a fraction of // the logical subtree; it'll all get reassembled in the final // multiple passes. module dif() { difference() { children(0); children([1:$children-1], $color=undef); } } // Intersect the children. // Think of this as taking the first child, and subtracting // parts of it that are not in common with the later children. // That neatly answers the question of what color the result // should be, and makes everything consistent: the first child's // color wins. module int() { intersection_for(i=[0:1:$children-1]) { if (i == 0) { children(i); } else { $color = undef; children(i); } } } // As noted above, this list of colors needs to be // known in advance; in a built-in implementation (or even // in a script-driven userspace implementation) this list // would be dynamically derived. colors = [ "red", "green", "blue" ]; // Build the model. for (c = colors) { $color=c; color(c) render() main(); } // Build an exploded set so that you can see // what the individual colored parts look like. for (i = [ 0:len(colors)-1 ]) { c = colors[i]; $color=c; translate([20+i*20,0,0]) color(c) render() main(); }
GH
gene heskett
Wed, Dec 24, 2025 1:57 AM

On 12/23/25 20:03, Jordan Brown via Discuss wrote:

Today's OpenSCAD color processing does face coloring.  It is perfectly
possible to have the six faces of a cube have six different colors, and
if you union two shapes of different colors there's nothing known about
the color of the overlap area.

That scheme is fine, more or less, for visualization, but it doesn't
work well for actual 3D printing where you need to know what color (or
material) the interior of a shape is to be.

What you need is volumetric color, so that there are no overlapping
shapes and you always know what color the interior of a shape is.

I mentioned this need as part of a discussion of color semantics, and
one of the responses was that we didn't know how to do volumetric
color.  I'd done an OpenSCAD demonstration of volumetric color and was
pretty sure that it was straightforward to come up with appropriate
processing, so I said I'd recreate that proof-of-concept for discussion.

And here it is.

Note:  this is not the most efficient possible implementation.  It
re-evaluates the model many times, when it really only needs to be
evaluated once.  There should probably be a few more render()s scattered
around to try to get subtrees to be cached.  But it looks like it works.

Very impressive, and raising the priority of building a 3d printer
capable of doing that,
Currently my dream thoughts have leaned more toward switching src spools
of the
same color to make a printer capable of switching src spools to continue
the print
when the current spool runs out.  To that continuous end, or for
multicolor, we'ed need to
establish a protocol we could setup in the slicer, to select which
method we have in
mind.  Selectable by telling the slicer in the g-code pramble, what we
want the printer
to do.  As the src of the code that winds driving the printer, it
behooves us to develop
the method, and attempt to set the industrues std way of doing this.

Otherwise we are left with everybody going off in their own direction,
diluting the
transition because every kit we might buy to build a printer, ideally
capable of
doing either according to the job at hand, and no ones product is compatible
with any other vendors hardware. That is the road block preventing me from
buying a box turtle, or any other solution.  And because of this, not
one is offering
a complete, bolt it on, load it with spools of plastic and Just Run
solution.

So please, develop a std and break a few arms getting it accepted on an
industry
wide basis because it in the end, the inter-compatibility makes sense.

Now 91 yo & running out of time, its beyond my pay grade, but the
present situation
makes no sense at all.  It is a huge road block to progress.

Thank you and Merry Christmas everybody.

Implementations of hull(), minkowski(), et cetera, and of the 2D
operations, left as an exercise for the reader.

Here's the result of this particular model, both in assembled form and
exploded by color:

// Volumetric color proof of concept
// Jordan Brown, openscad@jordan.maileater.net

// There are four relevant modules in this POC:
// col - replacement for color()
// uni - replacement for union()
// dif - replacement for difference()
// int - replacement for intersection()

// In this POC, the list of possible colors needs to be known in advance;
// in a built-in implementation it would either be collected during the
// evaluation phase or managed entirely dynamically.  It would be
// straightforward to build a version of this POC that would be
// driven by an external script that would first run it in a
// "list colors" mode and would then run it once for each color.

// Similarly, in this POC the model is encapsulated in a module main(),
// while in a built-in implementation the final "step through the colors"
// loop would be implied and the model could be at the top level.

// This POC steps through the colors, generating the parts for one color,
// then the next, then the next.  A built-in implementation could do
// that, or could do roughly the same operations across all colors at once.

// The model.  A couple of unions, a difference, and an intersection
// to do a cutaway so that you can see the internal colors.
module main() {
int() {
uni() {
col("green") rotate([90,0,0]) cylinder(h=30, d=5, center=true);
dif() {
uni() {
col("red") cube(10);
col("blue") sphere(10);
}
cylinder(h=30, d=5, center=true);
}
}
rotate(-45) translate([0,-20,-20]) cube([40,40,40]);
}
}

// And now the infrastructure...

// Set the color of the children, like color().
// In this POC, this really operates by skipping anything that
// isn't the desired color, and then coloring during the per-color
// pass at the end, but there are other variations.
module col(c) {
union() {  // work around #6456.
// $color=undef means that we want all colors - in particular,
// for the second-and-later children of dif() and int().
if (is_undef($color) || c == $color) {
children();
}
}
}

// Union the children.
// What this does is to draw the first child, then draw the second child
// less the first child, then the third less the first and second, and
// so on.  Note that the negative components have $color=undef so that
// the entire subassembly, of all colors, gets subtracted out.
module uni() {
for (i=[0:1:$children-1]) {
// Add this child, less the children before it.  Note that
// because of col() processing this might be only part
// of the logical subtree, but that's OK; what's important
// is that we mask it all colors of the previous children.
difference() {
children(i);
children([0:1:i-1], $color=undef);
}
}
}

// Difference the children.
// The only novel thing that this does is to set $color=undef
// for the second-and-later children, so that all colors are
// subtracted away from the first child.  Again, because of
// col() processing the first child might only be a fraction of
// the logical subtree; it'll all get reassembled in the final
// multiple passes.
module dif() {
difference() {
children(0);
children([1:$children-1], $color=undef);
}
}

// Intersect the children.
// Think of this as taking the first child, and subtracting
// parts of it that are not in common with the later children.
// That neatly answers the question of what color the result
// should be, and makes everything consistent:  the first child's
// color wins.
module int() {
intersection_for(i=[0:1:$children-1]) {
if (i == 0) {
children(i);
} else {
$color = undef;
children(i);
}
}
}

// As noted above, this list of colors needs to be
// known in advance; in a built-in implementation (or even
// in a script-driven userspace implementation) this list
// would be dynamically derived.
colors = [ "red", "green", "blue" ];

// Build the model.
for (c = colors) {
$color=c;
color(c) render() main();
}

// Build an exploded set so that you can see
// what the individual colored parts look like.
for (i = [ 0:len(colors)-1 ]) {
c = colors[i];
$color=c;
translate([20+i*20,0,0]) color(c) render() main();
}


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Cheers, Gene Heskett, CET.

"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.

  • Louis D. Brandeis
    Don't poison our oceans, interdict drugs at the src.
On 12/23/25 20:03, Jordan Brown via Discuss wrote: > Today's OpenSCAD color processing does face coloring.  It is perfectly > possible to have the six faces of a cube have six different colors, and > if you union two shapes of different colors there's nothing known about > the color of the overlap area. > > That scheme is fine, more or less, for visualization, but it doesn't > work well for actual 3D printing where you need to know what color (or > material) the interior of a shape is to be. > > What you need is volumetric color, so that there are no overlapping > shapes and you always know what color the interior of a shape is. > > I mentioned this need as part of a discussion of color semantics, and > one of the responses was that we didn't know how to do volumetric > color.  I'd done an OpenSCAD demonstration of volumetric color and was > pretty sure that it was straightforward to come up with appropriate > processing, so I said I'd recreate that proof-of-concept for discussion. > > And here it is. > > Note:  this is not the most efficient possible implementation.  It > re-evaluates the model many times, when it really only needs to be > evaluated once.  There should probably be a few more render()s scattered > around to try to get subtrees to be cached.  But it looks like it works. Very impressive, and raising the priority of building a 3d printer capable of doing that, Currently my dream thoughts have leaned more toward switching src spools of the same color to make a printer capable of switching src spools to continue the print when the current spool runs out.  To that continuous end, or for multicolor, we'ed need to establish a protocol we could setup in the slicer, to select which method we have in mind.  Selectable by telling the slicer in the g-code pramble, what we want the printer to do.  As the src of the code that winds driving the printer, it behooves us to develop the method, and attempt to set the industrues std way of doing this. Otherwise we are left with everybody going off in their own direction, diluting the transition because every kit we might buy to build a printer, ideally capable of doing either according to the job at hand, and no ones product is compatible with any other vendors hardware. That is the road block preventing me from buying a box turtle, or any other solution.  And because of this, not one is offering a complete, bolt it on, load it with spools of plastic and Just Run solution. So please, develop a std and break a few arms getting it accepted on an industry wide basis because it in the end, the inter-compatibility makes sense. Now 91 yo & running out of time, its beyond my pay grade, but the present situation makes no sense at all.  It is a huge road block to progress. Thank you and Merry Christmas everybody. > > Implementations of hull(), minkowski(), et cetera, and of the 2D > operations, left as an exercise for the reader. > > Here's the result of this particular model, both in assembled form and > exploded by color: > > > > // Volumetric color proof of concept > // Jordan Brown, openscad@jordan.maileater.net > > // There are four relevant modules in this POC: > // col - replacement for color() > // uni - replacement for union() > // dif - replacement for difference() > // int - replacement for intersection() > > // In this POC, the list of possible colors needs to be known in advance; > // in a built-in implementation it would either be collected during the > // evaluation phase or managed entirely dynamically. It would be > // straightforward to build a version of this POC that would be > // driven by an external script that would first run it in a > // "list colors" mode and would then run it once for each color. > > // Similarly, in this POC the model is encapsulated in a module main(), > // while in a built-in implementation the final "step through the colors" > // loop would be implied and the model could be at the top level. > > // This POC steps through the colors, generating the parts for one color, > // then the next, then the next. A built-in implementation could do > // that, or could do roughly the same operations across all colors at once. > > // The model. A couple of unions, a difference, and an intersection > // to do a cutaway so that you can see the internal colors. > module main() { > int() { > uni() { > col("green") rotate([90,0,0]) cylinder(h=30, d=5, center=true); > dif() { > uni() { > col("red") cube(10); > col("blue") sphere(10); > } > cylinder(h=30, d=5, center=true); > } > } > rotate(-45) translate([0,-20,-20]) cube([40,40,40]); > } > } > > // And now the infrastructure... > > // Set the color of the children, like color(). > // In this POC, this really operates by skipping anything that > // isn't the desired color, and then coloring during the per-color > // pass at the end, but there are other variations. > module col(c) { > union() { // work around #6456. > // $color=undef means that we want all colors - in particular, > // for the second-and-later children of dif() and int(). > if (is_undef($color) || c == $color) { > children(); > } > } > } > > // Union the children. > // What this does is to draw the first child, then draw the second child > // less the first child, then the third less the first and second, and > // so on. Note that the negative components have $color=undef so that > // the entire subassembly, of all colors, gets subtracted out. > module uni() { > for (i=[0:1:$children-1]) { > // Add this child, less the children before it. Note that > // because of col() processing this might be only part > // of the logical subtree, but that's OK; what's important > // is that we mask it all colors of the previous children. > difference() { > children(i); > children([0:1:i-1], $color=undef); > } > } > } > > // Difference the children. > // The only novel thing that this does is to set $color=undef > // for the second-and-later children, so that all colors are > // subtracted away from the first child. Again, because of > // col() processing the first child might only be a fraction of > // the logical subtree; it'll all get reassembled in the final > // multiple passes. > module dif() { > difference() { > children(0); > children([1:$children-1], $color=undef); > } > } > > // Intersect the children. > // Think of this as taking the first child, and subtracting > // parts of it that are not in common with the later children. > // That neatly answers the question of what color the result > // should be, and makes everything consistent: the first child's > // color wins. > module int() { > intersection_for(i=[0:1:$children-1]) { > if (i == 0) { > children(i); > } else { > $color = undef; > children(i); > } > } > } > > // As noted above, this list of colors needs to be > // known in advance; in a built-in implementation (or even > // in a script-driven userspace implementation) this list > // would be dynamically derived. > colors = [ "red", "green", "blue" ]; > > // Build the model. > for (c = colors) { > $color=c; > color(c) render() main(); > } > > // Build an exploded set so that you can see > // what the individual colored parts look like. > for (i = [ 0:len(colors)-1 ]) { > c = colors[i]; > $color=c; > translate([20+i*20,0,0]) color(c) render() main(); > } > > > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org Cheers, Gene Heskett, CET. -- "There are four boxes to be used in defense of liberty: soap, ballot, jury, and ammo. Please use in that order." -Ed Howdershelt (Author, 1940) If we desire respect for the law, we must first make the law respectable. - Louis D. Brandeis Don't poison our oceans, interdict drugs at the src.
JB
Jon Bondy
Wed, Dec 24, 2025 2:36 AM

Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene?

I think the standards for slicing have been out there for quite a while.

Jon

On 12/23/2025 8:57 PM, gene heskett via Discuss wrote:

On 12/23/25 20:03, Jordan Brown via Discuss wrote:

Today's OpenSCAD color processing does face coloring.  It is perfectly
possible to have the six faces of a cube have six different colors, and
if you union two shapes of different colors there's nothing known about
the color of the overlap area.

That scheme is fine, more or less, for visualization, but it doesn't
work well for actual 3D printing where you need to know what color (or
material) the interior of a shape is to be.

What you need is volumetric color, so that there are no overlapping
shapes and you always know what color the interior of a shape is.

I mentioned this need as part of a discussion of color semantics, and
one of the responses was that we didn't know how to do volumetric
color.  I'd done an OpenSCAD demonstration of volumetric color and was
pretty sure that it was straightforward to come up with appropriate
processing, so I said I'd recreate that proof-of-concept for discussion.

And here it is.

Note:  this is not the most efficient possible implementation. It
re-evaluates the model many times, when it really only needs to be
evaluated once.  There should probably be a few more render()s scattered
around to try to get subtrees to be cached.  But it looks like it works.

Very impressive, and raising the priority of building a 3d printer
capable of doing that,
Currently my dream thoughts have leaned more toward switching src
spools of the
same color to make a printer capable of switching src spools to
continue the print
when the current spool runs out.  To that continuous end, or for
multicolor, we'ed need to
establish a protocol we could setup in the slicer, to select which
method we have in
mind.  Selectable by telling the slicer in the g-code pramble, what we
want the printer
to do.  As the src of the code that winds driving the printer, it
behooves us to develop
the method, and attempt to set the industrues std way of doing this.

Otherwise we are left with everybody going off in their own direction,
diluting the
transition because every kit we might buy to build a printer, ideally
capable of
doing either according to the job at hand, and no ones product is
compatible
with any other vendors hardware. That is the road block preventing me
from
buying a box turtle, or any other solution.  And because of this, not
one is offering
a complete, bolt it on, load it with spools of plastic and Just Run
solution.

So please, develop a std and break a few arms getting it accepted on
an industry
wide basis because it in the end, the inter-compatibility makes sense.

Now 91 yo & running out of time, its beyond my pay grade, but the
present situation
makes no sense at all.  It is a huge road block to progress.

Thank you and Merry Christmas everybody.

Implementations of hull(), minkowski(), et cetera, and of the 2D
operations, left as an exercise for the reader.

Here's the result of this particular model, both in assembled form and
exploded by color:

// Volumetric color proof of concept
// Jordan Brown, openscad@jordan.maileater.net

// There are four relevant modules in this POC:
// col - replacement for color()
// uni - replacement for union()
// dif - replacement for difference()
// int - replacement for intersection()

// In this POC, the list of possible colors needs to be known in
advance;
// in a built-in implementation it would either be collected during the
// evaluation phase or managed entirely dynamically.  It would be
// straightforward to build a version of this POC that would be
// driven by an external script that would first run it in a
// "list colors" mode and would then run it once for each color.

// Similarly, in this POC the model is encapsulated in a module main(),
// while in a built-in implementation the final "step through the
colors"
// loop would be implied and the model could be at the top level.

// This POC steps through the colors, generating the parts for one
color,
// then the next, then the next.  A built-in implementation could do
// that, or could do roughly the same operations across all colors at
once.

// The model.  A couple of unions, a difference, and an intersection
// to do a cutaway so that you can see the internal colors.
module main() {
     int() {
         uni() {
             col("green") rotate([90,0,0]) cylinder(h=30, d=5,
center=true);
             dif() {
                 uni() {
                     col("red") cube(10);
                     col("blue") sphere(10);
                 }
                 cylinder(h=30, d=5, center=true);
             }
         }
         rotate(-45) translate([0,-20,-20]) cube([40,40,40]);
     }
}

// And now the infrastructure...

// Set the color of the children, like color().
// In this POC, this really operates by skipping anything that
// isn't the desired color, and then coloring during the per-color
// pass at the end, but there are other variations.
module col(c) {
     union() {   // work around #6456.
         // $color=undef means that we want all colors - in particular,
         // for the second-and-later children of dif() and int().
         if (is_undef($color) || c == $color) {
             children();
         }
     }
}

// Union the children.
// What this does is to draw the first child, then draw the second child
// less the first child, then the third less the first and second, and
// so on.  Note that the negative components have $color=undef so that
// the entire subassembly, of all colors, gets subtracted out.
module uni() {
     for (i=[0:1:$children-1]) {
         // Add this child, less the children before it.  Note that
         // because of col() processing this might be only part
         // of the logical subtree, but that's OK; what's important
         // is that we mask it all colors of the previous children.
         difference() {
             children(i);
             children([0:1:i-1], $color=undef);
         }
     }
}

// Difference the children.
// The only novel thing that this does is to set $color=undef
// for the second-and-later children, so that all colors are
// subtracted away from the first child.  Again, because of
// col() processing the first child might only be a fraction of
// the logical subtree; it'll all get reassembled in the final
// multiple passes.
module dif() {
     difference() {
         children(0);
         children([1:$children-1], $color=undef);
     }
}

// Intersect the children.
// Think of this as taking the first child, and subtracting
// parts of it that are not in common with the later children.
// That neatly answers the question of what color the result
// should be, and makes everything consistent:  the first child's
// color wins.
module int() {
     intersection_for(i=[0:1:$children-1]) {
         if (i == 0) {
             children(i);
         } else {
             $color = undef;
             children(i);
         }
     }
}

// As noted above, this list of colors needs to be
// known in advance; in a built-in implementation (or even
// in a script-driven userspace implementation) this list
// would be dynamically derived.
colors = [ "red", "green", "blue" ];

// Build the model.
for (c = colors) {
     $color=c;
     color(c) render() main();
}

// Build an exploded set so that you can see
// what the individual colored parts look like.
for (i = [ 0:len(colors)-1 ]) {
     c = colors[i];
     $color=c;
     translate([20+i*20,0,0]) color(c) render() main();
}


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Cheers, Gene Heskett, CET.

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene? I think the standards for slicing have been out there for quite a while. Jon On 12/23/2025 8:57 PM, gene heskett via Discuss wrote: > On 12/23/25 20:03, Jordan Brown via Discuss wrote: >> Today's OpenSCAD color processing does face coloring.  It is perfectly >> possible to have the six faces of a cube have six different colors, and >> if you union two shapes of different colors there's nothing known about >> the color of the overlap area. >> >> That scheme is fine, more or less, for visualization, but it doesn't >> work well for actual 3D printing where you need to know what color (or >> material) the interior of a shape is to be. >> >> What you need is volumetric color, so that there are no overlapping >> shapes and you always know what color the interior of a shape is. >> >> I mentioned this need as part of a discussion of color semantics, and >> one of the responses was that we didn't know how to do volumetric >> color.  I'd done an OpenSCAD demonstration of volumetric color and was >> pretty sure that it was straightforward to come up with appropriate >> processing, so I said I'd recreate that proof-of-concept for discussion. >> >> And here it is. >> >> Note:  this is not the most efficient possible implementation. It >> re-evaluates the model many times, when it really only needs to be >> evaluated once.  There should probably be a few more render()s scattered >> around to try to get subtrees to be cached.  But it looks like it works. > Very impressive, and raising the priority of building a 3d printer > capable of doing that, > Currently my dream thoughts have leaned more toward switching src > spools of the > same color to make a printer capable of switching src spools to > continue the print > when the current spool runs out.  To that continuous end, or for > multicolor, we'ed need to > establish a protocol we could setup in the slicer, to select which > method we have in > mind.  Selectable by telling the slicer in the g-code pramble, what we > want the printer > to do.  As the src of the code that winds driving the printer, it > behooves us to develop > the method, and attempt to set the industrues std way of doing this. > > Otherwise we are left with everybody going off in their own direction, > diluting the > transition because every kit we might buy to build a printer, ideally > capable of > doing either according to the job at hand, and no ones product is > compatible > with any other vendors hardware. That is the road block preventing me > from > buying a box turtle, or any other solution.  And because of this, not > one is offering > a complete, bolt it on, load it with spools of plastic and Just Run > solution. > > So please, develop a std and break a few arms getting it accepted on > an industry > wide basis because it in the end, the inter-compatibility makes sense. > > Now 91 yo & running out of time, its beyond my pay grade, but the > present situation > makes no sense at all.  It is a huge road block to progress. > > Thank you and Merry Christmas everybody. >> >> Implementations of hull(), minkowski(), et cetera, and of the 2D >> operations, left as an exercise for the reader. >> >> Here's the result of this particular model, both in assembled form and >> exploded by color: >> >> >> >> // Volumetric color proof of concept >> // Jordan Brown, openscad@jordan.maileater.net >> >> // There are four relevant modules in this POC: >> // col - replacement for color() >> // uni - replacement for union() >> // dif - replacement for difference() >> // int - replacement for intersection() >> >> // In this POC, the list of possible colors needs to be known in >> advance; >> // in a built-in implementation it would either be collected during the >> // evaluation phase or managed entirely dynamically.  It would be >> // straightforward to build a version of this POC that would be >> // driven by an external script that would first run it in a >> // "list colors" mode and would then run it once for each color. >> >> // Similarly, in this POC the model is encapsulated in a module main(), >> // while in a built-in implementation the final "step through the >> colors" >> // loop would be implied and the model could be at the top level. >> >> // This POC steps through the colors, generating the parts for one >> color, >> // then the next, then the next.  A built-in implementation could do >> // that, or could do roughly the same operations across all colors at >> once. >> >> // The model.  A couple of unions, a difference, and an intersection >> // to do a cutaway so that you can see the internal colors. >> module main() { >>      int() { >>          uni() { >>              col("green") rotate([90,0,0]) cylinder(h=30, d=5, >> center=true); >>              dif() { >>                  uni() { >>                      col("red") cube(10); >>                      col("blue") sphere(10); >>                  } >>                  cylinder(h=30, d=5, center=true); >>              } >>          } >>          rotate(-45) translate([0,-20,-20]) cube([40,40,40]); >>      } >> } >> >> // And now the infrastructure... >> >> // Set the color of the children, like color(). >> // In this POC, this really operates by skipping anything that >> // isn't the desired color, and then coloring during the per-color >> // pass at the end, but there are other variations. >> module col(c) { >>      union() {   // work around #6456. >>          // $color=undef means that we want all colors - in particular, >>          // for the second-and-later children of dif() and int(). >>          if (is_undef($color) || c == $color) { >>              children(); >>          } >>      } >> } >> >> // Union the children. >> // What this does is to draw the first child, then draw the second child >> // less the first child, then the third less the first and second, and >> // so on.  Note that the negative components have $color=undef so that >> // the entire subassembly, of all colors, gets subtracted out. >> module uni() { >>      for (i=[0:1:$children-1]) { >>          // Add this child, less the children before it.  Note that >>          // because of col() processing this might be only part >>          // of the logical subtree, but that's OK; what's important >>          // is that we mask it all colors of the previous children. >>          difference() { >>              children(i); >>              children([0:1:i-1], $color=undef); >>          } >>      } >> } >> >> // Difference the children. >> // The only novel thing that this does is to set $color=undef >> // for the second-and-later children, so that all colors are >> // subtracted away from the first child.  Again, because of >> // col() processing the first child might only be a fraction of >> // the logical subtree; it'll all get reassembled in the final >> // multiple passes. >> module dif() { >>      difference() { >>          children(0); >>          children([1:$children-1], $color=undef); >>      } >> } >> >> // Intersect the children. >> // Think of this as taking the first child, and subtracting >> // parts of it that are not in common with the later children. >> // That neatly answers the question of what color the result >> // should be, and makes everything consistent:  the first child's >> // color wins. >> module int() { >>      intersection_for(i=[0:1:$children-1]) { >>          if (i == 0) { >>              children(i); >>          } else { >>              $color = undef; >>              children(i); >>          } >>      } >> } >> >> // As noted above, this list of colors needs to be >> // known in advance; in a built-in implementation (or even >> // in a script-driven userspace implementation) this list >> // would be dynamically derived. >> colors = [ "red", "green", "blue" ]; >> >> // Build the model. >> for (c = colors) { >>      $color=c; >>      color(c) render() main(); >> } >> >> // Build an exploded set so that you can see >> // what the individual colored parts look like. >> for (i = [ 0:len(colors)-1 ]) { >>      c = colors[i]; >>      $color=c; >>      translate([20+i*20,0,0]) color(c) render() main(); >> } >> >> >> >> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org > > Cheers, Gene Heskett, CET. -- This email has been checked for viruses by AVG antivirus software. www.avg.com
CC
Cory Cross
Wed, Dec 24, 2025 3:07 AM

How do you think this improves on colorscad?

You made a number of choices regarding what
union/difference/intersection mean, but are those useful and efficient
in creating actual shapes versus i.e. BOSL2's coloring?

How do you think this improves on colorscad? You made a number of choices regarding what union/difference/intersection mean, but are those useful and efficient in creating actual shapes versus i.e. BOSL2's coloring?
LD
lee.deraud@roadrunner.com
Wed, Dec 24, 2025 3:35 AM

The whole "just do it in python" thing seems to be turning into a meme. 😊

There appear to be multiple approaches to extending OS with python...

Any suggestions for where best to start, assuming  someone (1) decently familiar with OS,

(2) relative beginner with python, and (3) working in a Windows environment (if that matters)?

The whole "just do it in python" thing seems to be turning into a meme. 😊 There appear to be multiple approaches to extending OS with python... Any suggestions for where best to start, assuming someone (1) decently familiar with OS, (2) relative beginner with python, and (3) working in a Windows environment (if that matters)?
GH
gene heskett
Wed, Dec 24, 2025 5:55 AM

Currently prusasliccer 2.8.1's AppImage, later are flatpacks which won't
run on my bookworm.

On 12/23/25 21:36, Jon Bondy wrote:

Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene?

yes, no-no privacy, and no. Cura for a while. prusa has more knobs.

I think the standards for slicing have been out there for quite a while.

But not for multi-color.

Jon

Merry Christmas, Jon.

On 12/23/2025 8:57 PM, gene heskett via Discuss wrote:

On 12/23/25 20:03, Jordan Brown via Discuss wrote:

Today's OpenSCAD color processing does face coloring.  It is perfectly
possible to have the six faces of a cube have six different colors, and
if you union two shapes of different colors there's nothing known about
the color of the overlap area.

That scheme is fine, more or less, for visualization, but it doesn't
work well for actual 3D printing where you need to know what color (or
material) the interior of a shape is to be.

What you need is volumetric color, so that there are no overlapping
shapes and you always know what color the interior of a shape is.

I mentioned this need as part of a discussion of color semantics, and
one of the responses was that we didn't know how to do volumetric
color.  I'd done an OpenSCAD demonstration of volumetric color and was
pretty sure that it was straightforward to come up with appropriate
processing, so I said I'd recreate that proof-of-concept for
discussion.

And here it is.

Note:  this is not the most efficient possible implementation. It
re-evaluates the model many times, when it really only needs to be
evaluated once.  There should probably be a few more render()s
scattered
around to try to get subtrees to be cached.  But it looks like it
works.

Very impressive, and raising the priority of building a 3d printer
capable of doing that,
Currently my dream thoughts have leaned more toward switching src
spools of the
same color to make a printer capable of switching src spools to
continue the print
when the current spool runs out.  To that continuous end, or for
multicolor, we'ed need to
establish a protocol we could setup in the slicer, to select which
method we have in
mind.  Selectable by telling the slicer in the g-code pramble, what
we want the printer
to do.  As the src of the code that winds driving the printer, it
behooves us to develop
the method, and attempt to set the industrues std way of doing this.

Otherwise we are left with everybody going off in their own
direction, diluting the
transition because every kit we might buy to build a printer, ideally
capable of
doing either according to the job at hand, and no ones product is
compatible
with any other vendors hardware. That is the road block preventing me
from
buying a box turtle, or any other solution.  And because of this, not
one is offering
a complete, bolt it on, load it with spools of plastic and Just Run
solution.

So please, develop a std and break a few arms getting it accepted on
an industry
wide basis because it in the end, the inter-compatibility makes sense.

Now 91 yo & running out of time, its beyond my pay grade, but the
present situation
makes no sense at all.  It is a huge road block to progress.

Thank you and Merry Christmas everybody.

Implementations of hull(), minkowski(), et cetera, and of the 2D
operations, left as an exercise for the reader.

Here's the result of this particular model, both in assembled form and
exploded by color:

// Volumetric color proof of concept
// Jordan Brown, openscad@jordan.maileater.net

// There are four relevant modules in this POC:
// col - replacement for color()
// uni - replacement for union()
// dif - replacement for difference()
// int - replacement for intersection()

// In this POC, the list of possible colors needs to be known in
advance;
// in a built-in implementation it would either be collected during the
// evaluation phase or managed entirely dynamically.  It would be
// straightforward to build a version of this POC that would be
// driven by an external script that would first run it in a
// "list colors" mode and would then run it once for each color.

// Similarly, in this POC the model is encapsulated in a module main(),
// while in a built-in implementation the final "step through the
colors"
// loop would be implied and the model could be at the top level.

// This POC steps through the colors, generating the parts for one
color,
// then the next, then the next.  A built-in implementation could do
// that, or could do roughly the same operations across all colors
at once.

// The model.  A couple of unions, a difference, and an intersection
// to do a cutaway so that you can see the internal colors.
module main() {
     int() {
         uni() {
             col("green") rotate([90,0,0]) cylinder(h=30, d=5,
center=true);
             dif() {
                 uni() {
                     col("red") cube(10);
                     col("blue") sphere(10);
                 }
                 cylinder(h=30, d=5, center=true);
             }
         }
         rotate(-45) translate([0,-20,-20]) cube([40,40,40]);
     }
}

// And now the infrastructure...

// Set the color of the children, like color().
// In this POC, this really operates by skipping anything that
// isn't the desired color, and then coloring during the per-color
// pass at the end, but there are other variations.
module col(c) {
     union() {   // work around #6456.
         // $color=undef means that we want all colors - in particular,
         // for the second-and-later children of dif() and int().
         if (is_undef($color) || c == $color) {
             children();
         }
     }
}

// Union the children.
// What this does is to draw the first child, then draw the second
child
// less the first child, then the third less the first and second, and
// so on.  Note that the negative components have $color=undef so that
// the entire subassembly, of all colors, gets subtracted out.
module uni() {
     for (i=[0:1:$children-1]) {
         // Add this child, less the children before it.  Note that
         // because of col() processing this might be only part
         // of the logical subtree, but that's OK; what's important
         // is that we mask it all colors of the previous children.
         difference() {
             children(i);
             children([0:1:i-1], $color=undef);
         }
     }
}

// Difference the children.
// The only novel thing that this does is to set $color=undef
// for the second-and-later children, so that all colors are
// subtracted away from the first child.  Again, because of
// col() processing the first child might only be a fraction of
// the logical subtree; it'll all get reassembled in the final
// multiple passes.
module dif() {
     difference() {
         children(0);
         children([1:$children-1], $color=undef);
     }
}

// Intersect the children.
// Think of this as taking the first child, and subtracting
// parts of it that are not in common with the later children.
// That neatly answers the question of what color the result
// should be, and makes everything consistent:  the first child's
// color wins.
module int() {
     intersection_for(i=[0:1:$children-1]) {
         if (i == 0) {
             children(i);
         } else {
             $color = undef;
             children(i);
         }
     }
}

// As noted above, this list of colors needs to be
// known in advance; in a built-in implementation (or even
// in a script-driven userspace implementation) this list
// would be dynamically derived.
colors = [ "red", "green", "blue" ];

// Build the model.
for (c = colors) {
     $color=c;
     color(c) render() main();
}

// Build an exploded set so that you can see
// what the individual colored parts look like.
for (i = [ 0:len(colors)-1 ]) {
     c = colors[i];
     $color=c;
     translate([20+i*20,0,0]) color(c) render() main();
}


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Cheers, Gene Heskett, CET.

Cheers, Gene Heskett, CET.

"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.

  • Louis D. Brandeis
    Don't poison our oceans, interdict drugs at the src.
Currently prusasliccer 2.8.1's AppImage, later are flatpacks which won't run on my bookworm. On 12/23/25 21:36, Jon Bondy wrote: > Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene? yes, no-no privacy, and no. Cura for a while. prusa has more knobs. > > I think the standards for slicing have been out there for quite a while. But not for multi-color. > > > Jon > Merry Christmas, Jon. > > On 12/23/2025 8:57 PM, gene heskett via Discuss wrote: >> On 12/23/25 20:03, Jordan Brown via Discuss wrote: >>> Today's OpenSCAD color processing does face coloring.  It is perfectly >>> possible to have the six faces of a cube have six different colors, and >>> if you union two shapes of different colors there's nothing known about >>> the color of the overlap area. >>> >>> That scheme is fine, more or less, for visualization, but it doesn't >>> work well for actual 3D printing where you need to know what color (or >>> material) the interior of a shape is to be. >>> >>> What you need is volumetric color, so that there are no overlapping >>> shapes and you always know what color the interior of a shape is. >>> >>> I mentioned this need as part of a discussion of color semantics, and >>> one of the responses was that we didn't know how to do volumetric >>> color.  I'd done an OpenSCAD demonstration of volumetric color and was >>> pretty sure that it was straightforward to come up with appropriate >>> processing, so I said I'd recreate that proof-of-concept for >>> discussion. >>> >>> And here it is. >>> >>> Note:  this is not the most efficient possible implementation. It >>> re-evaluates the model many times, when it really only needs to be >>> evaluated once.  There should probably be a few more render()s >>> scattered >>> around to try to get subtrees to be cached.  But it looks like it >>> works. >> Very impressive, and raising the priority of building a 3d printer >> capable of doing that, >> Currently my dream thoughts have leaned more toward switching src >> spools of the >> same color to make a printer capable of switching src spools to >> continue the print >> when the current spool runs out.  To that continuous end, or for >> multicolor, we'ed need to >> establish a protocol we could setup in the slicer, to select which >> method we have in >> mind.  Selectable by telling the slicer in the g-code pramble, what >> we want the printer >> to do.  As the src of the code that winds driving the printer, it >> behooves us to develop >> the method, and attempt to set the industrues std way of doing this. >> >> Otherwise we are left with everybody going off in their own >> direction, diluting the >> transition because every kit we might buy to build a printer, ideally >> capable of >> doing either according to the job at hand, and no ones product is >> compatible >> with any other vendors hardware. That is the road block preventing me >> from >> buying a box turtle, or any other solution.  And because of this, not >> one is offering >> a complete, bolt it on, load it with spools of plastic and Just Run >> solution. >> >> So please, develop a std and break a few arms getting it accepted on >> an industry >> wide basis because it in the end, the inter-compatibility makes sense. >> >> Now 91 yo & running out of time, its beyond my pay grade, but the >> present situation >> makes no sense at all.  It is a huge road block to progress. >> >> Thank you and Merry Christmas everybody. >>> >>> Implementations of hull(), minkowski(), et cetera, and of the 2D >>> operations, left as an exercise for the reader. >>> >>> Here's the result of this particular model, both in assembled form and >>> exploded by color: >>> >>> >>> >>> // Volumetric color proof of concept >>> // Jordan Brown, openscad@jordan.maileater.net >>> >>> // There are four relevant modules in this POC: >>> // col - replacement for color() >>> // uni - replacement for union() >>> // dif - replacement for difference() >>> // int - replacement for intersection() >>> >>> // In this POC, the list of possible colors needs to be known in >>> advance; >>> // in a built-in implementation it would either be collected during the >>> // evaluation phase or managed entirely dynamically.  It would be >>> // straightforward to build a version of this POC that would be >>> // driven by an external script that would first run it in a >>> // "list colors" mode and would then run it once for each color. >>> >>> // Similarly, in this POC the model is encapsulated in a module main(), >>> // while in a built-in implementation the final "step through the >>> colors" >>> // loop would be implied and the model could be at the top level. >>> >>> // This POC steps through the colors, generating the parts for one >>> color, >>> // then the next, then the next.  A built-in implementation could do >>> // that, or could do roughly the same operations across all colors >>> at once. >>> >>> // The model.  A couple of unions, a difference, and an intersection >>> // to do a cutaway so that you can see the internal colors. >>> module main() { >>>      int() { >>>          uni() { >>>              col("green") rotate([90,0,0]) cylinder(h=30, d=5, >>> center=true); >>>              dif() { >>>                  uni() { >>>                      col("red") cube(10); >>>                      col("blue") sphere(10); >>>                  } >>>                  cylinder(h=30, d=5, center=true); >>>              } >>>          } >>>          rotate(-45) translate([0,-20,-20]) cube([40,40,40]); >>>      } >>> } >>> >>> // And now the infrastructure... >>> >>> // Set the color of the children, like color(). >>> // In this POC, this really operates by skipping anything that >>> // isn't the desired color, and then coloring during the per-color >>> // pass at the end, but there are other variations. >>> module col(c) { >>>      union() {   // work around #6456. >>>          // $color=undef means that we want all colors - in particular, >>>          // for the second-and-later children of dif() and int(). >>>          if (is_undef($color) || c == $color) { >>>              children(); >>>          } >>>      } >>> } >>> >>> // Union the children. >>> // What this does is to draw the first child, then draw the second >>> child >>> // less the first child, then the third less the first and second, and >>> // so on.  Note that the negative components have $color=undef so that >>> // the entire subassembly, of all colors, gets subtracted out. >>> module uni() { >>>      for (i=[0:1:$children-1]) { >>>          // Add this child, less the children before it.  Note that >>>          // because of col() processing this might be only part >>>          // of the logical subtree, but that's OK; what's important >>>          // is that we mask it all colors of the previous children. >>>          difference() { >>>              children(i); >>>              children([0:1:i-1], $color=undef); >>>          } >>>      } >>> } >>> >>> // Difference the children. >>> // The only novel thing that this does is to set $color=undef >>> // for the second-and-later children, so that all colors are >>> // subtracted away from the first child.  Again, because of >>> // col() processing the first child might only be a fraction of >>> // the logical subtree; it'll all get reassembled in the final >>> // multiple passes. >>> module dif() { >>>      difference() { >>>          children(0); >>>          children([1:$children-1], $color=undef); >>>      } >>> } >>> >>> // Intersect the children. >>> // Think of this as taking the first child, and subtracting >>> // parts of it that are not in common with the later children. >>> // That neatly answers the question of what color the result >>> // should be, and makes everything consistent:  the first child's >>> // color wins. >>> module int() { >>>      intersection_for(i=[0:1:$children-1]) { >>>          if (i == 0) { >>>              children(i); >>>          } else { >>>              $color = undef; >>>              children(i); >>>          } >>>      } >>> } >>> >>> // As noted above, this list of colors needs to be >>> // known in advance; in a built-in implementation (or even >>> // in a script-driven userspace implementation) this list >>> // would be dynamically derived. >>> colors = [ "red", "green", "blue" ]; >>> >>> // Build the model. >>> for (c = colors) { >>>      $color=c; >>>      color(c) render() main(); >>> } >>> >>> // Build an exploded set so that you can see >>> // what the individual colored parts look like. >>> for (i = [ 0:len(colors)-1 ]) { >>>      c = colors[i]; >>>      $color=c; >>>      translate([20+i*20,0,0]) color(c) render() main(); >>> } >>> >>> >>> >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> To unsubscribe send an email to discuss-leave@lists.openscad.org >> >> Cheers, Gene Heskett, CET. > Cheers, Gene Heskett, CET. -- "There are four boxes to be used in defense of liberty: soap, ballot, jury, and ammo. Please use in that order." -Ed Howdershelt (Author, 1940) If we desire respect for the law, we must first make the law respectable. - Louis D. Brandeis Don't poison our oceans, interdict drugs at the src.
P
pca006132
Wed, Dec 24, 2025 6:45 AM
  1. I think it will be better to do it in openscad or maybe think about
    how to do it in Manifold, we can cache and optimize stuff better.
  2. I think 3MF does have its standard for multi-material/color. Probably
    just multiple meshes with metadata. Whether all slicers support that is
    another story.

On 12/24/25 13:55, gene heskett via Discuss wrote:

Currently prusasliccer 2.8.1's AppImage, later are flatpacks which
won't run on my bookworm.

On 12/23/25 21:36, Jon Bondy wrote:

Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene?

yes, no-no privacy, and no. Cura for a while. prusa has more knobs.

I think the standards for slicing have been out there for quite a while.

But not for multi-color.

Jon

Merry Christmas, Jon.

On 12/23/2025 8:57 PM, gene heskett via Discuss wrote:

On 12/23/25 20:03, Jordan Brown via Discuss wrote:

Today's OpenSCAD color processing does face coloring.  It is perfectly
possible to have the six faces of a cube have six different colors,
and
if you union two shapes of different colors there's nothing known
about
the color of the overlap area.

That scheme is fine, more or less, for visualization, but it doesn't
work well for actual 3D printing where you need to know what color (or
material) the interior of a shape is to be.

What you need is volumetric color, so that there are no overlapping
shapes and you always know what color the interior of a shape is.

I mentioned this need as part of a discussion of color semantics, and
one of the responses was that we didn't know how to do volumetric
color.  I'd done an OpenSCAD demonstration of volumetric color and was
pretty sure that it was straightforward to come up with appropriate
processing, so I said I'd recreate that proof-of-concept for
discussion.

And here it is.

Note:  this is not the most efficient possible implementation. It
re-evaluates the model many times, when it really only needs to be
evaluated once.  There should probably be a few more render()s
scattered
around to try to get subtrees to be cached.  But it looks like it
works.

Very impressive, and raising the priority of building a 3d printer
capable of doing that,
Currently my dream thoughts have leaned more toward switching src
spools of the
same color to make a printer capable of switching src spools to
continue the print
when the current spool runs out.  To that continuous end, or for
multicolor, we'ed need to
establish a protocol we could setup in the slicer, to select which
method we have in
mind.  Selectable by telling the slicer in the g-code pramble, what
we want the printer
to do.  As the src of the code that winds driving the printer, it
behooves us to develop
the method, and attempt to set the industrues std way of doing this.

Otherwise we are left with everybody going off in their own
direction, diluting the
transition because every kit we might buy to build a printer,
ideally capable of
doing either according to the job at hand, and no ones product is
compatible
with any other vendors hardware. That is the road block preventing
me from
buying a box turtle, or any other solution.  And because of this,
not one is offering
a complete, bolt it on, load it with spools of plastic and Just Run
solution.

So please, develop a std and break a few arms getting it accepted on
an industry
wide basis because it in the end, the inter-compatibility makes sense.

Now 91 yo & running out of time, its beyond my pay grade, but the
present situation
makes no sense at all.  It is a huge road block to progress.

Thank you and Merry Christmas everybody.

Implementations of hull(), minkowski(), et cetera, and of the 2D
operations, left as an exercise for the reader.

Here's the result of this particular model, both in assembled form and
exploded by color:

// Volumetric color proof of concept
// Jordan Brown, openscad@jordan.maileater.net

// There are four relevant modules in this POC:
// col - replacement for color()
// uni - replacement for union()
// dif - replacement for difference()
// int - replacement for intersection()

// In this POC, the list of possible colors needs to be known in
advance;
// in a built-in implementation it would either be collected during
the
// evaluation phase or managed entirely dynamically.  It would be
// straightforward to build a version of this POC that would be
// driven by an external script that would first run it in a
// "list colors" mode and would then run it once for each color.

// Similarly, in this POC the model is encapsulated in a module
main(),
// while in a built-in implementation the final "step through the
colors"
// loop would be implied and the model could be at the top level.

// This POC steps through the colors, generating the parts for one
color,
// then the next, then the next.  A built-in implementation could do
// that, or could do roughly the same operations across all colors
at once.

// The model.  A couple of unions, a difference, and an intersection
// to do a cutaway so that you can see the internal colors.
module main() {
     int() {
         uni() {
             col("green") rotate([90,0,0]) cylinder(h=30, d=5,
center=true);
             dif() {
                 uni() {
                     col("red") cube(10);
                     col("blue") sphere(10);
                 }
                 cylinder(h=30, d=5, center=true);
             }
         }
         rotate(-45) translate([0,-20,-20]) cube([40,40,40]);
     }
}

// And now the infrastructure...

// Set the color of the children, like color().
// In this POC, this really operates by skipping anything that
// isn't the desired color, and then coloring during the per-color
// pass at the end, but there are other variations.
module col(c) {
     union() {   // work around #6456.
         // $color=undef means that we want all colors - in
particular,
         // for the second-and-later children of dif() and int().
         if (is_undef($color) || c == $color) {
             children();
         }
     }
}

// Union the children.
// What this does is to draw the first child, then draw the second
child
// less the first child, then the third less the first and second, and
// so on.  Note that the negative components have $color=undef so that
// the entire subassembly, of all colors, gets subtracted out.
module uni() {
     for (i=[0:1:$children-1]) {
         // Add this child, less the children before it. Note that
         // because of col() processing this might be only part
         // of the logical subtree, but that's OK; what's important
         // is that we mask it all colors of the previous children.
         difference() {
             children(i);
             children([0:1:i-1], $color=undef);
         }
     }
}

// Difference the children.
// The only novel thing that this does is to set $color=undef
// for the second-and-later children, so that all colors are
// subtracted away from the first child.  Again, because of
// col() processing the first child might only be a fraction of
// the logical subtree; it'll all get reassembled in the final
// multiple passes.
module dif() {
     difference() {
         children(0);
         children([1:$children-1], $color=undef);
     }
}

// Intersect the children.
// Think of this as taking the first child, and subtracting
// parts of it that are not in common with the later children.
// That neatly answers the question of what color the result
// should be, and makes everything consistent:  the first child's
// color wins.
module int() {
     intersection_for(i=[0:1:$children-1]) {
         if (i == 0) {
             children(i);
         } else {
             $color = undef;
             children(i);
         }
     }
}

// As noted above, this list of colors needs to be
// known in advance; in a built-in implementation (or even
// in a script-driven userspace implementation) this list
// would be dynamically derived.
colors = [ "red", "green", "blue" ];

// Build the model.
for (c = colors) {
     $color=c;
     color(c) render() main();
}

// Build an exploded set so that you can see
// what the individual colored parts look like.
for (i = [ 0:len(colors)-1 ]) {
     c = colors[i];
     $color=c;
     translate([20+i*20,0,0]) color(c) render() main();
}


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Cheers, Gene Heskett, CET.

Cheers, Gene Heskett, CET.

"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.

  • Louis D. Brandeis
    Don't poison our oceans, interdict drugs at the src.

OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

1. I think it will be better to do it in openscad or maybe think about how to do it in Manifold, we can cache and optimize stuff better. 2. I think 3MF does have its standard for multi-material/color. Probably just multiple meshes with metadata. Whether all slicers support that is another story. On 12/24/25 13:55, gene heskett via Discuss wrote: > Currently prusasliccer 2.8.1's AppImage, later are flatpacks which > won't run on my bookworm. > > On 12/23/25 21:36, Jon Bondy wrote: >> Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene? > yes, no-no privacy, and no. Cura for a while. prusa has more knobs. >> >> I think the standards for slicing have been out there for quite a while. > But not for multi-color. >> >> >> Jon >> > Merry Christmas, Jon. >> >> On 12/23/2025 8:57 PM, gene heskett via Discuss wrote: >>> On 12/23/25 20:03, Jordan Brown via Discuss wrote: >>>> Today's OpenSCAD color processing does face coloring.  It is perfectly >>>> possible to have the six faces of a cube have six different colors, >>>> and >>>> if you union two shapes of different colors there's nothing known >>>> about >>>> the color of the overlap area. >>>> >>>> That scheme is fine, more or less, for visualization, but it doesn't >>>> work well for actual 3D printing where you need to know what color (or >>>> material) the interior of a shape is to be. >>>> >>>> What you need is volumetric color, so that there are no overlapping >>>> shapes and you always know what color the interior of a shape is. >>>> >>>> I mentioned this need as part of a discussion of color semantics, and >>>> one of the responses was that we didn't know how to do volumetric >>>> color.  I'd done an OpenSCAD demonstration of volumetric color and was >>>> pretty sure that it was straightforward to come up with appropriate >>>> processing, so I said I'd recreate that proof-of-concept for >>>> discussion. >>>> >>>> And here it is. >>>> >>>> Note:  this is not the most efficient possible implementation. It >>>> re-evaluates the model many times, when it really only needs to be >>>> evaluated once.  There should probably be a few more render()s >>>> scattered >>>> around to try to get subtrees to be cached.  But it looks like it >>>> works. >>> Very impressive, and raising the priority of building a 3d printer >>> capable of doing that, >>> Currently my dream thoughts have leaned more toward switching src >>> spools of the >>> same color to make a printer capable of switching src spools to >>> continue the print >>> when the current spool runs out.  To that continuous end, or for >>> multicolor, we'ed need to >>> establish a protocol we could setup in the slicer, to select which >>> method we have in >>> mind.  Selectable by telling the slicer in the g-code pramble, what >>> we want the printer >>> to do.  As the src of the code that winds driving the printer, it >>> behooves us to develop >>> the method, and attempt to set the industrues std way of doing this. >>> >>> Otherwise we are left with everybody going off in their own >>> direction, diluting the >>> transition because every kit we might buy to build a printer, >>> ideally capable of >>> doing either according to the job at hand, and no ones product is >>> compatible >>> with any other vendors hardware. That is the road block preventing >>> me from >>> buying a box turtle, or any other solution.  And because of this, >>> not one is offering >>> a complete, bolt it on, load it with spools of plastic and Just Run >>> solution. >>> >>> So please, develop a std and break a few arms getting it accepted on >>> an industry >>> wide basis because it in the end, the inter-compatibility makes sense. >>> >>> Now 91 yo & running out of time, its beyond my pay grade, but the >>> present situation >>> makes no sense at all.  It is a huge road block to progress. >>> >>> Thank you and Merry Christmas everybody. >>>> >>>> Implementations of hull(), minkowski(), et cetera, and of the 2D >>>> operations, left as an exercise for the reader. >>>> >>>> Here's the result of this particular model, both in assembled form and >>>> exploded by color: >>>> >>>> >>>> >>>> // Volumetric color proof of concept >>>> // Jordan Brown, openscad@jordan.maileater.net >>>> >>>> // There are four relevant modules in this POC: >>>> // col - replacement for color() >>>> // uni - replacement for union() >>>> // dif - replacement for difference() >>>> // int - replacement for intersection() >>>> >>>> // In this POC, the list of possible colors needs to be known in >>>> advance; >>>> // in a built-in implementation it would either be collected during >>>> the >>>> // evaluation phase or managed entirely dynamically.  It would be >>>> // straightforward to build a version of this POC that would be >>>> // driven by an external script that would first run it in a >>>> // "list colors" mode and would then run it once for each color. >>>> >>>> // Similarly, in this POC the model is encapsulated in a module >>>> main(), >>>> // while in a built-in implementation the final "step through the >>>> colors" >>>> // loop would be implied and the model could be at the top level. >>>> >>>> // This POC steps through the colors, generating the parts for one >>>> color, >>>> // then the next, then the next.  A built-in implementation could do >>>> // that, or could do roughly the same operations across all colors >>>> at once. >>>> >>>> // The model.  A couple of unions, a difference, and an intersection >>>> // to do a cutaway so that you can see the internal colors. >>>> module main() { >>>>      int() { >>>>          uni() { >>>>              col("green") rotate([90,0,0]) cylinder(h=30, d=5, >>>> center=true); >>>>              dif() { >>>>                  uni() { >>>>                      col("red") cube(10); >>>>                      col("blue") sphere(10); >>>>                  } >>>>                  cylinder(h=30, d=5, center=true); >>>>              } >>>>          } >>>>          rotate(-45) translate([0,-20,-20]) cube([40,40,40]); >>>>      } >>>> } >>>> >>>> // And now the infrastructure... >>>> >>>> // Set the color of the children, like color(). >>>> // In this POC, this really operates by skipping anything that >>>> // isn't the desired color, and then coloring during the per-color >>>> // pass at the end, but there are other variations. >>>> module col(c) { >>>>      union() {   // work around #6456. >>>>          // $color=undef means that we want all colors - in >>>> particular, >>>>          // for the second-and-later children of dif() and int(). >>>>          if (is_undef($color) || c == $color) { >>>>              children(); >>>>          } >>>>      } >>>> } >>>> >>>> // Union the children. >>>> // What this does is to draw the first child, then draw the second >>>> child >>>> // less the first child, then the third less the first and second, and >>>> // so on.  Note that the negative components have $color=undef so that >>>> // the entire subassembly, of all colors, gets subtracted out. >>>> module uni() { >>>>      for (i=[0:1:$children-1]) { >>>>          // Add this child, less the children before it. Note that >>>>          // because of col() processing this might be only part >>>>          // of the logical subtree, but that's OK; what's important >>>>          // is that we mask it all colors of the previous children. >>>>          difference() { >>>>              children(i); >>>>              children([0:1:i-1], $color=undef); >>>>          } >>>>      } >>>> } >>>> >>>> // Difference the children. >>>> // The only novel thing that this does is to set $color=undef >>>> // for the second-and-later children, so that all colors are >>>> // subtracted away from the first child.  Again, because of >>>> // col() processing the first child might only be a fraction of >>>> // the logical subtree; it'll all get reassembled in the final >>>> // multiple passes. >>>> module dif() { >>>>      difference() { >>>>          children(0); >>>>          children([1:$children-1], $color=undef); >>>>      } >>>> } >>>> >>>> // Intersect the children. >>>> // Think of this as taking the first child, and subtracting >>>> // parts of it that are not in common with the later children. >>>> // That neatly answers the question of what color the result >>>> // should be, and makes everything consistent:  the first child's >>>> // color wins. >>>> module int() { >>>>      intersection_for(i=[0:1:$children-1]) { >>>>          if (i == 0) { >>>>              children(i); >>>>          } else { >>>>              $color = undef; >>>>              children(i); >>>>          } >>>>      } >>>> } >>>> >>>> // As noted above, this list of colors needs to be >>>> // known in advance; in a built-in implementation (or even >>>> // in a script-driven userspace implementation) this list >>>> // would be dynamically derived. >>>> colors = [ "red", "green", "blue" ]; >>>> >>>> // Build the model. >>>> for (c = colors) { >>>>      $color=c; >>>>      color(c) render() main(); >>>> } >>>> >>>> // Build an exploded set so that you can see >>>> // what the individual colored parts look like. >>>> for (i = [ 0:len(colors)-1 ]) { >>>>      c = colors[i]; >>>>      $color=c; >>>>      translate([20+i*20,0,0]) color(c) render() main(); >>>> } >>>> >>>> >>>> >>>> >>>> _______________________________________________ >>>> OpenSCAD mailing list >>>> To unsubscribe send an email to discuss-leave@lists.openscad.org >>> >>> Cheers, Gene Heskett, CET. >> > > Cheers, Gene Heskett, CET. > -- > "There are four boxes to be used in defense of liberty: > soap, ballot, jury, and ammo. Please use in that order." > -Ed Howdershelt (Author, 1940) > If we desire respect for the law, we must first make the law respectable. > - Louis D. Brandeis > Don't poison our oceans, interdict drugs at the src. > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
GH
gene heskett
Wed, Dec 24, 2025 8:18 AM

On 12/24/25 01:46, pca006132 via Discuss wrote:

  1. I think it will be better to do it in openscad or maybe think about
    how to do it in Manifold, we can cache and optimize stuff better.
  2. I think 3MF does have its standard for multi-material/color.
    Probably just multiple meshes with metadata. Whether all slicers
    support that is another story.

I use .3mf exclusively unless the slicer objects, but have not been made
aware of that. Where can I find this documentation so I can understand
what is out there?
Thank you.

On 12/24/25 13:55, gene heskett via Discuss wrote:

Currently prusasliccer 2.8.1's AppImage, later are flatpacks which
won't run on my bookworm.

On 12/23/25 21:36, Jon Bondy wrote:

Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene?

yes, no-no privacy, and no. Cura for a while. prusa has more knobs.

I think the standards for slicing have been out there for quite a
while.

But not for multi-color.

[...]

Cheers, Gene Heskett, CET.

"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author, 1940)
If we desire respect for the law, we must first make the law respectable.

  • Louis D. Brandeis
    Don't poison our oceans, interdict drugs at the src.
On 12/24/25 01:46, pca006132 via Discuss wrote: > 1. I think it will be better to do it in openscad or maybe think about > how to do it in Manifold, we can cache and optimize stuff better. > 2. I think 3MF does have its standard for multi-material/color. > Probably just multiple meshes with metadata. Whether all slicers > support that is another story. I use .3mf exclusively unless the slicer objects, but have not been made aware of that. Where can I find this documentation so I can understand what is out there? Thank you. > > On 12/24/25 13:55, gene heskett via Discuss wrote: >> Currently prusasliccer 2.8.1's AppImage, later are flatpacks which >> won't run on my bookworm. >> >> On 12/23/25 21:36, Jon Bondy wrote: >>> Have you used PrusaSlicer or Bambu Studio or OrcaSlicer, Gene? >> yes, no-no privacy, and no. Cura for a while. prusa has more knobs. >>> >>> I think the standards for slicing have been out there for quite a >>> while. >> But not for multi-color. [...] Cheers, Gene Heskett, CET. -- "There are four boxes to be used in defense of liberty: soap, ballot, jury, and ammo. Please use in that order." -Ed Howdershelt (Author, 1940) If we desire respect for the law, we must first make the law respectable. - Louis D. Brandeis Don't poison our oceans, interdict drugs at the src.
JB
Jordan Brown
Wed, Dec 24, 2025 8:28 AM

How do you think this improves on colorscad?

I haven’t used colorscad; I’ve only just now read its README. Looking at it, it looks like it’s actually almost exactly the stuff I said you could wrap around this implementation to make it actually useful.

But it doesn’t do the stuff that I consider truly interesting. Consider this paragraph from its README:

Let's avoid weird geometry such as overlapping color volumes... Avoid using multiple colors in an intersection() or difference(), if unavoidable then just wrap it in a color() statement.

If you’re willing to live with those restrictions, well, OK, but it sure seems like the example that I gave would be much harder to build if you have to live within them. I want something where color (“red”) cube(10); color(“blue”) sphere(10); does something sensible and predictable, without me having to do the work to avoid the overlap. Similarly, I want to be able to take a multicolor object and cut it in half with a difference or intersection and have it just work. (Which I suspect it will, with colorscad, but the documentation isn’t encouraging.)

As an exercise, you could demonstrate creating my sample model using colorscad’s restrictions; it would be interesting to see the comparison. (Remember that “my sample model” is only the stuff inside the “main” module; the rest is infrastructure.)

You made a number of choices regarding what union/difference/intersection mean, but are those useful and efficient in creating actual shapes versus i.e. BOSL2's coloring?

I haven’t noticed similar support in BOSL2, but I haven’t looked. It wouldn’t surprise me if they had something similar, because what I did is a lot like what they do with their diff() operator.

But that would only make my point, which is that it is possible to define volumetric color.

Are the definitions I picked useful? I have no practical experience with them, since I don’t have a multicolor printer. However, since they’re a superset of the capabilities of colorscad’s design capabilities - if you avoid overlaps, it’ll generate the same results that colorscad produces - they’re at least as useful as it is. (Again noting that it does the automation that wraps around this geometry processing to step through the colors, which wasn’t the point of this exercise.)

I’ve been thinking about the definitions on and off for a long time. Difference is easy; the colors of the first child must remain unchanged as you cut away parts of it. Intersection and the overlapping part of union, which are in a sense the same thing, kind of need to be either first-wins or last-wins, and the two strategies seems equivalent, so I picked first-wins because that’s what difference needs. Hull and the others need some answer, but I doubt that what the answer is matters.

Are they efficient? First, I don’t care. Getting a useful and understandable result is the critical piece; a scheme that is ten times faster and requires the model to be ten times as complicated (or even twice as complicated) is in my mind a losing proposition. Second… as implemented, absolutely not. There’s at least a couple of optimizations that could be made even in an OpenSCAD-language implementation, and there’s several more that can be made if you can work directly with the CSG tree. (Geometry values from PR#4478 would help there.) Third, I expect that a multicolor scheme is always going to be slower than a single-color scheme, because there’s just more geometry processing to do.

> How do you think this improves on colorscad? I haven’t used colorscad; I’ve only just now read its README. Looking at it, it looks like it’s actually almost exactly the stuff I said you could wrap around this implementation to make it actually useful. But it doesn’t do the stuff that I consider truly interesting. Consider this paragraph from its README: Let's avoid weird geometry such as overlapping color volumes... Avoid using multiple colors in an intersection() or difference(), if unavoidable then just wrap it in a color() statement. If you’re willing to live with those restrictions, well, OK, but it sure seems like the example that I gave would be much harder to build if you have to live within them. I want something where color (“red”) cube(10); color(“blue”) sphere(10); does something sensible and predictable, without me having to do the work to avoid the overlap. Similarly, I want to be able to take a multicolor object and cut it in half with a difference or intersection and have it just work. (Which I suspect it will, with colorscad, but the documentation isn’t encouraging.) As an exercise, you could demonstrate creating my sample model using colorscad’s restrictions; it would be interesting to see the comparison. (Remember that “my sample model” is only the stuff inside the “main” module; the rest is infrastructure.) > You made a number of choices regarding what union/difference/intersection mean, but are those useful and efficient in creating actual shapes versus i.e. BOSL2's coloring? I haven’t noticed similar support in BOSL2, but I haven’t looked. It wouldn’t surprise me if they had something similar, because what I did is a lot like what they do with their diff() operator. But that would only make my point, which is that it *is* possible to define volumetric color. Are the definitions I picked useful? I have no practical experience with them, since I don’t have a multicolor printer. However, since they’re a superset of the capabilities of colorscad’s design capabilities - if you avoid overlaps, it’ll generate the same results that colorscad produces - they’re at least as useful as it is. (Again noting that it does the automation that wraps around this geometry processing to step through the colors, which wasn’t the point of this exercise.) I’ve been thinking about the definitions on and off for a long time. Difference is easy; the colors of the first child must remain unchanged as you cut away parts of it. Intersection and the overlapping part of union, which are in a sense the same thing, kind of need to be either first-wins or last-wins, and the two strategies seems equivalent, so I picked first-wins because that’s what difference needs. Hull and the others need *some* answer, but I doubt that what the answer is matters. Are they efficient? First, I don’t care. Getting a useful and understandable result is the critical piece; a scheme that is ten times faster and requires the model to be ten times as complicated (or even twice as complicated) is in my mind a losing proposition. Second… as implemented, absolutely not. There’s at least a couple of optimizations that could be made even in an OpenSCAD-language implementation, and there’s several more that can be made if you can work directly with the CSG tree. (Geometry values from PR#4478 would help there.) Third, I expect that a multicolor scheme is always going to be slower than a single-color scheme, because there’s just more geometry processing to do.
JB
Jordan Brown
Wed, Dec 24, 2025 8:43 AM
  1. I think it will be better to do it in openscad or maybe think about how to do it in Manifold, we can cache and optimize stuff better.

Better than my OpenSCAD-language implementation? Absolutely! My point was only to demonstrate definitions, using operations that we already have.

Better than in a slicer? Also absolutely, for a different reason. Slicers shouldn’t be controlling the design of the piece. They are responsible for implementing the design, but the model should say unambiguously how the model is divided by color/material/whatever.

  1. I think 3MF does have its standard for multi-material/color. Probably just multiple meshes with metadata. Whether all slicers support that is another story.

Yeah, I get the impression that that’s more or less a solved problem.

> 1. I think it will be better to do it in openscad or maybe think about how to do it in Manifold, we can cache and optimize stuff better. Better than my OpenSCAD-language implementation? Absolutely! My point was only to demonstrate definitions, using operations that we already have. Better than in a slicer? Also absolutely, for a different reason. Slicers shouldn’t be controlling the design of the piece. They are responsible for *implementing* the design, but the model should say unambiguously how the model is divided by color/material/whatever. > 2. I think 3MF does have its standard for multi-material/color. Probably just multiple meshes with metadata. Whether all slicers support that is another story. > Yeah, I get the impression that that’s more or less a solved problem.