mirror of
https://github.com/kristov/ldraw2stl.git
synced 2025-05-15 14:20:11 -07:00
Before this commit it appeared that STL viewers could handle the output. However, rendering the models in OpenGL revealed that the surface normals were all messed up. I believe most STL viewers just don't care about surface normals, because I suppose they don't really matter for 3d slicing. The problem ended up being really a complex issue around the winding order of triangles in sub-parts, and how this is affected by the "inversion" state. The winding order of triangles in ldraw is a complex combination of BFC meta commands and transformation matricies that "mirror" sub-parts. I tried to leave extensive comments in the code rather than go into it in the commit message. Also added a json output for rendering as OpenGL buffers. This is to help me debug issues with the surface normals. While working on this I also realized that the output of parsing a sub-part can be cached, as long at the "invert" flag is part of the cache key. This could make a huge difference in performance, because for example a "stud" gets generated many many times, and in this version of the code that results in a lot of repeated processing.
103 lines
2.4 KiB
Perl
Executable File
103 lines
2.4 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use FindBin;
|
|
use lib "$FindBin::Bin/../lib";
|
|
use LDraw::Parser;
|
|
use Getopt::Long;
|
|
|
|
my $opts = {};
|
|
GetOptions(
|
|
$opts,
|
|
'help',
|
|
'scale=s',
|
|
'ldrawdir=s',
|
|
'file=s',
|
|
'debug',
|
|
'json',
|
|
'nomodel',
|
|
'invert',
|
|
);
|
|
|
|
if (!keys %{$opts}) {
|
|
print_usage();
|
|
exit 0;
|
|
}
|
|
|
|
if ($opts->{help}) {
|
|
print_usage();
|
|
exit 0;
|
|
}
|
|
|
|
if (!$opts->{file}) {
|
|
print "ERROR: --file is required! (try --help)\n";
|
|
exit 1;
|
|
}
|
|
|
|
sub print_usage {
|
|
print <<END;
|
|
Usage: $0 --file <input file> [--scale=<N> --ldrawdir=/usr/share/ldraw]
|
|
|
|
Takes an ldraw part .dat file as input and converts it into an STL file.
|
|
|
|
--file <string>
|
|
The full path to the input .dat part file. Regardless of where this file
|
|
is, sub-parts of the file will be searched in --ldrawdir.
|
|
|
|
--scale <int>
|
|
Also scale the STL by N. This is separate from the LDU scaling that is
|
|
used to convert internally from LDU (LDraw Unit) to mm (STL).
|
|
|
|
--ldrawdir <string>
|
|
The location of the ldraw parts library package. Note: it is expected
|
|
that this contains the directories "p", "parts" and "models". The Debian
|
|
non-free package "ldraw-parts" installs to /usr/share/ldraw and that is
|
|
the default value for this tool.
|
|
|
|
--debug
|
|
Print debugging messages to STDERR
|
|
|
|
--json
|
|
Dump the model as a json object in the form:
|
|
|
|
{"normals":[],"vertexes":[]}
|
|
|
|
Note: the surface normal of the triangle is duplicated for each of the 3 vertexes
|
|
in the triangle, so these can be loaded into GL buffers and rendered with
|
|
glDrawArrays.
|
|
|
|
--nomodel
|
|
Do not print the stl output. I am using this to run the script over all
|
|
parts to try to detect issues.
|
|
|
|
--invert
|
|
Invert the part. Used for debugging.
|
|
|
|
END
|
|
}
|
|
|
|
my $parser = LDraw::Parser->new({
|
|
file => $opts->{file},
|
|
$opts->{scale} ? ( scale => $opts->{scale} ) : (),
|
|
$opts->{ldrawdir} ? ( ldraw_path => $opts->{ldrawdir} ) : (),
|
|
$opts->{debug} ? ( debug => 1 ) : (),
|
|
$opts->{invert} ? ( invert => 1 ) : (),
|
|
});
|
|
|
|
$parser->parse;
|
|
if ($opts->{json}) {
|
|
my $data = $parser->gl_buffer;
|
|
print '{"normals":[';
|
|
print join(',', @{$data->{normals}});
|
|
print '],"vertexes":[';
|
|
print join(',', @{$data->{vertexes}});
|
|
print ']}';
|
|
print "\n";
|
|
exit 0;
|
|
}
|
|
if ($opts->{nomodel}) {
|
|
exit 0;
|
|
}
|
|
print $parser->to_stl;
|