Open GL学习 (二) 3D模型的使用
2013-01-14 17:19
471 查看
(本页文章,参考了http://blog.csdn.net/wangyuchun_799/article/details/7861226 以及 http://heikobehrens.net/2009/08/27/obj2opengl/)
在网上找到可以用来制作3 D模型的免费软件,Blender, Cheetah3D。其中Blender是免费的,而Cheetah3D需要花费469多人民币。这两个都可以用来制作Obj模型文件,并可以存储为obj文件,而Cheetah3D文件还可以直接生成.h文件,供代码直接使用,而Blender可以导出为obj文件,但不能再直接生成.h文件。
这里我使用的是Blender,(可直接去其官网进行下载)。
Blender制作模型后,然后导出为obj文件,由于我们在代码中不能直接使用obj文件,我们需要这个模型的数据,所以我们需要把这个obj转为.h文件供我们使用,幸运的是,有这一个脚本可以做这事,就是"objopengl.pl"。
在命令行中,运行
-(void)render
{
//
加载3D模型
[selfbindMaterial:material3DKey];
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
//关掉颜色,因为采用3D帖图,所以需要关掉颜色
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(vertexSize,GL_FLOAT,
0, vertexes);
glTexCoordPointer(2,GL_FLOAT,
0, uv3DCoordinates);
glNormalPointer(GL_FLOAT,0,
normal3D);
glDrawArrays(renderStyle,0,
vertexCount);
}
然后就是设置光照,代码如下:
-(void)setupLighting
{
// cull the unseen faces
// we use 'front' culling because Cheetah3d exports our models to be compatible
// with this way
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
// Light features
GLfloat light_ambient[]= { 0.2f,
0.2f, 0.2f,
1.0f };
GLfloat light_diffuse[]= { 80.0f,
80.0f, 80.0f,
0.0f };
GLfloat light_specular[]= { 80.0f,
80.0f, 80.0f,
0.0f };
// Set up light 0
glLightfv (GL_LIGHT0,
GL_AMBIENT, light_ambient);
glLightfv (GL_LIGHT0,
GL_DIFFUSE, light_diffuse);
glLightfv (GL_LIGHT0,
GL_SPECULAR, light_specular);
// // // Material features
// GLfloat mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
// GLfloat mat_shininess[] = { 120.0 };
// glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
// glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
glShadeModel (GL_SMOOTH);
// Place the light up and to the right
GLfloat light0_position[] = { 50.0,
50.0, 50.0,
1.0 };
glLightfv(GL_LIGHT0,
GL_POSITION, light0_position);
// Enable lighting and lights
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
这里也有一个例子可以下载,里面进行了简化,工程中加入了纹理、旋转、平移和光照,包含OBJ文件和对应的纹理图片。注意在经过本人尝试后发现,JPG、GIF和PNG都是可以使用的纹理图片,而tga格式加载失败,所以还是使用PNG格式好一点。
本地预览.3DS、.OBJ、.MD2、.MD3、.MS3D、.X等模型文件,推荐使用supermodel (下载地址:supermodel,注意这是windows平台使用的),这里还有一些有几个OBJ
3D示例模型,感兴趣的可以下载使用 (这里)
可以直接下载这个例子运行,来感受OpenGL的强大,OBJ2OpenGLES示例代码 以及obj2opengl.zip 例子。
下面是这个脚本的内容,复制完成后,存储为"objopengl.pl"文件即可。
#! /usr/bin/perl
=head1 NAME
obj2opengl - converts obj files to arrays for glDrawArrays
=head1 SYNOPSIS
obj2opengl [options] file
use -help or -man for further information
=head1 DESCRIPTION
This script expects and OBJ file consisting of vertices,
texture coords and normals. Each face must contain
exactly 3 vertices. The texture coords are two dimonsional.
The resulting .H file offers three float arrays to be rendered
with glDrawArrays.
=head1 AUTHOR
Heiko Behrens (http://www.HeikoBehrens.net)
=head1 VERSION
14th August 2012
=head1 COPYRIGHT
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=head1 ACKNOWLEDGEMENTS
This script is based on the work of Margaret Geroch.
=head1 REQUIRED ARGUMENTS
The first or the last argument has to be an OBJ file according
to this () specification.
=head1 OPTIONS
=over
=item B<-help>
Print a brief help message and exits.
=item B<-man>
Prints the extended manual page and exits.
=item B<-noScale>
Prevents automatic scaling. Otherwise the object will be scaled
such the the longest dimension is 1 unit.
=item B<-scale <float>>
Sets the scale factor explicitly. Please be aware that negative numbers
are not handled correctly regarding the orientation of the normals.
=item B<-noMove>
Prevents automatic scaling. Otherwise the object will be moved to the center of
its vertices.
=item B<-o>, B<-outputFilename>
Name of the output file name. If omitted, the output file the same as the
input filename but with the extension .h
=item B<-nameOfObject>
Specifies the name of the generated variables. If omitted, same as
output filename without path and extension.
=item B<-noverbose>
Runs this script silently.
=cut
use Getopt::Long;
use File::Basename;
use Pod::Usage;
# -----------------------------------------------------------------
# Main Program
# -----------------------------------------------------------------
handleArguments();
# derive center coords and scale factor if neither provided nor disabled
unless(defined($scalefac) &&defined($xcen)) {
calcSizeAndCenter();
}
if($verbose) {
printInputAndOptions();
}
# TODO check integrity: Does every referenced vertex, normal and coord exist?
loadData();
normalizeNormals();
if($verbose) {
printStatistics();
}
writeOutput();
# -----------------------------------------------------------------
# Sub Routines
# -----------------------------------------------------------------
sub handleArguments() {
my $help =0;
my $man =0;
my $noscale =0;
my $nomove =0;
$verbose =1;
$errorInOptions = !GetOptions (
"help" => \$help,
"man" => \$man,
"noScale" => \$noscale,
"scale=f" => \$scalefac,
"noMove" => \$nomove,
"center=f{3}" => \@center,
"outputFilename=s" => \$outFilename,
"nameOfObject=s" => \$object,
"verbose!" => \$verbose,
);
if($noscale) {
$scalefac =1;
}
if($nomove) {
@center = (0,0,
0);
}
if(defined(@center)) {
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}
if($#ARGV ==0) {
my ($file, $dir, $ext) = fileparse($ARGV[0], qr/\.[^.]*/);
$inFilename = $dir . $file . $ext;
}else {
$errorInOptions = true;
}
# (optional) derive output filename from input filename
unless($errorInOptions ||defined($outFilename)) {
my ($file, $dir, $ext) = fileparse($inFilename, qr/\.[^.]*/);
$outFilename = $dir . $file .".h";
}
# (optional) define object name from output filename
unless($errorInOptions ||defined($object)) {
my ($file, $dir, $ext) = fileparse($outFilename, qr/\.[^.]*/);
$object = $file;
}
($inFilenamene $outFilename)
or
die ("Input filename must not be the same as output filename")
unless($errorInOptions);
if($errorInOptions || $man || $help) {
pod2usage(-verbose =>2)
if $man;
pod2usage(-verbose =>1)
if $help;
pod2usage();
}
# check wheter file exists
open ( INFILE,"<$inFilename" )
|| die"Can't find file '$inFilename' ...exiting \n";
close(INFILE);
}
# Stores center of object in $xcen, $ycen, $zcen
# and calculates scaling factor $scalefac to limit max
# side of object to 1.0 units
sub calcSizeAndCenter() {
open ( INFILE,"<$inFilename" )
|| die"Can't find file $inFilename...exiting \n";
$numVerts =0;
my (
$xsum, $ysum, $zsum,
$xmin, $ymin, $zmin,
$xmax, $ymax, $zmax,
);
while ( $line = <INFILE> )
{
chop $line;
if ($line =~ /v\s+.*/)
{
$numVerts++;
@tokens =split(' ', $line);
$xsum += $tokens[1];
$ysum += $tokens[2];
$zsum += $tokens[3];
if ( $numVerts ==
1 )
{
$xmin = $tokens[1];
$xmax = $tokens[1];
$ymin = $tokens[2];
$ymax = $tokens[2];
$zmin = $tokens[3];
$zmax = $tokens[3];
}
else
{
if ($tokens[1] < $xmin)
{
$xmin = $tokens[1];
}
elsif ($tokens[1] > $xmax)
{
$xmax = $tokens[1];
}
if ($tokens[2] < $ymin)
{
$ymin = $tokens[2];
}
elsif ($tokens[2] > $ymax)
{
$ymax = $tokens[2];
}
if ($tokens[3] < $zmin)
{
$zmin = $tokens[3];
}
elsif ($tokens[3] > $zmax)
{
$zmax = $tokens[3];
}
}
}
}
close INFILE;
# Calculate the center
unless(defined($xcen)) {
$xcen = $xsum / $numVerts;
$ycen = $ysum / $numVerts;
$zcen = $zsum / $numVerts;
}
# Calculate the scale factor
unless(defined($scalefac)) {
my $xdiff = ($xmax - $xmin);
my $ydiff = ($ymax - $ymin);
my $zdiff = ($zmax - $zmin);
if ( ( $xdiff >= $ydiff ) && ( $xdiff >= $zdiff ) )
{
$scalefac = $xdiff;
}
elsif ( ( $ydiff >= $xdiff ) && ( $ydiff >= $zdiff ) )
{
$scalefac = $ydiff;
}
else
{
$scalefac = $zdiff;
}
$scalefac =1.0 / $scalefac;
}
}
sub printInputAndOptions() {
print"Input file : $inFilename\n";
print"Output file : $outFilename\n";
print"Object name : $object\n";
print"Center : <$xcen, $ycen, $zcen>\n";
print"Scale by : $scalefac\n";
}
sub printStatistics() {
print"----------------\n";
print"Vertices : $numVerts\n";
print"Faces : $numFaces\n";
print"Texture Coords : $numTexture\n";
print"Normals : $numNormals\n";
}
# reads vertices into $xcoords[], $ycoords[], $zcoords[]
# where coordinates are moved and scaled according to
# $xcen, $ycen, $zcen and $scalefac
# reads texture coords into $tx[], $ty[]
# where y coordinate is mirrowed
# reads normals into $nx[], $ny[], $nz[]
# but does not normalize, see normalizeNormals()
# reads faces and establishes lookup data where
# va_idx[], vb_idx[], vc_idx[] for vertices
# ta_idx[], tb_idx[], tc_idx[] for texture coords
# na_idx[], nb_idx[], nc_idx[] for normals
# store indizes for the former arrays respectively
# also, $face_line[] store actual face string
sub loadData {
$numVerts =0;
$numFaces =0;
$numTexture =0;
$numNormals =0;
open ( INFILE,"<$inFilename" )
|| die"Can't find file $inFilename...exiting \n";
while ($line = <INFILE>)
{
chop $line;
# vertices
if ($line =~ /v\s+.*/)
{
@tokens=split(' ', $line);
$x = ( $tokens[1] - $xcen ) * $scalefac;
$y = ( $tokens[2] - $ycen ) * $scalefac;
$z = ( $tokens[3] - $zcen ) * $scalefac;
$xcoords[$numVerts] = $x;
$ycoords[$numVerts] = $y;
$zcoords[$numVerts] = $z;
$numVerts++;
}
# texture coords
if ($line =~ /vt\s+.*/)
{
@tokens=split(' ', $line);
$x = $tokens[1];
$y =1 - $tokens[2];
$tx[$numTexture] = $x;
$ty[$numTexture] = $y;
$numTexture++;
}
#normals
if ($line =~ /vn\s+.*/)
{
@tokens=split(' ', $line);
$x = $tokens[1];
$y = $tokens[2];
$z = $tokens[3];
$nx[$numNormals] = $x;
$ny[$numNormals] = $y;
$nz[$numNormals] = $z;
$numNormals++;
}
# faces
if ($line =~ /f\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)(\s+([^ ]+))?/)
{
@a =
split('/', $1);
@b =
split('/', $2);
@c =
split('/', $3);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $b[0]-1;
$tb_idx[$numFaces] = $b[1]-1;
$nb_idx[$numFaces] = $b[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
# ractangle => second triangle
if($5 !="")
{
@d =split('/', $5);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $d[0]-1;
$tb_idx[$numFaces] = $d[1]-1;
$nb_idx[$numFaces] = $d[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
}
}
}
close INFILE;
}
sub normalizeNormals {
for ( $j =0; $j < $numNormals; ++$j)
{
$d =sqrt ( $nx[$j]*$nx[$j] + $ny[$j]*$ny[$j] + $nz[$j]*$nz[$j] );
if ( $d ==
0 )
{
$nx[$j] =1;
$ny[$j] =0;
$nz[$j] =0;
}
else
{
$nx[$j] = $nx[$j] / $d;
$ny[$j] = $ny[$j] / $d;
$nz[$j] = $nz[$j] / $d;
}
}
}
sub fixedIndex {
local $idx = $_[0];
local $num = $_[1];
if($idx >= 0)
{
$idx;
}
else {
$num + $idx +1;
}
}
sub writeOutput {
open ( OUTFILE,">$outFilename" )
|| die"Can't create file $outFilename ... exiting\n";
print OUTFILE"/*\n";
print OUTFILE"created with obj2opengl.pl\n\n";
# some statistics
print OUTFILE"source file : $inFilename\n";
print OUTFILE"vertices : $numVerts\n";
print OUTFILE"faces : $numFaces\n";
print OUTFILE"normals : $numNormals\n";
print OUTFILE"texture coords : $numTexture\n";
print OUTFILE"\n\n";
# example usage
print OUTFILE"// include generated arrays\n";
print OUTFILE"#import \"".$outFilename."\"\n";
print OUTFILE"\n";
print OUTFILE"// set input data to arrays\n";
print OUTFILE"glVertexPointer(3, GL_FLOAT, 0, ".$object."Verts);\n";
print OUTFILE"glNormalPointer(GL_FLOAT, 0, ".$object."Normals);\n"
if $numNormals >0;
print OUTFILE"glTexCoordPointer(2, GL_FLOAT, 0, ".$object."TexCoords);\n"
if $numTexture >0;
print OUTFILE"\n";
print OUTFILE"// draw data\n";
print OUTFILE"glDrawArrays(GL_TRIANGLES, 0, ".$object."NumVerts);\n";
print OUTFILE"*/\n\n";
# needed constant for glDrawArrays
print OUTFILE"unsigned int ".$object."NumVerts = ".($numFaces
*3).";\n\n";
# write verts
print OUTFILE"float ".$object."Verts \[\] = {\n";
for( $j =0; $j < $numFaces; $j++)
{
$ia = fixedIndex($va_idx[$j], $numVerts);
$ib = fixedIndex($vb_idx[$j], $numVerts);
$ic = fixedIndex($vc_idx[$j], $numVerts);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $xcoords[$ia], $ycoords[$ia], $zcoords[$ia],\n";
print OUTFILE" $xcoords[$ib], $ycoords[$ib], $zcoords[$ib],\n";
print OUTFILE" $xcoords[$ic], $ycoords[$ic], $zcoords[$ic],\n";
}
print OUTFILE"};\n\n";
# write normals
if($numNormals >0) {
print OUTFILE"float ".$object."Normals \[\] = {\n";
for( $j =0; $j < $numFaces; $j++) {
$ia = fixedIndex($na_idx[$j], $numNormals);
$ib = fixedIndex($nb_idx[$j], $numNormals);
$ic = fixedIndex($nc_idx[$j], $numNormals);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $nx[$ia], $ny[$ia], $nz[$ia],\n";
print OUTFILE" $nx[$ib], $ny[$ib], $nz[$ib],\n";
print OUTFILE" $nx[$ic], $ny[$ic], $nz[$ic],\n";
}
print OUTFILE"};\n\n";
}
# write texture coords
if($numTexture) {
print OUTFILE"float ".$object."TexCoords \[\] = {\n";
for( $j =0; $j < $numFaces; $j++) {
$ia = fixedIndex($ta_idx[$j], $numTexture);
$ib = fixedIndex($tb_idx[$j], $numTexture);
$ic = fixedIndex($tc_idx[$j], $numTexture);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $tx[$ia], $ty[$ia],\n";
print OUTFILE" $tx[$ib], $ty[$ib],\n";
print OUTFILE" $tx[$ic], $ty[$ic],\n";
}
print OUTFILE"};\n\n";
}
close OUTFILE;
}
在网上找到可以用来制作3 D模型的免费软件,Blender, Cheetah3D。其中Blender是免费的,而Cheetah3D需要花费469多人民币。这两个都可以用来制作Obj模型文件,并可以存储为obj文件,而Cheetah3D文件还可以直接生成.h文件,供代码直接使用,而Blender可以导出为obj文件,但不能再直接生成.h文件。
这里我使用的是Blender,(可直接去其官网进行下载)。
Blender制作模型后,然后导出为obj文件,由于我们在代码中不能直接使用obj文件,我们需要这个模型的数据,所以我们需要把这个obj转为.h文件供我们使用,幸运的是,有这一个脚本可以做这事,就是"objopengl.pl"。
在命令行中,运行
./obj2opengl.pl myobj.obj
-(void)render
{
//
加载3D模型
[selfbindMaterial:material3DKey];
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
//关掉颜色,因为采用3D帖图,所以需要关掉颜色
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(vertexSize,GL_FLOAT,
0, vertexes);
glTexCoordPointer(2,GL_FLOAT,
0, uv3DCoordinates);
glNormalPointer(GL_FLOAT,0,
normal3D);
glDrawArrays(renderStyle,0,
vertexCount);
}
然后就是设置光照,代码如下:
-(void)setupLighting
{
// cull the unseen faces
// we use 'front' culling because Cheetah3d exports our models to be compatible
// with this way
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
// Light features
GLfloat light_ambient[]= { 0.2f,
0.2f, 0.2f,
1.0f };
GLfloat light_diffuse[]= { 80.0f,
80.0f, 80.0f,
0.0f };
GLfloat light_specular[]= { 80.0f,
80.0f, 80.0f,
0.0f };
// Set up light 0
glLightfv (GL_LIGHT0,
GL_AMBIENT, light_ambient);
glLightfv (GL_LIGHT0,
GL_DIFFUSE, light_diffuse);
glLightfv (GL_LIGHT0,
GL_SPECULAR, light_specular);
// // // Material features
// GLfloat mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
// GLfloat mat_shininess[] = { 120.0 };
// glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
// glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
glShadeModel (GL_SMOOTH);
// Place the light up and to the right
GLfloat light0_position[] = { 50.0,
50.0, 50.0,
1.0 };
glLightfv(GL_LIGHT0,
GL_POSITION, light0_position);
// Enable lighting and lights
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
这里也有一个例子可以下载,里面进行了简化,工程中加入了纹理、旋转、平移和光照,包含OBJ文件和对应的纹理图片。注意在经过本人尝试后发现,JPG、GIF和PNG都是可以使用的纹理图片,而tga格式加载失败,所以还是使用PNG格式好一点。
本地预览.3DS、.OBJ、.MD2、.MD3、.MS3D、.X等模型文件,推荐使用supermodel (下载地址:supermodel,注意这是windows平台使用的),这里还有一些有几个OBJ
3D示例模型,感兴趣的可以下载使用 (这里)
可以直接下载这个例子运行,来感受OpenGL的强大,OBJ2OpenGLES示例代码 以及obj2opengl.zip 例子。
下面是这个脚本的内容,复制完成后,存储为"objopengl.pl"文件即可。
#! /usr/bin/perl
=head1 NAME
obj2opengl - converts obj files to arrays for glDrawArrays
=head1 SYNOPSIS
obj2opengl [options] file
use -help or -man for further information
=head1 DESCRIPTION
This script expects and OBJ file consisting of vertices,
texture coords and normals. Each face must contain
exactly 3 vertices. The texture coords are two dimonsional.
The resulting .H file offers three float arrays to be rendered
with glDrawArrays.
=head1 AUTHOR
Heiko Behrens (http://www.HeikoBehrens.net)
=head1 VERSION
14th August 2012
=head1 COPYRIGHT
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=head1 ACKNOWLEDGEMENTS
This script is based on the work of Margaret Geroch.
=head1 REQUIRED ARGUMENTS
The first or the last argument has to be an OBJ file according
to this () specification.
=head1 OPTIONS
=over
=item B<-help>
Print a brief help message and exits.
=item B<-man>
Prints the extended manual page and exits.
=item B<-noScale>
Prevents automatic scaling. Otherwise the object will be scaled
such the the longest dimension is 1 unit.
=item B<-scale <float>>
Sets the scale factor explicitly. Please be aware that negative numbers
are not handled correctly regarding the orientation of the normals.
=item B<-noMove>
Prevents automatic scaling. Otherwise the object will be moved to the center of
its vertices.
=item B<-o>, B<-outputFilename>
Name of the output file name. If omitted, the output file the same as the
input filename but with the extension .h
=item B<-nameOfObject>
Specifies the name of the generated variables. If omitted, same as
output filename without path and extension.
=item B<-noverbose>
Runs this script silently.
=cut
use Getopt::Long;
use File::Basename;
use Pod::Usage;
# -----------------------------------------------------------------
# Main Program
# -----------------------------------------------------------------
handleArguments();
# derive center coords and scale factor if neither provided nor disabled
unless(defined($scalefac) &&defined($xcen)) {
calcSizeAndCenter();
}
if($verbose) {
printInputAndOptions();
}
# TODO check integrity: Does every referenced vertex, normal and coord exist?
loadData();
normalizeNormals();
if($verbose) {
printStatistics();
}
writeOutput();
# -----------------------------------------------------------------
# Sub Routines
# -----------------------------------------------------------------
sub handleArguments() {
my $help =0;
my $man =0;
my $noscale =0;
my $nomove =0;
$verbose =1;
$errorInOptions = !GetOptions (
"help" => \$help,
"man" => \$man,
"noScale" => \$noscale,
"scale=f" => \$scalefac,
"noMove" => \$nomove,
"center=f{3}" => \@center,
"outputFilename=s" => \$outFilename,
"nameOfObject=s" => \$object,
"verbose!" => \$verbose,
);
if($noscale) {
$scalefac =1;
}
if($nomove) {
@center = (0,0,
0);
}
if(defined(@center)) {
$xcen = $center[0];
$ycen = $center[1];
$zcen = $center[2];
}
if($#ARGV ==0) {
my ($file, $dir, $ext) = fileparse($ARGV[0], qr/\.[^.]*/);
$inFilename = $dir . $file . $ext;
}else {
$errorInOptions = true;
}
# (optional) derive output filename from input filename
unless($errorInOptions ||defined($outFilename)) {
my ($file, $dir, $ext) = fileparse($inFilename, qr/\.[^.]*/);
$outFilename = $dir . $file .".h";
}
# (optional) define object name from output filename
unless($errorInOptions ||defined($object)) {
my ($file, $dir, $ext) = fileparse($outFilename, qr/\.[^.]*/);
$object = $file;
}
($inFilenamene $outFilename)
or
die ("Input filename must not be the same as output filename")
unless($errorInOptions);
if($errorInOptions || $man || $help) {
pod2usage(-verbose =>2)
if $man;
pod2usage(-verbose =>1)
if $help;
pod2usage();
}
# check wheter file exists
open ( INFILE,"<$inFilename" )
|| die"Can't find file '$inFilename' ...exiting \n";
close(INFILE);
}
# Stores center of object in $xcen, $ycen, $zcen
# and calculates scaling factor $scalefac to limit max
# side of object to 1.0 units
sub calcSizeAndCenter() {
open ( INFILE,"<$inFilename" )
|| die"Can't find file $inFilename...exiting \n";
$numVerts =0;
my (
$xsum, $ysum, $zsum,
$xmin, $ymin, $zmin,
$xmax, $ymax, $zmax,
);
while ( $line = <INFILE> )
{
chop $line;
if ($line =~ /v\s+.*/)
{
$numVerts++;
@tokens =split(' ', $line);
$xsum += $tokens[1];
$ysum += $tokens[2];
$zsum += $tokens[3];
if ( $numVerts ==
1 )
{
$xmin = $tokens[1];
$xmax = $tokens[1];
$ymin = $tokens[2];
$ymax = $tokens[2];
$zmin = $tokens[3];
$zmax = $tokens[3];
}
else
{
if ($tokens[1] < $xmin)
{
$xmin = $tokens[1];
}
elsif ($tokens[1] > $xmax)
{
$xmax = $tokens[1];
}
if ($tokens[2] < $ymin)
{
$ymin = $tokens[2];
}
elsif ($tokens[2] > $ymax)
{
$ymax = $tokens[2];
}
if ($tokens[3] < $zmin)
{
$zmin = $tokens[3];
}
elsif ($tokens[3] > $zmax)
{
$zmax = $tokens[3];
}
}
}
}
close INFILE;
# Calculate the center
unless(defined($xcen)) {
$xcen = $xsum / $numVerts;
$ycen = $ysum / $numVerts;
$zcen = $zsum / $numVerts;
}
# Calculate the scale factor
unless(defined($scalefac)) {
my $xdiff = ($xmax - $xmin);
my $ydiff = ($ymax - $ymin);
my $zdiff = ($zmax - $zmin);
if ( ( $xdiff >= $ydiff ) && ( $xdiff >= $zdiff ) )
{
$scalefac = $xdiff;
}
elsif ( ( $ydiff >= $xdiff ) && ( $ydiff >= $zdiff ) )
{
$scalefac = $ydiff;
}
else
{
$scalefac = $zdiff;
}
$scalefac =1.0 / $scalefac;
}
}
sub printInputAndOptions() {
print"Input file : $inFilename\n";
print"Output file : $outFilename\n";
print"Object name : $object\n";
print"Center : <$xcen, $ycen, $zcen>\n";
print"Scale by : $scalefac\n";
}
sub printStatistics() {
print"----------------\n";
print"Vertices : $numVerts\n";
print"Faces : $numFaces\n";
print"Texture Coords : $numTexture\n";
print"Normals : $numNormals\n";
}
# reads vertices into $xcoords[], $ycoords[], $zcoords[]
# where coordinates are moved and scaled according to
# $xcen, $ycen, $zcen and $scalefac
# reads texture coords into $tx[], $ty[]
# where y coordinate is mirrowed
# reads normals into $nx[], $ny[], $nz[]
# but does not normalize, see normalizeNormals()
# reads faces and establishes lookup data where
# va_idx[], vb_idx[], vc_idx[] for vertices
# ta_idx[], tb_idx[], tc_idx[] for texture coords
# na_idx[], nb_idx[], nc_idx[] for normals
# store indizes for the former arrays respectively
# also, $face_line[] store actual face string
sub loadData {
$numVerts =0;
$numFaces =0;
$numTexture =0;
$numNormals =0;
open ( INFILE,"<$inFilename" )
|| die"Can't find file $inFilename...exiting \n";
while ($line = <INFILE>)
{
chop $line;
# vertices
if ($line =~ /v\s+.*/)
{
@tokens=split(' ', $line);
$x = ( $tokens[1] - $xcen ) * $scalefac;
$y = ( $tokens[2] - $ycen ) * $scalefac;
$z = ( $tokens[3] - $zcen ) * $scalefac;
$xcoords[$numVerts] = $x;
$ycoords[$numVerts] = $y;
$zcoords[$numVerts] = $z;
$numVerts++;
}
# texture coords
if ($line =~ /vt\s+.*/)
{
@tokens=split(' ', $line);
$x = $tokens[1];
$y =1 - $tokens[2];
$tx[$numTexture] = $x;
$ty[$numTexture] = $y;
$numTexture++;
}
#normals
if ($line =~ /vn\s+.*/)
{
@tokens=split(' ', $line);
$x = $tokens[1];
$y = $tokens[2];
$z = $tokens[3];
$nx[$numNormals] = $x;
$ny[$numNormals] = $y;
$nz[$numNormals] = $z;
$numNormals++;
}
# faces
if ($line =~ /f\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)(\s+([^ ]+))?/)
{
@a =
split('/', $1);
@b =
split('/', $2);
@c =
split('/', $3);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $b[0]-1;
$tb_idx[$numFaces] = $b[1]-1;
$nb_idx[$numFaces] = $b[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
# ractangle => second triangle
if($5 !="")
{
@d =split('/', $5);
$va_idx[$numFaces] = $a[0]-1;
$ta_idx[$numFaces] = $a[1]-1;
$na_idx[$numFaces] = $a[2]-1;
$vb_idx[$numFaces] = $d[0]-1;
$tb_idx[$numFaces] = $d[1]-1;
$nb_idx[$numFaces] = $d[2]-1;
$vc_idx[$numFaces] = $c[0]-1;
$tc_idx[$numFaces] = $c[1]-1;
$nc_idx[$numFaces] = $c[2]-1;
$face_line[$numFaces] = $line;
$numFaces++;
}
}
}
close INFILE;
}
sub normalizeNormals {
for ( $j =0; $j < $numNormals; ++$j)
{
$d =sqrt ( $nx[$j]*$nx[$j] + $ny[$j]*$ny[$j] + $nz[$j]*$nz[$j] );
if ( $d ==
0 )
{
$nx[$j] =1;
$ny[$j] =0;
$nz[$j] =0;
}
else
{
$nx[$j] = $nx[$j] / $d;
$ny[$j] = $ny[$j] / $d;
$nz[$j] = $nz[$j] / $d;
}
}
}
sub fixedIndex {
local $idx = $_[0];
local $num = $_[1];
if($idx >= 0)
{
$idx;
}
else {
$num + $idx +1;
}
}
sub writeOutput {
open ( OUTFILE,">$outFilename" )
|| die"Can't create file $outFilename ... exiting\n";
print OUTFILE"/*\n";
print OUTFILE"created with obj2opengl.pl\n\n";
# some statistics
print OUTFILE"source file : $inFilename\n";
print OUTFILE"vertices : $numVerts\n";
print OUTFILE"faces : $numFaces\n";
print OUTFILE"normals : $numNormals\n";
print OUTFILE"texture coords : $numTexture\n";
print OUTFILE"\n\n";
# example usage
print OUTFILE"// include generated arrays\n";
print OUTFILE"#import \"".$outFilename."\"\n";
print OUTFILE"\n";
print OUTFILE"// set input data to arrays\n";
print OUTFILE"glVertexPointer(3, GL_FLOAT, 0, ".$object."Verts);\n";
print OUTFILE"glNormalPointer(GL_FLOAT, 0, ".$object."Normals);\n"
if $numNormals >0;
print OUTFILE"glTexCoordPointer(2, GL_FLOAT, 0, ".$object."TexCoords);\n"
if $numTexture >0;
print OUTFILE"\n";
print OUTFILE"// draw data\n";
print OUTFILE"glDrawArrays(GL_TRIANGLES, 0, ".$object."NumVerts);\n";
print OUTFILE"*/\n\n";
# needed constant for glDrawArrays
print OUTFILE"unsigned int ".$object."NumVerts = ".($numFaces
*3).";\n\n";
# write verts
print OUTFILE"float ".$object."Verts \[\] = {\n";
for( $j =0; $j < $numFaces; $j++)
{
$ia = fixedIndex($va_idx[$j], $numVerts);
$ib = fixedIndex($vb_idx[$j], $numVerts);
$ic = fixedIndex($vc_idx[$j], $numVerts);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $xcoords[$ia], $ycoords[$ia], $zcoords[$ia],\n";
print OUTFILE" $xcoords[$ib], $ycoords[$ib], $zcoords[$ib],\n";
print OUTFILE" $xcoords[$ic], $ycoords[$ic], $zcoords[$ic],\n";
}
print OUTFILE"};\n\n";
# write normals
if($numNormals >0) {
print OUTFILE"float ".$object."Normals \[\] = {\n";
for( $j =0; $j < $numFaces; $j++) {
$ia = fixedIndex($na_idx[$j], $numNormals);
$ib = fixedIndex($nb_idx[$j], $numNormals);
$ic = fixedIndex($nc_idx[$j], $numNormals);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $nx[$ia], $ny[$ia], $nz[$ia],\n";
print OUTFILE" $nx[$ib], $ny[$ib], $nz[$ib],\n";
print OUTFILE" $nx[$ic], $ny[$ic], $nz[$ic],\n";
}
print OUTFILE"};\n\n";
}
# write texture coords
if($numTexture) {
print OUTFILE"float ".$object."TexCoords \[\] = {\n";
for( $j =0; $j < $numFaces; $j++) {
$ia = fixedIndex($ta_idx[$j], $numTexture);
$ib = fixedIndex($tb_idx[$j], $numTexture);
$ic = fixedIndex($tc_idx[$j], $numTexture);
print OUTFILE" // $face_line[$j]\n";
print OUTFILE" $tx[$ia], $ty[$ia],\n";
print OUTFILE" $tx[$ib], $ty[$ib],\n";
print OUTFILE" $tx[$ic], $ty[$ic],\n";
}
print OUTFILE"};\n\n";
}
close OUTFILE;
}
相关文章推荐
- Open GL学习 (二) 3D模型的使用
- ROS 学习系列 -- 使用urdf创建机器人模型在Rviz中3D观察 之二 joint 使用
- ROS 学习系列 -- 使用urdf创建机器人模型在Rviz中3D观察 之一 link使用
- ROS学习(1)使用URDF创建机器人3D仿真模型
- ROS 学习系列 -- 使用urdf创建机器人模型在Rviz中3D观察 之一 link使用
- ThinkPHP学习笔记(五)使用模型操作数据库之CURD
- OpenGL ES 学习教程(六) 使用开源库 Assimp 将 Obj 模型 转换成自己的格式
- OPENCV学习笔记3-4_使用模型-视图-控制器设计应用程序
- 使用Python和Blender来学习3D编程
- OpenGL ES 学习教程(六) 使用开源库 Assimp 将 Obj 模型 转换成自己的格式
- Libgdx New 3D API 教程之 -- 使用Libgdx加载模型
- 使用RenderTexture实现3D模型与UI的组合显示
- ogre3D学习基础18 -- 材质的使用与脚本的简单书写
- 深度学习【19】ncnn安卓搭建并使用自己的模型
- 苹果最新机器学习论文:使用VoxelNet进行3D物体检测
- 使用Cesium.js加载3D模型
- 使用Cesium.js加载3D模型
- 使用Three.js + Blender构建在浏览器端显示的3D模型(1)
- Genesis-3D学习手册——9.使用组件
- PythonOCC 3D图形库学习—导入STEP模型