Can the `render` function be used to speed up rendering?

5

I am designing a moderately complicated piece in OpenScad.

It renders fast enough in preview mode (1s). But when i do a full render so I can export to STL, it takes ages (In the 10s of minutes)

I have read that sometimes the function render is useful to speed up overall rendering.

  • Is this correct, or have I misunderstood?
    • If I have misunderstood, what is the render function useful for?
  • How does this work?
  • In what circumstances can I apply it?

Lyndon White

Posted 2018-02-05T04:09:08.453

Reputation: 151

What processor chip is in your PC? Why do you think those particular functions (union, difference) are the problem? Is there a reason you can't finalize the booleans into a single object prior to rendering? – Carl Witthoft – 2018-02-05T13:46:49.700

What does it mean to "finalize the booleans into a single object"? (I kinda thought render might be the command to do this, if it is what I think it is) PC Proc is Core2 Duo E6750 2.66Ghz on one computer, and i5-6400 2.70GHz on the other.

I think the bools are a problem because they are well known to be slow, they show up in almost every google result about rendering speed in every CAD program. – Lyndon White – 2018-02-05T13:57:50.007

Though, to be fair, I gues Booleans probably show up in every nontirival openScad example, they are useful, I will tweak question – Lyndon White – 2018-02-05T14:01:57.747

Fair enough - I was thinking in Meshmixer terms, where merging two objects can be done at any time, prior to a final cleanup or part rendering. – Carl Witthoft – 2018-02-05T19:44:52.373

1@CarlWitthoft - Boolean operations in CAD are extremely expensive, especially when the surfaces that need to be trimmed are curved. In fact such operations are so complex that can't be solved in a sensible time, and for this reasons CAD packages use approximations that in turn makes most 3D models broken (and generate the occasional crash). Google "Surface-to-surface intersection problem" if you want to learn more about this! :) – mac – 2018-02-06T01:35:57.960

Answers

4

First a disclaimer: I am far from an expert on the subject, I'm just a regular Joe who happens to use OpenSCAD and have done some experimentation with it. I believe the answer below to be correct, but I will be very grateful if errors or misconceptions were brought to my attention in the comments. :)

I have read that sometimes the function render is useful to speed up overall rendering. Is this correct, or have I misunderstood?

I'm unaware if it is possible to use render() to speed up the "overall rendering", but I'm rather confident that the intended purpose of render() is to simplify the in-memory representation of the model and thus the responsiveness of the preview window, rather than speed-up its final rendering.

How does this work?

In order to understand how this work, one has to understand how Constructive Solid Geometry (CSG) works.

The entire premise of CSG is that using boolean operations between primitive solid shapes, it is possible to represent complex shapes.

However, while the human operator may see subtractive operations like difference and intersection as something that makes the model smaller in volume and thus possibly easier to handle, the computer sees each and every operation as adding geometry and complexity to the part, as the following image aptly illustrates:

visuals vs in-memory model

When manipulating the model in the CAD viewer, OpenSCAD is in the preview mode and all that "invisible geometry" needs to be processed for each adjustment of the viewport. It is easy to reach a level at which the OpenSCAD viewer will become jittery or unresponsive.

What the render() function does, is telling OpenSCAD to compute the mesh resulting from the boolean operations enclosed in the render() call, and use that single mesh instead of the underlying boolean-combined primitives when handling the model in the viewer. Meshes are what is normally used in the render mode of OpenSCAD (F6) rather than in the preview one, but here their advantage is not better visual quality, but the fact that OpenSCAD needs to handle a lot less geometry.

In what circumstances can I apply it?

You can apply it any time you like, really, but it is a trade-off: a model that uses the render() function internally, will take longer to display its initial preview (because generating the mesh is an expensive operation) but it will behave very well in the viewer. Conversely, a large model that does not leverage render() will be jittery to handle in the viewer, but it will render to screen in a fraction of the time. It has to be noted that OpenSCAD make heavy use of caching, so the first preview is the one that will take the longest, while successive ones may be a lot faster.

small test

For reference, the code at the bottom of this answer (which generates the image above) behaved like this:

  • With render(): 15s for the preview, 1m29s more for the proper rendering (TOTAL: 1m44s).
  • Without render(): 0s for the preview, 1m45s more for the proper rendering (TOTAL: 1m45s).

I don't know if the fact that the totals resemble each other is a coincidence peculiar to my model or a general rule of thumb (the render() function effectively creating part of the final rendering during preview), but you are free to play with the code and if you find out a pattern, please leave a comment.

In the following code, you may need to increase the grid size to 20x20 if you want to see the difference in responsiveness between vanilla code and render() function.

Also remember to close and reopen OpenSCAD between tests, in order to flush the cache.


$fn = 30;

module shape() {
    render() difference() {
        sphere();
        cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, 90, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([45, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([-45, 0, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, 45, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([0, -45, 0]) cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, 45]) cylinder(r=0.3, h=3, center=true);
        rotate([90, 0, -45]) cylinder(r=0.3, h=3, center=true);
    }
}

module line(x, y) {
    translate([x * 2, y, 0]) shape();
    if (x > 0) line(x - 1, y);
}    

module grid(x, y) {
    line(x, y * 2);
    if (y > 0) grid(x, y - 1);
}

grid(3, 3);

mac

Posted 2018-02-05T04:09:08.453

Reputation: 4 437