tag:blogger.com,1999:blog-38303503920702774862024-03-15T18:10:03.725-07:00Random thoughts on Computer Graphics, 3D printing, Games, and the UniverseUnknownnoreply@blogger.comBlogger76125tag:blogger.com,1999:blog-3830350392070277486.post-63988289375162813882017-07-09T00:43:00.001-07:002017-07-09T05:56:27.211-07:00[3dprint] Adaptive slicing, smooth and optimizedIceSL 2.1 introduces per-layer settings, with a simple interface allowing to customize many parameters per-layer. Below is a screenshot for layer thickness (blue is thinner).<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjB_bJM5Mn0nDR-TB9LvAfYFH7V2HQgKVb0s20BBGUMkqpsnXRxxzn6y8Em-UyFnqoevtV_NCdhPMdOWUfuTiGp73lllSTVOazGFCRyBuKf0H-sc6qAX7-4LsHsoypx-RkPlCpIsCwcuWs/s1600/adaptive1.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1371" data-original-width="1539" height="570" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjB_bJM5Mn0nDR-TB9LvAfYFH7V2HQgKVb0s20BBGUMkqpsnXRxxzn6y8Em-UyFnqoevtV_NCdhPMdOWUfuTiGp73lllSTVOazGFCRyBuKf0H-sc6qAX7-4LsHsoypx-RkPlCpIsCwcuWs/s640/adaptive1.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Model is https://www.thingiverse.com/thing:222814</td></tr>
</tbody></table>
<div style="text-align: justify;">
The bar on the left represents the height of the print, and by simply placing keys (a setting value at a given height) you can precisely control how the parameter varies along the print. In between keys a smooth interpolation is done, avoiding abrupt changes that might produce visible differences (but if abrupt changes are required, simply place two keys with different values next to each others).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The idea that smoothness is important for adaptive slicing was recently introduced by <a href="http://www.prusaprinters.org/smooth-variable-layer-height-awesome-supports-slic3r-prusa-edition/">Prusa</a>. My experience with adaptive slicing is that indeed abrupt changes lead to noticeable differences in surface finish, and therefore if visual quality matters, smoothness is great. IceSL smoothly interpolates all per-layer parameters.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
However, regarding adaptive slicing IceSL goes much further than just providing an interface. It features a novel, state of the art algorithm for automatic layer thickness selection. This is powered by an algorithm developed by Marc Alexa, Kristian Hildebrand and myself, <a href="http://dl.acm.org/citation.cfm?id=2999536">that was recently published in ACM Transactions on Graphics</a> (will be presented at SIGGRAPH this summer, don't miss it!).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
What is different between this algorithm and previous work is that it computes a provably optimal result (in a discrete setting): the best possible choice of slice thicknesses that will minimize an error, in this case the part accuracy (the volume difference between the print and the actual geometry). Not only that, but it finds a solution for all possible number of slices in a single optimization pass.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The bottom line is that you get automatically a great selection of layer thicknesses, <i>for a desired number of slices</i>. Yes, this means you get to choose a number of slices (which strongly correlates with printing time in most cases), and the algorithm selects the slice thicknesses than provide the most accurate result for this choice.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
One drawback of the algorithm as described in the paper is that it does not produce a smooth result. As smoothness is important for visual quality, I provide in IceSL a modified version that generates smooth results (but gives up optimal accuracy). Of course you can choose between both versions!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's see some results! (To activate the optimizer simply click on the "Optimize" button at the top of the left bar, in IceSL-slicer of IceSL-forge. After optimization a slider lets you choose the number of slices.)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Here is the castle for 999 slices from 0.1 to 0.3 mm, smooth solution. See how the algorithm uses thick slices in vertical parts and thinner ones in slanted/detailed regions. Keep in mind this is a compromise constrained by the chosen number of slices.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMgbVnRj2GR4Opgapcfxm0fGKmVjQA6wkP5vjkpHpaBGUvYff614A1IIKm9g6kYVyiAzmgE_g5cCixQnlV5g0f6XyoFLj4wB0Gco2qU0RPRHpcPhjePDHN71QYaCml6YycE2n8g2tOn8Q/s1600/adaptive2.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1339" data-original-width="1509" height="566" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMgbVnRj2GR4Opgapcfxm0fGKmVjQA6wkP5vjkpHpaBGUvYff614A1IIKm9g6kYVyiAzmgE_g5cCixQnlV5g0f6XyoFLj4wB0Gco2qU0RPRHpcPhjePDHN71QYaCml6YycE2n8g2tOn8Q/s640/adaptive2.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Result with 999 slices, smooth solution</td><td class="tr-caption" style="text-align: center;"><br /></td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: justify;">
One thing that cannot easily be seen, is that the position of the
horizontal surfaces (tops) is now very accurate. When slicing at 0.3 mm,
if a horizontal surface is located at height 1.05 mm, the positioning
error is as large as 0.15 mm ! (because 3 slices give 0.9 mm, and 4 slices give 1.2mm, we cannot reach height 1.05mm). Our algorithm will insert one smaller slice to ensure the top part is accurately positioned, and this is true of all complex alignment cases that can occur.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is another solution with more slices (you can interactively select the number of slices you want in the print, with immediate feedback):</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiop-xOchSwQ5yZ8vxJdsZ3E_PAZyu_Cfla7712JR4sM0aDMcy27kjv8vJkKWScmtWcgvWiq_ueZpuijcsLBDvSe2y_ReoodybC9Jdbo98As5OWZhyrz019aq24nJfb7DA2T-hvD-uOujk/s1600/adaptive3.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1337" data-original-width="1491" height="572" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiop-xOchSwQ5yZ8vxJdsZ3E_PAZyu_Cfla7712JR4sM0aDMcy27kjv8vJkKWScmtWcgvWiq_ueZpuijcsLBDvSe2y_ReoodybC9Jdbo98As5OWZhyrz019aq24nJfb7DA2T-hvD-uOujk/s640/adaptive3.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Result with 1499 slices, smooth solution</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
Great isn't it? And you can always fall back to manual selection, if you do not like the optimized result.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Stay tuned for other focuses on the new features of IceSL 2.1, and don't miss the SIGGRAPH presentation this summer about our algorithm (Session "Fabricating curves, surfaces and volumes, Tuesday, 1 August, 10:45 am-12:35 pm).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://shapeforge.loria.fr/icesl/download.html">Download IceSL.</a></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://shapeforge.loria.fr/slicecrafter/">Try our online STL slicing engine.</a></div>
<div class="separator" style="clear: both; text-align: left;">
Follow us on <a href="https://twitter.com/iceslapp">@iceslapp</a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMgbVnRj2GR4Opgapcfxm0fGKmVjQA6wkP5vjkpHpaBGUvYff614A1IIKm9g6kYVyiAzmgE_g5cCixQnlV5g0f6XyoFLj4wB0Gco2qU0RPRHpcPhjePDHN71QYaCml6YycE2n8g2tOn8Q/s1600/adaptive2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-29107133324795113672016-12-08T01:32:00.000-08:002016-12-08T01:32:06.602-08:00[3dprint] IceSL onlineWe just released <a href="http://shapeforge.loria.fr/icesl-online/">IceSL online</a>. If you enjoy solid modeling (CSG) and 3D printing, don't miss it! You can directly model with code (in lua!), customize objects (in real time!) and generate G-code from your web browser. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib95-SAXlZBGPhD410vm1xQPJ0EVkRNqMNJnN7zuWp0_d0LxAvs-JsCUVOHp5bcORe6aME0KSQGvy2wJ37-qtTlEO5_XaoF1gokBLW852ZfNaIeYcxsfvOL0iicG28g6Wu-wjdELpDd7s/s1600/icesl-online.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib95-SAXlZBGPhD410vm1xQPJ0EVkRNqMNJnN7zuWp0_d0LxAvs-JsCUVOHp5bcORe6aME0KSQGvy2wJ37-qtTlEO5_XaoF1gokBLW852ZfNaIeYcxsfvOL0iicG28g6Wu-wjdELpDd7s/s400/icesl-online.jpg" width="400" /></a></div>
<br />
From a technical point of view, IceSL online was quite an endeavor. Imagine taking a state-of-the-art GPU modeling and slicing engine, that by the way requires OpenGL 4.2 to run, and now squeeze it into a WebGL 1.0 javascript engine...<br />
<br />
... Errr?<br />
<br />
That's also how I felt the first time the thought occurred to me: no way! But well, who does not like a challenge :-) It turns out WebGL 1.0 is more or less at the level of what was available back in 2004-2006 when I was a PhD student and postdoc. And at the time, I had <a href="http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter37.html">quite</a> <a href="http://hhoppe.com/proj/paratexsyn/">some</a> <a href="http://evasion.inrialpes.fr/Publications/2004/LDN04/">fun</a> with GPU programming. Only, 2016 GPUs are much much more powerful. This is a perfect situation for a complete abuse of good old-school OpenGL GPU programming!
And this is what made IceSL-online possible. It is a new engine, yet it shares many (most) core algorithms with IceSL (the new version, not yet released) and SliceCrafter (<a href="http://shapeforge.loria.fr/slicecrafter/">slice STL files online</a>).<br />
<br />
I am hoping to find the time to describe how it works -- nothing ground breaking for experts, but it is quite fun. Even possibly a bit novel. In any case, I hope you'll enjoy using it!<br />
<br />
Of course it has limitations compared to the desktop version and it will not support large designs, but most of my models work just fine in it. I have already made several projects, and it is super convenient to fire up the web browser, customize or model a little something and directly get the G-Code for a quick print. I am also hoping it can be a good educational tool, to learn programming and 3D printing.<br />
<br />
Stay tuned for upcoming features, and please spread the word!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-12089960840670862972016-08-05T10:07:00.000-07:002016-08-05T16:05:26.145-07:00[3dprint] hierarchical rhombic infillRhombic infills are both strong and fast to print. If you are using <a href="http://shapeforge.loria.fr/icesl/">IceSL</a>, you probably already have seen these patterns as they have been the default infill for the past year. I also did a number of experiments with a <a href="https://twitter.com/sylefeb/status/627140622319792129">hierarchical version of a rhombic infill</a>. However, the question of how to select the subdivision level depends on the target application.<br />
<br />
<center>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGgtIyiXNJNQ5te99076-T18cMf6XzqRExBsxxUKYlU05a0Fnt0d_kkHPqiupkCdxBTDncpwhsPxF1d2E2VQYmQOOfJVLZuxFO7ihIcMQmwMIEXbHhs-Eg73fRXJRUxG9wBd3KB4Q6JNY/s1600/octree-infill4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGgtIyiXNJNQ5te99076-T18cMf6XzqRExBsxxUKYlU05a0Fnt0d_kkHPqiupkCdxBTDncpwhsPxF1d2E2VQYmQOOfJVLZuxFO7ihIcMQmwMIEXbHhs-Eg73fRXJRUxG9wBd3KB4Q6JNY/s200/octree-infill4.jpg" width="190" /></a></center>
<br />
A <a href="http://homepage.tudelft.nl/h05k3/pubs/CADInfillOptm.pdf">recent article</a> by Wu and colleagues explores interesting ways to subdivide a rhombic infill to strengthen objects, for instance using a finite element simulation to subdivide weak areas in priority. This increases the density of the structures locally to obtain stronger parts.<br />
<br />
Beside their good properties (self supporting and mechanical strength), rhombic infills are also <a href="http://sylefeb.blogspot.fr/2015/07/3dprint-3d-infilling-faster-stronger.html">very efficient to generate and print</a>. Our web based slicer, <a href="http://shapeforge.loria.fr/slicecrafter/">SliceCrafter</a>, includes an improved rhombic infill that prints very fast because it only uses 45 degree angled print paths (an idea suggested by IceSL user Maze Mietner). <a href="http://shapeforge.loria.fr/slicecrafter/">Try it out</a>!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-35063646509667799432016-06-15T11:28:00.000-07:002016-06-15T11:28:01.708-07:00[3dprint] Plastic deposition flow control in IceSLIceSL has a nice feature to control plastic flow that I never took the time to explain.<br />
<br />
There are several ways to produce the toolpaths for plastic deposition, and some of them result in paths that can slightly overlap : if you were to follow the paths with a thick marker, some places would receive color twice. Well, the same happens with plastic resulting in overflow! The reason a slicer might want to do that is to avoid the opposite: leaving a gap. IceSL tends to squeeze more paths within a slice so as to reduce some of these gaps (it is not perfect though, as some thin walls are still problematic).<br />
<br />
While often small, if such overflows occur always at the same place across layers, they will accumulate and result in bad looking 'bumps' (or worse, the nozzle will collide with the part).<br />
<br />
The 'flow' module of IceSL takes care of this. It uses OpenGL rendering tricks and follows the path with the virtual equivalent of a marker. Only, in each pixel it counts how much color (plastic, really) is deposited. If this amounts exceeds the target, it tunes down the extrusion rate so has to avoid overflow. This works quite well in practice! I believe this could also be used for SLA / laser engraving where 'beam energy' can also accumulate more than desired (the beam footprint is not an exact dot, but rather a small circle).<br />
<br />
The two images at the end of the post show a slice before flow optimization, and the same afterwards. The grayscale levels indicate a reduction of the plastic flow ; they are especially visible in the thin areas (you might have to zoom in to appreciate the changes.<br />
<br />
Now is this the best way to do this? Possibly not ; geometry analysis of the path thicknesses could be faster than the brute force GPU approach -- which is also quite approximate.<br />
<br />
I am currently exploring better ways to limit gaps and overflows in IceSL. Stay tuned!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz5KhYmHtj8ZAXtygkUuzpKzze8g1R7F_Ryeb1ZasX3PI4RHot8jd2lQBJND4UGjSZlFY2z9WlwunAQTNmL9_Jn1GmZH5yGqj54NzD3qAv_xeGT-pp0qzGvf-dOqfE8WW1O-lX2kCiSdU/s1600/rt_037_1_before.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz5KhYmHtj8ZAXtygkUuzpKzze8g1R7F_Ryeb1ZasX3PI4RHot8jd2lQBJND4UGjSZlFY2z9WlwunAQTNmL9_Jn1GmZH5yGqj54NzD3qAv_xeGT-pp0qzGvf-dOqfE8WW1O-lX2kCiSdU/s640/rt_037_1_before.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_zQ6SnpBxMHCcYEidr_fqgo0HpSAWt40Jaleb3AC4qKO703Bwk73GLwhrGD3LisRLCeTjL_b5n52DwHfcfcmfMIUoWyrzdBtpRQhPCbwIlZv6EBBJLzd4xdbe3eFrO-MkumJ3CWdHSgI/s1600/rt_037_1_before.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRsEfC8uWDTPnoPIFtZNoN0_PqaLB1ohNCciuA17LkS6rejSrIbnoMAdnsFxVLcb6_yVEOsjkeeDBIcXKawnZ80ovpwOw5jHgbaIWfQ7IwNxiZr2D1vca1fQMlCcwD5ZZxxZUKJm_-dNk/s1600/rt_037_2_after.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRsEfC8uWDTPnoPIFtZNoN0_PqaLB1ohNCciuA17LkS6rejSrIbnoMAdnsFxVLcb6_yVEOsjkeeDBIcXKawnZ80ovpwOw5jHgbaIWfQ7IwNxiZr2D1vca1fQMlCcwD5ZZxxZUKJm_-dNk/s640/rt_037_2_after.jpg" width="640" /></a></div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-63787091311176909562016-01-31T12:56:00.001-08:002016-01-31T12:56:22.241-08:00[icesl] Things to do with IceSL: Arcade bartop!After an exciting but somewhat stressful SIGGRAPH deadline I allowed myself a little fun and decided to use IceSL to model and laser cut (and 3D print) a complete Arcade bartop :-)<br />
<br />
Here is the design in IceSL:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMESDDHxuMqvaURyPlYr8nEbuIEQkSE5tr3-Dvll0R85YkcFVZIcPrv6G29Oh91CXEcyKBzeOxRDK3KOhjVjEJLlC71cjzf8GIt8R0DmoHt-xOr56O1LzGbZBC_6Pmg8V9_J9lrx138jo/s1600/icesl1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMESDDHxuMqvaURyPlYr8nEbuIEQkSE5tr3-Dvll0R85YkcFVZIcPrv6G29Oh91CXEcyKBzeOxRDK3KOhjVjEJLlC71cjzf8GIt8R0DmoHt-xOr56O1LzGbZBC_6Pmg8V9_J9lrx138jo/s640/icesl1.jpg" width="770" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
Of course it is fully parametric! It can easily be adapted to screens of different sizes, other joysticks and buttons. The bartop is quite small, I wanted something that would nicely fit on a table and not look bulky. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is a transparent 3D view and an exploded view in IceSL:</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBALke7TxYLTha_pAn56HA8jV3J0trBjG_5qHd-D2UepPg9EuJpC2ACUc8COgeZTmA0WUN_ZPcWIR4-72J8cCJ_8PLu4KbIOmavlVBZFONyYLzqkkHnFpJh7LeZlb2EIJ6b7ObBax_Rqg/s1600/icesl1-3d.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBALke7TxYLTha_pAn56HA8jV3J0trBjG_5qHd-D2UepPg9EuJpC2ACUc8COgeZTmA0WUN_ZPcWIR4-72J8cCJ_8PLu4KbIOmavlVBZFONyYLzqkkHnFpJh7LeZlb2EIJ6b7ObBax_Rqg/s320/icesl1-3d.jpg" width="285" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwQ7N_V4ETzwy-CVsnnmt1Fh_8fq-DOFjCsKX_VKazxyt5rvycUKlIHHwb6tZYglLg1Tb_ijRiWbHrB466NkukEZTG-Zey5SuvqfX9X6dxV-km-cjlsFnYh2HSO2rulHhnh51eBilURLQ/s1600/icesl2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwQ7N_V4ETzwy-CVsnnmt1Fh_8fq-DOFjCsKX_VKazxyt5rvycUKlIHHwb6tZYglLg1Tb_ijRiWbHrB466NkukEZTG-Zey5SuvqfX9X6dxV-km-cjlsFnYh2HSO2rulHhnh51eBilURLQ/s320/icesl2.jpg" width="292" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And the final result! </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYpgzxADyWQnOFc2p00Klh75zprTF9sagqr9L2JfH0C6z6ysZF16c-BWzBSUqtRzlzJDwhFxLMC7pGlSUR5_g-e67Zf_tsVTYRspvvwJRc1DlUT4FKfqWf2u_-ynVRZjwl4o8Cl6_d9aA/s1600/P1020298.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYpgzxADyWQnOFc2p00Klh75zprTF9sagqr9L2JfH0C6z6ysZF16c-BWzBSUqtRzlzJDwhFxLMC7pGlSUR5_g-e67Zf_tsVTYRspvvwJRc1DlUT4FKfqWf2u_-ynVRZjwl4o8Cl6_d9aA/s320/P1020298.JPG" width="273" /></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8z2zalnPfOWpsCC6seqbVN7zx_g-sOtp7qmk6EFy6qN5RkDBSKJVtMN_rEWUim8xU0UcAkvxEiDAnZ579_6xRfQYgv9dHiLt9MlkGvOzqGXogkqyO8ADS3yX-NEN_wowH-rc70MmDu-E/s1600/P1020303.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8z2zalnPfOWpsCC6seqbVN7zx_g-sOtp7qmk6EFy6qN5RkDBSKJVtMN_rEWUim8xU0UcAkvxEiDAnZ579_6xRfQYgv9dHiLt9MlkGvOzqGXogkqyO8ADS3yX-NEN_wowH-rc70MmDu-E/s320/P1020303.JPG" width="275" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
All parts are laser cut using G-code produced by IceSL, using the 'laser' profile (gcode is sent to a <a href="http://smoothieware.org/smoothieboard">smoothieboard</a> driven CO2 laser cutter). This is using 3 mm plywood. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The insides of the 'beast':</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBe9xJKWcZm60hh8JzVDztYT3IX7g118vFrXWvDZSvTO34IzQhnnzIHIwk3ajOWAgDqmOXjSMo7NRDE6xTmNXO7nkIRB9yz-CcZmR0bu3H4DZo6mld43pmiwkJ0WYQM1bz11HYT4b2JKs/s1600/P1020305.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBe9xJKWcZm60hh8JzVDztYT3IX7g118vFrXWvDZSvTO34IzQhnnzIHIwk3ajOWAgDqmOXjSMo7NRDE6xTmNXO7nkIRB9yz-CcZmR0bu3H4DZo6mld43pmiwkJ0WYQM1bz11HYT4b2JKs/s320/P1020305.JPG" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1pdIXarAD9xOYXdNyqi8YCBNmsVrdVd3Xp4A193Fuu8ARBLaV0zZAdrnTWHfXb7SW-H74dDxuUqAhjRFGhYuKoj1EBOqX2b2RJHXxp3hcP6LXP4fvOzUCgMmGXPYrE27qQg5q0I23v0A/s1600/P1020309.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1pdIXarAD9xOYXdNyqi8YCBNmsVrdVd3Xp4A193Fuu8ARBLaV0zZAdrnTWHfXb7SW-H74dDxuUqAhjRFGhYuKoj1EBOqX2b2RJHXxp3hcP6LXP4fvOzUCgMmGXPYrE27qQg5q0I23v0A/s320/P1020309.JPG" /></a></div>
<span id="goog_268471013"></span><span id="goog_268471014"></span><br />
<span id="goog_268471013">This is of course powered by a Raspberry Pi 2, running <a href="http://blog.petrockblock.com/retropie/">RetroPie.</a></span> I went for Sanwa hardware ; no regrets, the buttons and joystick are indeed super nice. I use a small USB pad emulator board to plug the joystick and buttons -- but it seems GPIO pins could be used as well. <span id="goog_268471013">The screen is a HDMI TFT panel, size 10.1 (ref LP101WH1),
which has a reasonable resolution of 1366x768 -- but there are many
other models out there, I picked this one based on price/availability. </span><span id="goog_268471013"><span id="goog_268471013">For the sound </span>I took apart a pair of Logitech Z130 speakers (50mm diameter, fits nicely).</span><br />
<span id="goog_268471013"><br /></span>
<span id="goog_268471013">I learned quite a few lessons building this. The 3D preview in IceSL has been incredibly useful, as well as the ability to interactively move things around. I used 3D models of all electronics so that I could check for a proper layout and avoid collisions between the different parts. Nevertheless, I got a few things wrong mostly because I did not model the plugs (USB, HDMI, power) and these take *a lot* of space. This is the second prototype I made, the first one had a few issues and required some manual work to adjust. This one was taken right out of the cutter bed and assembled without requiring any drilling or gluing (everything tightly fits together).</span><br />
<br />
<span id="goog_268471013">I model all planks in their cutting position (thickness along Z), and define for each a transform to place it in the final 3D model. For instance the pad board is named 'pad_board' and its transform is 'pad_board_T' (just a matrix). To cut the board I use 'emit(</span><span id="goog_268471013"> pad_board )', whereas to display it in the final model I used 'emit( </span><span id="goog_268471013"><span id="goog_268471013">pad_board_T * </span></span><span id="goog_268471013"><span id="goog_268471013"><span id="goog_268471013">pad_board</span></span> )'. </span><br />
<br />
<span id="goog_268471013">To create the finger joints I model only one side on one board and then use the following trick, e.g. between the left side board and the floor board:</span><br />
<br />
<span id="goog_268471013">side_L_board = difference( </span><span id="goog_268471013">side_L_board</span><span id="goog_268471013"> , inverse(</span><span id="goog_268471013"><span id="goog_268471013">side_L_board</span>_T) * floor_board_T * floor_board )</span><br />
<br />
If you are not familiar with 3D matrices and transforms this may be a bit tricky to understand. <span id="goog_268471013">'</span><span id="goog_268471013"><span id="goog_268471013">side_L_board</span>_T'</span> is the transform (matrix) that puts the side board in position in the final model. Thus, <span id="goog_268471013">inverse(</span><span id="goog_268471013"><span id="goog_268471013">side_L_board</span>_T) is the matrix that moves everything back to the side board cutting space ; as if the entire final model was rotated to lie on the left side. Thus, writing '</span><span id="goog_268471013"><span id="goog_268471013">inverse(</span><span id="goog_268471013"><span id="goog_268471013">side_L_board</span>_T) * floor_board_T * floor_board' means that the floor board is first placed in the final model (by matrix </span></span><span id="goog_268471013"><span id="goog_268471013">floor_board_T) and then rotated back to the side (by matrix </span></span><span id="goog_268471013">inverse(</span><span id="goog_268471013"><span id="goog_268471013">side_L_board</span>_T) ). This is when I subtract the floor board from </span><span id="goog_268471013"><span id="goog_268471013">the side board</span>. This effectively carves the connectors (from the floor board) out of the side board. By following this method you can easily model all connectors while being sure they will match. Another example of the power of CSG :-)</span><br />
<span id="goog_268471013"></span><br />
<span id="goog_268471013">I still have a few things to add to finalize the bartop: external USB/Ethernet plugs, and most importantly an independent power supply (it requires three power plugs!) and of course paint and stickers. But for now, let's play some retro-games!</span><br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-57726328957784045742015-07-28T14:55:00.000-07:002015-07-29T01:50:02.452-07:00[3dprint] 3d infilling: faster, stronger, simpler<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="margin-left: 1em; margin-right: 1em;">
</div>
<br />
<img alt="" height="311" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4SU8RXhpZgAASUkqAAgAAAAMAAABBAABAAAAwAwAAAEBBAABAAAAkAkAAA8BAgAIAAAAngAAABABAgAJAAAApgAAABIBAwABAAAAAQAAABoBBQABAAAA0gAAABsBBQABAAAA2gAAACgBAwABAAAAAgAAADEBAgANAAAAsAAAADIBAgAUAAAAvgAAABMCAwABAAAAAQAAAGmHBAABAAAA4gAAAD4TAABTQU1TVU5HAEdULU43MTAwAABONzEwMFhYVUZORTEAADIwMTU6MDc6MjggMjI6NDI6NTYASAAAAAEAAABIAAAAAQAAABsAmoIFAAEAAAAsAgAAnYIFAAEAAAA0AgAAIogDAAEAAAADAAAAJ4gDAAEAAADiBAAAAJAHAAQAAAAwMjIwA5ACABQAAAA8AgAABJACABQAAABQAgAAAZEHAAQAAAABAgMAAZIKAAEAAABkAgAAApIFAAEAAABsAgAAA5IKAAEAAAB0AgAABJIKAAEAAAB8AgAABZIFAAEAAACEAgAAB5IDAAEAAAACAAAACZIDAAEAAAAAAAAACpIFAAEAAACMAgAAfJIHAGIAAAC+EgAAhpIHAAgQAACUAgAAAKAHAAQAAAAwMTAwAaADAAEAAAABAAAAAqAEAAEAAACQCQAAA6AEAAEAAADADAAABaAEAAEAAAAgEwAAAqQDAAEAAAAAAAAAA6QDAAEAAAAAAAAABqQDAAEAAAAAAAAAIKQCACEAAACcEgAAAAAAAAEAAAARAAAAGgAAAAoAAAAyMDE1OjA3OjI4IDIyOjQyOjU2ADIwMTU6MDc6MjggMjI6NDI6NTYADwQAAAABAAAUAQAAZAAAAC/+//8AAQAAAAAAAAoAAAAUAQAAZAAAACUAAAAKAAAAQVNDSUkAAAAS+A87AAAAAHEEAAAAAAAADwQAAC/+//8RAAAAAQA0EnhWNBJ4VjQSeFY0EgAAAAAAADAAYADDLREA6AQQCgAACwAAAP//fHJoAAAAAACEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP39AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQwBBAEwAR0tGSTAzAAAAAEN1ci5HS0ZKMDNDTUwAMDE4MDAxMDAxNTA5MDAyOTAxMDkwNTAyMDEwRDAxMEQwMTI0MDk2NxLvBQAAAwAjEusmAAAEAAAAAFQAVQBOAEEAAwDQAg8E6QfJA8n+CHcBAAAAAQBGjAIAr3gBAGN0///uEgAAnc7//3pBAQDp7///nxQAAIg4///ZsgEAAABGTEZMAQBTVk4jDQFnCQAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArgAAAAAA0AIPBOkH9gPJ/sn+9gMJFQUAOQlRCQAAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHS0ewAAAAAAAAAAAADIAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1AAYAPAD/AOoAAAAAAAAAAAAAAAAAOwH5/w0BCQEAAQABWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpLSksCBXYLAQCc/gAAeXIAADKIAADCCwIAAAABAEKFAQABAAAAAA8EAADpBwAAyf7/AAAAAAAAAACZbAEAAAABANJ8AgAIdwEAAAABAEaMAgCveAEAY3T//+4SAACdzv//ekEBAOnv//+fFAAAiDj//9myAQBKS0pLcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgCBmQkAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgCBmQkAgpkJAIKZCQCCmQkAgZkJAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgZkJAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHCZCQBxZgYAcWYGAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCBmQkAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCBmQkAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAHFmBgBxZgYAcWYGAHFVBQBxZgYAcWYGAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQBxZgYAcWYGAHFVBQBxVQUAcWYGAHFmBgCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAcWYGAHFVBQBxVQUAcVUFAHFmBgBxZgYAgZkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAcWYGAHFVBQBxVQUAcVUFAHFVBQBxZgYAcWYGAHFmBgCCmQkAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAcWYGAHFVBQBxVQUAcVUFAHFVBQBxVQUAcWYGAHFmBgBxZgYAgpkJAIKZCQCCmQkAgpkJAIKZCQCCmQkAgZkJAHFVBQBxVQUAcVUFAHFVBQBxVQUAcVUFAHFmBgBxZgYAcWYGAIKZCQCCmQkAgpkJAIKZCQCCmQkAcVUFAHFVBQBxVQUAcVUFAHFVBQBxVQUAcVUFAHFVBQBxZgYAcWYGAHFmBgCBmQkAgZkJAHFmBgBxZgYAcWYGAHFmBgBxVQUAcVUFAHFVBQBxVQUAcVUFAHFVBQBxVQUAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFmBgBxZgYAcWYGAHFVBQBxVQUAcVUFAHFVBQBxVQUAcVUFAEpLSksAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMXAEA/P8AAJLIAgCjdAEABgABAKVXAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYbAEA//8AANB8AgCYbAEA//8AANB8AgCYbAEA//8AANB8AgCYbAEA//8AANB8AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApAEFGQUYCAP//yP4pAAAA9gMBAAIA+qMBAAAAKZsFAAIAldcFAAAA578UAAIA2eoUAAAAyMEoAAMA2CUoAAAAbM03AAMA1E03AAAA09BGAAMACXdGAAAADNhaAAMAWqtaAAAAI+RuAAQAIQVuAAAAMPWCAAQAWVqCAAEAFgiWAAQANLmWAAEAZRy0AAUA5XS0AAEATUjSAAcAJw/SAAEAOpjwAAgAhMzwAAEAhvP6AAgA5m36AAEA0Oj+AAgAiDv+AAEAtNjI/ggAhMz8AAcAqLUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBRkFGAgBHAEdLMADsAGQFQUZBRhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADesPSAAAAAAA0ABAAGAAMAIAoAAAMAWA0ApHgfAFK8DwAp3gcAKd4HABRzDwAUcw8AXCYFusazAAA2bgFXAwAAVwMAAAAABAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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" width="320" /><br />
Sparsity: 80% empty (compared to volume of full cube)<br />
Strenght: I applied 90 kg on each face and it remained perfectly rigid (cube is 40x40 mm).<br />
<br />
We are working hard on the next release of IceSL.One thing I really wanted to improve are the infill patterns. The 'sine wave' patterns we are currently using look fancy, but they have a number of severe drawbacks ; one of them is resonance on less robust printers, and another is a slow print time.<br />
<br />
I have been thinking about this for some time now. What I wanted was: 1) something rigid (obviously!) 2) something that prints quickly 3) something that prints without putting stress on the printer and 4) something easy and fast to compute.<br />
<br />
These requirements are quite high.<br />
<br />
Regarding rigidity, I dislike that most infill patterns are simple extrusions along z. What is really called for is a pattern forming 3D cells inside the volume for maximum rigidity (side note: I just found about slic3r <a href="https://github.com/alexrj/Slic3r/issues/1646">3d honeycomb</a> while writing this post, these look great ; there may be more prior work as I haven't checked in details yet - please comment if you know some).<br />
<br />
Printing fast essentially means going along diagonals in straight lines - something IceSL doesn't do well currently. Avoiding stress on the printer also means moving as much as possible along straight lines (no vibrations, constant speed, constant pressure in nozzle). Unfortunately anything fancy (such as 3d honeycomb) quickly leads to some turns and broken lines. Finding out something simple and fast to compute just makes it harder.<b> </b><br />
<br />
<b>The idea. </b>More than just a specific infill, this is a general way to build simple and fast to print 3D infills. Let me warn you this is, indeed, very simple (once understood) -- but I am unaware of anything like that in the slicers I know.<br />
<br />
The initial intuition was to consider the walls of a regular axis aligned 3D grid. Now, we do not want that, because the horizontal planes would create flat surfaces. So, one possibility is to rotate the entire grid so that the diagonal of the cubic cells align with the z (up) direction. Take one slice through this rotated grid. The intersection is a pattern made of straight lines -- so that seems promising. At first sight, this also seems tricky to compute: the lines have to follow a very specific pattern and meet exactly at the right locations to form the 3D cells.<br />
<br />
Well, it turns out this is in fact trivial. What is a regular grid? It is defined as the intersection of three sets of equally spaced parallel planes; the three sets having non-coplanar normals. In 2D, for instance, draw two sets of parallel lines: this forms a regular subdivision. You can even define coordinates in this grid by numbering the spaces between the sets of lines (planes in 3D).<br />
<br />
There is no need to worry about the exact position of the planes: when you draw two sets of parallel lines on paper they <b>always </b>form a proper grid (as long as the two sets are not parallel). What this means is that we can easily produce an infill generating <b>closed 3D cells</b> simply by printing three independent sets of parallel planes!<br />
<br />
<b>This gets even better</b>. In a slice each set of planes becomes a set of parallel 2D lines (see top of the print in image). Whenever we go up by one slice the position of the lines have to shift: each line is the intersection of a slice and a slanted plane in 3D. This can clearly be seen on the sides of the print, in the image above. What this means is that you can produce an infill forming 3D cells simply by tracing three independent sets of parallel lines in each slice! It suffices to make sure the lines shift correctly from one slice to the next, which is absolutely trivial to do.<br />
<br />
For the initial tests I chose 2D lines which are angled at 0, 45 and 135 degrees so that 2 lines over 3 print diagonally (speed). The lines shift from one slice to the next to produce a 45 degree angle in 3D. All of this is easily controllable, the angle and spacing may vary for each direction and even between planes of a same set. More than three sets can be used to form more complex subdivisions.<br />
<br />
The first prototype was coded in less than 10 minutes (!). Count on it for the next release of IceSL!<br />
<br />
(Edit: if you include similar infills in your slicer, please cite this blog post, in the spirit of the CC BY license. Enjoy!)<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3830350392070277486.post-40594591737681908532015-03-18T14:07:00.000-07:002015-03-18T14:10:27.990-07:00[3dprint] New version of IceSLWe just released a new version of IceSL! Discover unique features such as implicit surfaces, print brushes, and slice shaders here: <a href="http://www.loria.fr/~slefebvr/icesl/">http://www.loria.fr/~slefebvr/icesl/ </a><br />
<br />
<br />
We now provide an installation package (Windows only) and IceSL will check automatically for updates!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-44573566483349327822014-09-10T00:16:00.000-07:002014-09-10T00:16:22.199-07:00[3dprint] IceSL Alpha 5_4We just released a new version of <a href="http://webloria.loria.fr/~slefebvr/icesl/">IceSL</a> (5_4).<br />
<br />
IceSL now runs on most OpenGL 4.2+ hardware (NVidia, AMD, Intel HD). The release fixes a number of issues; here is the change log:<br />
<ul>
<li> Improved dense infilling (no gaps)</li>
<li> Added support for SVG (see <a href="http://webloria.loria.fr/%7Eslefebvr/icesl/icesl-manual.pdf">manual</a>).</li>
<li> Fixed bug with save/load of '.ice' format when the scene contains scripts.</li>
<li> Improved cutting tool.</li>
<li> An on-screen message is now displayed when the view cannot be rendered (inside object box).</li>
<li>Fixed a rare bug producing a wrong bounding box for the object.</li>
<li>Fixed a rare bug creating an invalid skirt.</li>
</ul>
Join us on the <a href="https://groups.google.com/forum/#!forum/icesl">Google Group to discuss IceSL</a>!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-80818976746064009262014-05-27T11:03:00.000-07:002014-05-27T11:03:44.224-07:00[3dprint] adaptive slicing and color mixSome more thoughts on color mixing... One obvious thing to do is simply to <a href="http://web.iitd.ac.in/~pmpandey/RP_html_pdf/slice_review.pdf">slice adaptively</a>, switching colors between layers. For instance, to get 70% of black and 30% of white, simply slice a 0.07 layer of black and then a 0.03 layer of white (thickness to be scaled depending on desired layer height). That is trivial to do in most slicers. Of course, to generate a spatially varying pattern in XY you need to change the slicing heights within the slice (in the XY plane), but this has been <a href="http://www.sciencedirect.com/science/article/pii/S0010448599000330">proposed before</a> and does not seem too difficult to implement.<br />
<br />
... maybe I should just try that!<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-35198355251772044442014-04-21T11:51:00.003-07:002014-04-21T11:51:58.575-07:00[3dprint] More gradient examplesTwo more examples of filament gradients. The slope -- in particular in overhang regions -- slightly changes the perceived color. The first model uses a linear ramp, while the second model uses a sine wave along the Z direction. I started experimenting with gradients along XY, first tests look promising.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieAein_CTdeI99ithNNpcG6VkTJw-LwCybnjaum_SRbEHycDrioavWL-5u2Lq-PfmP9mvH9rA5KJQjVVtERiPIBMdHhaLP-Wtmge-PJFhM1cMZu8SzXBuhWp6EY566MxtfbdP4-t_FwJY/s1600/kitten1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieAein_CTdeI99ithNNpcG6VkTJw-LwCybnjaum_SRbEHycDrioavWL-5u2Lq-PfmP9mvH9rA5KJQjVVtERiPIBMdHhaLP-Wtmge-PJFhM1cMZu8SzXBuhWp6EY566MxtfbdP4-t_FwJY/s1600/kitten1.jpg" height="320" width="233" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUAnyjVUS4uHclRXXSYXzKd9AVvIPR-kGiKiONOPgUQdiuTqbueNCuMIgv97_jtIeGuXRv5Bi_KwFxQ6lhUCnbx4j4q59HZLV06I5W49PeKB2RowYwNBKL3yplopmq87y2Z1ZTHTfI3I0/s1600/kitten2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUAnyjVUS4uHclRXXSYXzKd9AVvIPR-kGiKiONOPgUQdiuTqbueNCuMIgv97_jtIeGuXRv5Bi_KwFxQ6lhUCnbx4j4q59HZLV06I5W49PeKB2RowYwNBKL3yplopmq87y2Z1ZTHTfI3I0/s1600/kitten2.jpg" height="320" width="221" /></a></div>
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3830350392070277486.post-31769019275320220442014-04-12T04:18:00.000-07:002014-04-12T04:18:18.082-07:00[3dprint] filament gradientsI have been working on a way to blend two filaments together to achieve smooth gradients along a print surface. It is not perfect yet, but here is a brief description of this idea.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhAWt-WWZBW_pBmTEsSp5xe_YKSXlbXI7H2ESXsh20XygxR1H5jzuPMWRp9Tm9Wv8x5bU1oPHKKKN0XoSrsQQ59_mGcWcQAS4zh_vxCaNzhLCHp2z1w9fv-ywswXjvTdETzd1P6e-lr4A/s1600/blend.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhAWt-WWZBW_pBmTEsSp5xe_YKSXlbXI7H2ESXsh20XygxR1H5jzuPMWRp9Tm9Wv8x5bU1oPHKKKN0XoSrsQQ59_mGcWcQAS4zh_vxCaNzhLCHp2z1w9fv-ywswXjvTdETzd1P6e-lr4A/s1600/blend.jpg" height="200" width="130" /></a></div>
<br />
When working on our <a href="http://webloria.loria.fr/~jhergel/cleanColor.pdf">'clean colors</a>' technique, we made the observation that alternating layers of two filaments would produce different gradients of colors along the sides of the object. What happens is that the filament closer to the observer has more impact visually, than the one slightly behind. Interestingly, <a href="http://cg.ivd.kit.edu/publications/2014/DCM/DualColorMixing.pdf">this paper</a> made the exact same observation and came up with a very interesting way of depositing filaments to mix colors.<br />
<br />
Starting from the same observation I came up with a different idea. Instead of changing the geometry I play with the flow of plastic. I do not alternate filament each layer but instead, at each layer, I deposit plastic twice (once for each filament) with a different flow of plastic. The two flows add up to 100% and by changing the percentage of each deposition you get different blends of colors. It is important though to always start by the filament having the highest percentage. What happens is that you get 'big' and 'small' cross sections of filament. And of course, the big one becomes more visible.<br />
<br />
This works quite well and has interesting properties:<br />
- the layer height is unchanged<br />
- there is no change to the geometry of the print<br />
The main drawback is that this requires carefull calibration to align the heads. This can be done in software by printing calibration tests. I have done initial experiments with spatial variations, but I yet have to explore this further. I am also curious to see what happens when doing this with soft/hard filaments and filaments of different properties.<br />
<br />
If you experiment with this please let me know! If that works well enough we will include this feature in <a href="http://webloria.loria.fr/~slefebvr/icesl/">IceSL</a>.<br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3830350392070277486.post-74884618360297840582013-06-22T02:02:00.002-07:002013-06-22T02:08:34.190-07:00[3dprint] new CURA engineI just had a look at the new CURA engine code:<br />
<a href="https://github.com/Ultimaker/CuraEngine">https://github.com/Ultimaker/CuraEngine</a><br />
<br />
Nice, elegant C++ implementation. Internally it relies on <a href="http://www.angusj.com/delphi/clipper.php">Clipper</a>, a fast library to perform operations on 2D polygons. That is an excellent choice: Intersecting each 3D triangle with the slice plane produces a bunch of segments. The segments are then linked back together to form polylines and 2D polygons. The Clipper library is used to compute polygon offsets, creating the perimeter and shells.<br />
<br />
Now I have to work hard to make IceSL as fast :) There are quite a few places where large speed ups are possible, so we'll see.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-71293143628012254222013-06-17T09:57:00.003-07:002013-06-17T09:57:37.061-07:00[3dprint] IceSL: Model, slice and print without intermediate meshes<b>Short story: </b>Model objects through a CSG language inspired by OpenSCAD but based on LUA with real time pixel-perfect CSG (with transparency) and direct slicing. Yes, this is both the modeler and slicer in a same package - no output mesh, only G-code. Small catch: you need a recent NVidia GPU (supporting OpenGL 4.2 ; Series 4 or above).<br />
<br />
<b>Download:</b><br />
<br />
<a href="http://webloria.loria.fr/~slefebvr/icesl/">http://webloria.loria.fr/~slefebvr/icesl/</a><br />
<br />
<b>Long story: </b>When I first discovered hobbyist 3D printing thanks to the great community around RepRap and derivatives, I was looking forward to modeling and printing my first objects. What's more, I had heard about <a href="http://www.openscad.org/">OpenSCAD</a>, where shapes are described by CSG operations between meshes and basic primitives. CSG (Constructive Solid Geometry) is good for modeling solids, because instead of worrying about a surface mesh you can focus on adding and subtracting matter. Modeling through scripting is also very efficient (reuse) and well suited to describe mechanical parts. It seems <a href="http://www.makerbot.com/blog/tag/customizer/">Makerbot</a> and <a href="http://www.thingiverse.com/">Thingiverse </a>users largely agree.<br />
<br />
However, what surprised me is how difficult the whole process was: The real-time rendering of OpenSCAD does not always succeed -- fast CSG display with basic OpenGL is no simple matter -- and sometimes the shape displayed on screen is very different from what it should be. When hitting the "Compile mesh" button you have to wait for a very long time before getting the final mesh. This is problematic since you are never quite sure that you positioned your shapes properly, unless waiting for minutes -- and it makes small trial-and-error adjustments tedious. In retrospect, this is to be expected: OpenSCAD is designed to produce very clean meshes and relies on <a href="http://www.cgal.org/philosophy.html">CGAL</a> to compute exact mesh-to-mesh intersections (in spite of numerical errors). This is a smart choice because it guarantees the quality of the output, at the price of more complex and time consuming algorithms, but that is the right way to go when meshes have to be produced.<br />
<br />
At the same time I was also stuck with another part of the process: The slicer. I mainly used Skeinforge through ReplicatorG. There are many, many settings which all make sense individually but are really scary for a beginner (which I am/was). Now, ReplicatorG does a great job at hiding things, but ultimately you want to dive deeper and tweak parameters. The result - for me - was lower print quality after hours of tweaking :-). Thus, I decided to look deeper into the problem and started implementing my own slicer to understand the intricacies of the process. I soon realized that the nice mesh computed by minutes of clever state-of-the-art CGAL algorithms in OpenSCAD was ultimately sliced into bits and pieces -- and in fact the large number of triangles only made matters worse when primitives such as cylinders or spheres were being used.<br />
<br />
The whole process now seemed a bit wrong: A lot of processing power and complex algorithms are devoted to generating a perfect mesh, but its quality is in fact a total overkill for the slicing that later takes place. So, ... do we <i>really</i> need this intermediate mesh? It turns out you <i>do not need to produce a mesh. Not at all: </i>not for display, not for slicing<i>. </i>IceSL is based on this principle: It is an alternative to OpenSCAD tailored specifically for additive manufacturing. It uses the same code path both for on screen rendering and slicing. And it is made fast by using just a little bit of GPU magic (note: obviously this also gives high requirement for the user - but I am doing research in hardcore graphics, right? ;-) ). This is only a first prototype of this idea: It is far from complete, far from optimized, and lacks many important features (infill patterns in particular, supports as well), but I hope you'll already enjoy the ability to quickly visualize your objects and the relatively fast slicing. IceSL can slice STL files ; it is relatively fast for this but not the fastest (not <i>yet</i> ;-) ). However, it is really fast when slicing CSG models: No need to generate the STL! What is intriguing is that the software, internally, never has to deal with triangles -- in fact, the source code does not even contain a triangle class (apart from what is required to load and send meshes to the GPU).<br />
<br />
The way it works is by first building a CSG description of the scene through a scripting language. For this I choose LUA, which is a very nice, easy to learn language. In fact, converting between OpenSCAD and the LUA scripts is not difficult at all -- I include a number of examples such as <a href="http://www.thingiverse.com/thing:3575">involute parametric gears</a>. It then relies on a real-time CSG rendering algorithm, which is reused during slicing. So what you see, truly is what you print. Now, after computing bitmaps for each slices the tool path is computed -- this part is more similar to other slicers as far as I can tell.<br />
<br />
It turns out my beginner's intuition was not exactly novel: I recently discovered that <a href="http://reprap.org/wiki/Mendel_User_Manual:_Host_Software#Using_CSG">RepRap Host</a> includes a similar strategy to directly slice from 'csg' files produced by OpenSCAD. As far as I can tell the main difference is that my pipeline relies on a single algorithm for display and slicing, and is therefore somewhat <i>simpler: </i>Meshes (as input) are treated as any other primitive. Btw, I recommend anyone interested in the topic to read through the code of <a href="https://github.com/reprap/host/tree/master/src/org/reprap">RepRap Host </a>(main author is <a href="http://adrianbowyer.net/">Adrian Bowyer</a>!). It is easy to read and the wiki does describe parts of the algorithm. It was great to read through it after doing my own, as I was happy to discover that for some parts I made similar choices (although I do not use marching squares for perimeters -- have to consider this). My code relies more heavily on the GPU and rasterization, but the basic principles remain similar. Another interesting prior work I recently discovered is <a href="http://www.sciencedirect.com/science/article/pii/S001044851100145X">this paper</a>. If you know of other works, please post a comment ; I'd like to get a good landscape of existing methods.<br />
<br />
Hope you'll find IceSL useful.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-75481912232511123542012-12-09T06:26:00.000-08:002012-12-09T06:26:16.117-08:00[3dprint] Joystick repairThis holiday season I decided we would play some of our Amiga favorite games, on the real Amiga!<br />
<br />
I had a hard time sourcing working joysticks, however I found a few that were broken. This particular one had a stick broken beyond repair and one destroyed microswitch. I decided to turn it into a 1-button joystick, and to rebuild it with a 3D printer :-)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL-z-haezuUrRaVCSLiHjcOYJPNjtYN4mquyJzBt6u-6eD1eREfru43xNKNqnAzwi8hcAuXxNAKx8rEKqwhXP3s1ra0h1rcTJxRE4eG1lDK_fd78hWSy7d14oAgK6JtO912Vo03dd3SCg/s1600/20121209_150549.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL-z-haezuUrRaVCSLiHjcOYJPNjtYN4mquyJzBt6u-6eD1eREfru43xNKNqnAzwi8hcAuXxNAKx8rEKqwhXP3s1ra0h1rcTJxRE4eG1lDK_fd78hWSy7d14oAgK6JtO912Vo03dd3SCg/s320/20121209_150549.jpg" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAnC5MJvp6TXI4tHeAsRPJvhwDhX-r0M3ydxa6BhL2woyc-ZqT1KscFCJJ0FMs-FYCc2d51PNxJqgfJteG1tJE44nh2O3dlxHjySbLT1Ws-8Qd4kGlAKpEtrvF61A3ZmgzTb6K7qNzO4/s1600/20121209_151015.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrAnC5MJvp6TXI4tHeAsRPJvhwDhX-r0M3ydxa6BhL2woyc-ZqT1KscFCJJ0FMs-FYCc2d51PNxJqgfJteG1tJE44nh2O3dlxHjySbLT1Ws-8Qd4kGlAKpEtrvF61A3ZmgzTb6K7qNzO4/s200/20121209_151015.jpg" width="150" /></a></div>
<br />
<br />
<br />
Here is the result. The final version is made of four pieces: the stick, the top button (articulated) and two pieces to fit the original screws. It was all printed using my own slicer on a Makerbor Replicator 1, with Sailfish firmware. The models were designed with Google Sketchup.<br />
<br />
The most difficult part was to get the original microswitch to fit, as well as to design the top button so that it would rotate properly and hit the switch in the right place. In the end it only required two prototype prints to get all measures right.<br />
<br />
It is not the most comfortable joystick, but it works reasonably well. I'll probably create another 2-button version with new microswitches.<br />
<br />
If you like this kind of repairs, check out the <a href="http://www.thingiverse.com/thing:30008">full joystick print</a> on Thingiverse!<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-49920166205544536032012-12-07T07:29:00.000-08:002012-12-07T07:29:54.065-08:00[3dprint] SlicerWhat's so special about this printout of <a href="http://www.thingiverse.com/thing:25644">thing #25644</a> ?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgopgNFUTAoWS0U-bIQ_kF_TY-ALbu8LbiEPvDJadMVDQdxj-QvfpzNqYxWjynrrOv16ZYpZLtFtXJj3K95wkncLpoe0oEIdg5dUtnxePWU4bNNVZE2UeSpzwMzrohgIXXdaN4_UprZ2w0/s1600/20121207_155724.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgopgNFUTAoWS0U-bIQ_kF_TY-ALbu8LbiEPvDJadMVDQdxj-QvfpzNqYxWjynrrOv16ZYpZLtFtXJj3K95wkncLpoe0oEIdg5dUtnxePWU4bNNVZE2UeSpzwMzrohgIXXdaN4_UprZ2w0/s320/20121207_155724.jpg" width="320" /></a></div>
<br />
It's been sliced with my own GPU-accelerated slicer :-)<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3830350392070277486.post-9095507493065664542011-12-14T05:52:00.000-08:002011-12-14T06:00:11.308-08:00[research] Coherent parallel hashingI just realized I never blogged about our coherent hashing paper! So don't miss it if you did not see the talk at SIGGRAPH Asia (which I am unfortunately not attending this year). The paper is <a href="http://www.ismaelgarcia.org/papers/cohash_siga2011/">here</a>. It will tell you how you can get both efficient storage of sparse data <span style="font-style: italic;">and</span> exploit access coherence at the same time -- something unusual for a spatial hashing scheme.<br /><br />Also, if you are interested in fast, parallel hashing do not miss the dissertation of <a href="http://idav.ucdavis.edu/%7Edfalcant/research.php">Dan Alcantara</a>: A great read for anyone interested in this topic.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-61582772185369741652011-09-16T06:52:00.000-07:002011-09-20T00:21:36.698-07:00[research] Producing resultsPublishing a paper is no easy task. First, you need a good piece of research -- of course, the most difficult, but largely compensated by the fun! Second, you need to produce a paper and often a video, demonstrating your results and comparing them with many other techniques, under a variety of situations.<br /><br />This is where things gets complicated.<br /><br />Often research code is a somewhat fragile unstable prototype, with a complex, hard to use GUI (by hard to use, I mean *impossible* to use by anyone but the one who implemented it!). Well, at least this has been the case more than once for me :) This is combined with a large set of parameters and optional features, many different data sets, and implementations of other methods -- sometimes your own implementation, sometimes the original code from other authors. While the later is better for the sake of fair comparisons, this also means different APIs, with different inputs/outputs -- possibly even different languages!<br /><br />And now, you have to make all this work together to produce figures and tables composed of thousands of data points. Well, good luck! And just to make things more interesting you can be sure to discover last minute bugs, or have your advisor decide to change a dataset, implying to redo all figures of the paper minutes before submission. (And no, it is not fine to resist 'because this will change everything in the paper').<br /><br />You probably recognize some of these situations. But things do not have to be painful. It just takes a few little tricks to avoid most trouble, even if all figures and tables of the paper -- and even the video -- have to be redone 2 minutes before submission. The answer?<br /><br />Scripting! ... done right.<br /><br />Research GUI's are great during development. It lets you tweak, test, debug interactively. However, such GUIs are really poor when it comes to generating results. Hence, your programs should <span style="font-weight: bold;">always</span> be able to produce <span style="font-weight: bold;">all </span>results from the command line without intervention.<br />If there are things to set up interactively, then there should be a way to <span style="font-weight: bold;">save </span>these parameters (viewpoint, background color, etc.) and load them <span style="font-weight: bold;">from the command line</span>. And don't tell me this is a lot of code. It takes a struct and a pair of fread/fwrite to do this. Sure, you could use serialization and persistance. But such nice designs mean less time on your research. So again, fwrite/fread is perfectly fine for this kind of preset parameters.<br /><br />Now I often hear "well, I would like to do that but the GUI is tightly coupled with the algorithm". Well, design 101: Do not mix the GUI with the algorithms, <span style="font-weight: bold;">never</span>. To make sure of this, start your prototype as a small library implementing core operations. Your GUI should be a separate code calling this library. This will force you to keep things separated. Then your command line application can simply be a different program calling the library. My advice is to do that from the start. It will cost you a lot to split things later, but much less to maintain a library/GUI split. And if you cannot maintain the split, something is wrong about your design. Btw, by 'library' I do not necessarily mean an actual '.so' or '.dll' -- even though that's probably a good idea. You can force yourself to have this split simply by including a single "core_library.h" header in your main.cpp, and nothing else. This header would only contain the interface to the core algorithm (a few functions, a class, etc.).<br /><br />Now you probably want to output images, performance numbers, framerates -- and come on, don't use <a href="http://www.fraps.com/">fraps </a>for this , please implement a FPS counter in your application (everything has to run from the command line with no intervention). Yes, this means waiting for FPS to stabilize before outputting it, but this is easy to do: Have your program wait for a few seconds before taking the data point. [Edit: ] As commented below, it is of course a good idea to double check with <a href="http://www.fraps.com/">fraps </a>(or other) that your FPS counter is not biased in any way.<br /><br />You also probably want to run many experiments, for varying settings. There are several options: Writing a program which directly runs all experiments and output the figure is <span style="font-weight: bold;">not</span> a good one. Any change to the figure layout will imply to rerun all experiments. If it takes 2 days, sorry. Similarly, if it crashes after 1.7 days (haha!), you'll lost all previous measurements.<br />I always find it much better to write a simple program running a single experiment, and then call it from an easy scripting language (pick your favorite, I use python these days).<br />And, please, we all know things will crash. So make sure your script will not hang when this happens. If you are under windows and have the 'Debug / Close program' dialog box, <a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/07/27/198410.aspx">it can be disabled</a>. So, really, no excuse. After producing data for all experiments, a second script parses it and produces figures.<br /><br />Now, how to output the actual data? First, whatever you do, output files in a separate 'results' directory. Nobody wants to mix a thousand temporary files with their source code. Also, it will help packaging and saving old results. One way to output values and file names (files being dumped into the results directory) is to write it all in a text file. This seems like simple, but this also means later parsing the file to extract numbers and produce a figure. And, parsing is much harder than dumping data. Plus, we have amazing tools to address this nowadays. One such tool is XML, another -- my favorite for this -- is <a href="http://www.sqlite.org/">sqlite</a>.<br /><br />Typically, my programs dump experiment results in a same database, starting each line with the date--time of the experiment, the program being called, the input data set, the parameters that were used, and then the measurements. From python you can easily open the sqlite database and produce a figure with <a href="http://matplotlib.sourceforge.net/">matplotlib</a>. But many other scripting languages can do that. Again all this takes is a small numbers of straightforward code lines. It is generally a good idea to separate the script running the experiments from the script generating the figures from these data points.<br /><br />Now, let's look at what we have: From a single command line script we can regenerate all images, figures, data tables (tex files). Something changed in the code? Just rerun. Need to change the layout of figures? Fix it and rerun the figure scripts. Something no longer running as expected? Search in the database for earlier results. Compare to the previous situation: Launching a GUI interface, manipulating widgets, and manually writing down numbers. The savings are in tens of hours, notwithstanding that you avoid all potential errors due to late working nights.<br /><br />Sounds great! But wait, sometimes we need to make measurements of things that change over time. For instance, measuring texture streaming performance as we move in a scene, or recording a piece of video of a real time rendered scene. This can be scripted too, and very easily. All the basic operations done in your application should correspond to simple function calls: load an object, set a parameter, load a camera path, play a camera path, etc. From there, you can very easily write your own script language: simple orders written in an easy to parse<br />text file. In your code, create a thread which parses this file and executes orders one by one. Better: use <a href="http://www.lua.org/">lua </a>/ <a href="http://www.rasterbar.com/products/luabind.html">luabind </a>(really simple!), and execute the lua script from a new thread.<br /><br />The script can look like:<br /><br /> open('bunny.obj')<br /> setview('fig1.camera')<br /> setparam('shadow',1)<br /> setlight(10.0,2.0,5.0)<br /> screenshot('fig1.png')<br /> loadpath('pathseq1.path')<br /> setscreenshotperiod(1.0,'seq1%d.tga')<br /> playpath()<br /> exit()<br /><br />This will take a screenshot and then play a path going around your model, saving a screenshot every second. Such scripts can also remove the need for other command line parameters: Simply load a script and it will do what is necessary. Because the script is in a separate thread it can wait, loop, walk along a path, without slowing down the main thread.<br /><br />This may seem a lot, but is very easy to implement with boost::thread and lua. Only potential trouble is thread safety, and (if applicable) threading mixed with OpenGL. I found that the easiest way to go is to have a command queue shared between the main thread and the scripting thread. The scripting thread simply pushes commands, while the main thread, at every frame, executes all commands on the queue (loading textures, changing viewpoint, etc.). Only the queue needs to be locked.<br /><br />Doubtful? Check out the<a href="http://www-sop.inria.fr/reves/Basilic/2008/DLTD08/LazySyn_EGSR_Video_DivX.avi"> video of our 2008 paper</a> 'Lazy solid texture synthesis'. Most of the video runs as a real time scripted application, including the 'cutting' scenes. There I even used <a href="http://msdn.microsoft.com/en-us/library/ms723627%28v=vs.85%29.aspx">MS SAPI</a> to have the script talk and get the timing of the sequences right. Did it take a lot of time? Quite the contrary: This is the least painful video I ever produced for a paper.<br /><br />A final word of advice: Do not wait, apply scripting right from the start. The first measurement your program outputs should be in a sqlite database. If you do not do it from the start, it will be harder to switch ('just a last experiment, I'll do it afterwards'), and the overall benefit will be reduced. Even if each experiment is fast (30 seconds), running a lot of them takes time. Even if all experiments run in seconds, scripting will avoid many mistakes. You are always better of with a script. A warning though: keep things simple, do not overdo this idea. The scripting 'engine' should serve only your purpose for the project, no more.<br /><br />That's it. Hope you found a few useful things in there!Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-3830350392070277486.post-39882808910912819122011-06-22T05:25:00.000-07:002011-06-22T05:27:01.059-07:00[latex] Math in algorithmsI am using the algorithmic package to add code in my latex documents. I came across the following issue: How to include math in the code? Simple solution:<br /><br />\begin{lstlisting}[mathescape]<br /><br />Thanks to <a href="http://stackoverflow.com/questions/2809836/latex-math-symbols-in-listings">http://stackoverflow.com/questions/2809836/latex-math-symbols-in-listings</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-91058107930369641392011-04-12T03:10:00.001-07:002011-04-12T04:40:44.061-07:00[devel] Bumping into wallsIf you are developing games, you have probably already been faced with this issue: How to make characters nicely slide against the walls?<br /><br />For a long time I did the usual trick: Detect a collision, compute (somehow) an extraction vector, remove from the motion vector the part parallel to the extraction vector (dot product ...). However, this never seemed to work quite well and I always ended up with troublesome cases. (Well, arguably this was due to poor coding ;) )<br /><br />In one of my latest projects (a never-to-be-released zombie game I will maybe blog about someday), not only had I to face this problem, but on top of it I had tens of zombies bumping into each other, through network latency to add to the mix. What a nightmare.<br /><br />After much wasted time, I figured out a simple and (I believe) elegant solution. The link may not be obvious, but it was in fact inspired by the Lloyd algorithm.<br /><br />Assuming a 2D scene layout, seen from above, let's consider a disk centered around a character. A trivial but important consideration is that the center of mass of the disk is right below the character.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbM8gYxaBzSn6E4JIVNVzaSHwTcZbQVmCRWdrVfDPTBzk24ycIrWT9z7SLHt6jmmP9mQHZv9PasXKQGV3jk7nFj2KwE4Z1MgBZ66xLqt_CpcS_AS_XO6_QHmj-8XMe-DIJLWR3A3yZ7GQ/s1600/Diapositive1.PNG"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 205px; height: 165px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbM8gYxaBzSn6E4JIVNVzaSHwTcZbQVmCRWdrVfDPTBzk24ycIrWT9z7SLHt6jmmP9mQHZv9PasXKQGV3jk7nFj2KwE4Z1MgBZ66xLqt_CpcS_AS_XO6_QHmj-8XMe-DIJLWR3A3yZ7GQ/s320/Diapositive1.PNG" alt="" id="BLOGGER_PHOTO_ID_5594658962714183346" border="0" /></a><br /><br />Now, let's consider a wall nearby the character:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg1TLz_zJmuXcIXybwooGrNt-VExChvnCV_pXd9mIsUU111vrmDYoxZlvjLCRIXBCYhC3znt8VI5EC4T9_uxci9mEGvtrDnWo9dRRRpJRWrBkTU0cU7Yp9YfYKZfmd9-OV4Jyz3vgIM_Y/s1600/Diapositive2.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 195px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg1TLz_zJmuXcIXybwooGrNt-VExChvnCV_pXd9mIsUU111vrmDYoxZlvjLCRIXBCYhC3znt8VI5EC4T9_uxci9mEGvtrDnWo9dRRRpJRWrBkTU0cU7Yp9YfYKZfmd9-OV4Jyz3vgIM_Y/s320/Diapositive2.PNG" alt="" id="BLOGGER_PHOTO_ID_5594658963645914034" border="0" /></a><br /><br />The disk is cropped by the wall. The center of mass of the remaining part is now displaced. The trick is simply to correct the position of the character so that it always goes to the center of mass of the cropped disk. In summary at every frame: Compute motion vector, displace, compute center of mass, correct position.<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSmdwD8xU0Ns79UA84FhU6Kw8L0MkJYtVr-_TyOca-1AholViNSFFbtZ7IyBCafqVG70oXZETiwaYV0zgNDTfkHphnaZiZIwHGsPXcZh6rPWj4nKBwNColHcuajXwDP81I93QIG3Rb0jY/s1600/Diapositive3.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 227px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSmdwD8xU0Ns79UA84FhU6Kw8L0MkJYtVr-_TyOca-1AholViNSFFbtZ7IyBCafqVG70oXZETiwaYV0zgNDTfkHphnaZiZIwHGsPXcZh6rPWj4nKBwNColHcuajXwDP81I93QIG3Rb0jY/s320/Diapositive3.PNG" alt="" id="BLOGGER_PHOTO_ID_5594658971420595474" border="0" /></a><br />Of course the figure is exaggerated. In practice a disk with smaller radius is used.<br /><br />For collisions between characters, I subtract from the disk the half plane which is mid-way between the characters:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimnRaajiGzD3PA7A5XNt0t5M3K723pLtD1n_vk5BuPgtoMgtL7iyfD86t_fjJTAJmedM_8gCitcm8cdBpVRq92PfdmdsjMgfHIpwW97WY_g1Ce_-LSMRnz5RaUD3V3Sd2mA_DjQWJZB6c/s1600/Diapositive4.PNG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimnRaajiGzD3PA7A5XNt0t5M3K723pLtD1n_vk5BuPgtoMgtL7iyfD86t_fjJTAJmedM_8gCitcm8cdBpVRq92PfdmdsjMgfHIpwW97WY_g1Ce_-LSMRnz5RaUD3V3Sd2mA_DjQWJZB6c/s320/Diapositive4.PNG" alt="" id="BLOGGER_PHOTO_ID_5594658973697680690" border="0" /></a><br /><br />Now, you might be wondering how in hell you will be able to compute the center of mass. There are two different approaches. Both rely on a square instead of a disk.<br /><br />In the first approach I used convex shapes as colliders ('brushes') and sliced the collision square by the shape of the colliders, keeping only the parts outside. (For code doing this, look back at Quake's code for slicing polygons by convex brushes). A simple center of mass computation then gives you the corrected position.<br /><br />The second approach relies on rasterization. Setup a viewport matching the square around the character, render a quad outputting pixel positions in the map, render the colliders in black. Then read back and average the values of non black pixels to obtain the center of mass. This is the new position.<br /><br />This works nicely, gives a feeling of 'soft' collisions (depending on how large the collision shape is) and supports easily even the trickiest cases (many characters in a tight space of complex shape).<br /><br />Enjoy!Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3830350392070277486.post-53807363568018871982011-03-02T00:00:00.001-08:002011-03-02T00:12:03.621-08:00[various] VOD is such a failure hereThis is driving me crazy. For years since I enjoyed NetFlix in the US I have been looking forward for a mail-based or download based video rental service in France.<br /><br />Mail-based DVD rental never really worked here for several practical reasons, but also because well, this is the Internet era and download seems just easier. Unfortunately, VOD services in France are crippled either by a very limited and rather boring choice of movies, or by extremely fragile implementations (not even mentioning prices). Four (!) of my latest attempts at renting movies with different services failed -- either the movie downloaded but could not be watched, or the payment could not be made, or the service was temporarily unavailable. I have to admit, it worked once, giving a fantastic success rate of 20%.<br /><br />Needless to say that US services cannot be used from France -- the 'global economy' does not seem to cross borders for customers. This left me wondering: If a customer willing to pay for watching movies and shows can't do it , isn't that actively encouraging piracy?Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-3830350392070277486.post-22874282653438245402011-01-09T10:03:00.000-08:002011-01-09T10:05:25.253-08:00[wubi] Accessing files from Windows<a href="http://ext2read.blogspot.com/">http://ext2read.blogspot.com/</a> is a good answer. No driver to install, just an explorer-like interface. Open root.disk and import your files.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-85742979009976590392010-08-30T14:47:00.000-07:002010-08-30T15:15:18.588-07:00[luabind] Global table of classes from C++These days I am playing with Lua and LuaBind (yet another game project, more on that hopefuly soon). LuaBind is really quite amazing and is a perfect complement to Lua for C++ programmers.<br /><br />There is one thing, however, that gave me a lot of trouble. I wanted to define from C++ a global table of class instances in the Lua script. With LuaBind you can easily define globals using luabind::globals. For instance, here is how to define, from C++, a global named 'test' and having 1234 for value:<br /><br /><code>luabind::globals(luaState)[ "test" ] = 1234;</code><br /><br />In LuaBind (v0.9), a table is created using luabind::newtable, which returns a generic object. For instance:<br /><br /><code><br /> luabind::object table = luabind::newtable( luaState );<br /> table[ "Instance1" ] = new MyClass( "A" );<br /> table[ "Instance2" ] = new MyClass( "B" );<br /> table[ "Instance3" ] = new MyClass( "C" );<br /></code><br /><br />where 'MyClass' is a C++ class previously registered into LuaBind.<br /><br />Defining the table as a global is as easy as:<br /><br /><code><br /> luabind::globals(luaState)[ "AllInstances" ] = table;<br /></code><br /><br />This was working fine, but the code would keep randomly crashing <span style="font-weight:bold;">after</span> the lua script execution. This was really a strange behavior. Fortunately, <a href="http://old.nabble.com/Accessing-functions-stored-in-a-table-using-luabind-td12917599.html#a12925099">this post</a> saved my day.<br /><br />The problem is not with the code above, but with the context around it. Here is the entire function running my script:<br /><br /><code><br />void threadLua()<br />{<br />...<br />lua_State* luaState = lua_open();<br />luabind::open(luaState);<br />...<br />luabind::object table = luabind::newtable(luaState);<br />table[ "Instance1" ] = new MyClass( 1 );<br />table[ "Instance2" ] = new MyClass( 2 );<br />table[ "Instance3" ] = new MyClass( 2 );<br />luabind::globals(luaState)["TableOfInstances"] = table;<br />...<br />int ret = luaL_dostring(luaState, program);<br />...<br />lua_close(luaState);<br />} /// things would crash here<br /></code><br /><br />So what's wrong? Well, lua_close destroys the lua context. Unfortunately, my seemingly innocent object 'table' is still alive when this happens. And as it turns out, the destructor of a luabind::object does expect the lua context to still be valid. Hence the crash. The fix is desperately simple - it is enough to limit the scope of the variable:<br /><br /><code><br />void threadLua()<br />{<br />...<br />lua_State* luaState = lua_open();<br />luabind::open(luaState);<br />...<br />{ <br /> luabind::object table = luabind::newtable(luaState);<br /> table[ "Instance1" ] = new MyClass( 1 );<br /> table[ "Instance2" ] = new MyClass( 2 );<br /> table[ "Instance3" ] = new MyClass( 2 );<br /> luabind::globals(luaState)["TableOfInstances"] = table;<br />} /// keep this: 'table' must not live after this point<br />...<br />int ret = luaL_dostring(luaState, program);<br />...<br />lua_close(luaState);<br />} /// no crash!<br /></code><br /><br />This one was painful to find out so I thought it was worth a post!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-33746843968182051492010-07-23T11:29:00.000-07:002016-03-08T23:46:23.160-08:00[research] By-example synthesis of architectural texturesI am leaving for SIGGRAPH tomorrow, where we will present our paper 'By-example synthesis of architectural textures'. This is joint work with Samuel Hornus and Anass Lasram.<br />
The paper is available on <a href="http://alice.loria.fr/index.php/publications.html?redirect=0&Paper=TEXRESIZE@2010">this web page</a>.<br />
<br />
See you at SIGGRAPH :-)Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3830350392070277486.post-50189272097042806252010-04-20T04:09:00.001-07:002010-05-25T13:39:04.221-07:00[wubi] X11 trouble during installAt work I have a computer with a Quadro FX. For some reason, the Wubi 9.10 install has trouble with it. The first reboot under Ubuntu is supposed to launch the install process. However, I was left with a blinking screen and a text console. After a bit of struggle, I was able to install the NVidia drivers:<br /><br />0. sudo stop gdm<br /> (in between two blinks!) This stops gdm and stops the painful blinking.<br />1. sudo apt-get install lynx<br /> (a text based browser)<br />2. Launch lynx, navigate through NVidia website<br />3. Download the dirvers (AMD64 bits for 64 bits computers)<br />4. Install the drivers<br />5. Start gdm<br /><br />After this the X server should start fine. However there is a catch: Ubuntu is not installed yet, in fact you are running in a virtual RAM disk. If you reboot at this stage, all changes are lost!<br />The trick is simply to launch 'ubiquity', and select the 'loop' partition as install partition. Then the install completes and you are ready to enjoy Ubuntu!<br /><br />Hope this helps.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3830350392070277486.post-90988254889262744242010-02-01T07:13:00.000-08:002010-02-01T07:23:03.032-08:00[code] Visual Express 2010I am trying out Visual Studio 2010. Again, thanks to CMake the transition is mostly painless.<br /><br />I had one issue though, related to global include paths.<br />As explained <a href="http://blogs.msdn.com/vsproject/archive/2009/07/07/vc-directories.aspx">here</a>, they can no longer be set for Visual Studio as a whole but only on a per-project basis. Let's not argue whether this is good or bad but let's assume you need to set them globally (I my case, I just want the DirectX SDK include / lib paths to be set once and for all).<br /><br />In fact, there is a very simple workaround. All projects seem to include the following property sheet: <span style="font-style: italic;">Microsoft.Cpp.Win32.User</span><br />Any change to these properties will happen in all your projects. Just edit it and modify the include / lib of the "VC++ directories" entry.<br /><br />Note that there seem to be issues under XP (I am under Windows 7) => so <a href="http://blogs.msdn.com/vsproject/archive/2009/07/07/vc-directories.aspx">read the full story</a> if you need to set global paths using XP and 2010.Unknownnoreply@blogger.com0