1
0
mirror of https://github.com/kristov/ldraw2stl.git synced 2025-05-15 14:20:11 -07:00
ldraw2stl/bin/dat2stl
ceade 28b5718628 Hopefully this fixes bugs with triangle winding
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.
2025-03-21 23:40:36 +01:00

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;