[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[原创代码] Perl 绘制3D模型文件 - 斯坦福兔子 (ply格式)

本帖最后由 523066680 于 2017-1-10 12:06 编辑



模型文件下载地址
http://www.cc.gatech.edu/projects/large_models/bunny.html

以及针对这只兔子的渲染代码,没有做成通用的,在加载不同模型的时候需要自己调整大小和位置以适应窗口

使用说明:需要 OpenGL 模块的支持,成功渲染后,按 w a s d, j k 可以旋转观察角度。
  1. =Copy is not Right
  2.     Author: 523066680@163.com
  3.       Date: 2016-12
  4. =cut
  5. use v5.16;
  6. use IO::Handle;
  7. use OpenGL qw/ :all /;
  8. use OpenGL::Config;
  9. use Time::HiRes 'sleep';
  10. use feature 'state';
  11. STDOUT->autoflush(1);
  12. our $WinID;
  13. our $width  = 500;
  14. our $height = 500;
  15. our $rx = 0.0;
  16. our $ry = 0.0;
  17. our $rz = 0.0;
  18. my @vtx;
  19. my @faces;
  20. open READ, "<:raw", "bunny.ply";
  21. my $models = 0;
  22. for  my $e ( <READ> )
  23. {
  24.     $e =~ s/\r?\n$//;
  25.     if ($e =~ /v ([^\s]+) ([^\s]+) ([^\s]+)/i )
  26.     {
  27.         #考虑 科学表示法的情况 5.5e-05
  28.         push @vtx, [ sprintf("%f", $1) * 1500.0,
  29.                      sprintf("%f", $2) * 1500.0,
  30.                      sprintf("%f", $3) * 1500.0 ] ;
  31.     }
  32.     elsif ($e =~ /f (\d+) (\d+) (\d+)/i )
  33.     {
  34.         #某些模型文件的三角形索引从 1 开始
  35.         push @faces,
  36.             [
  37.                 $1 - 1,
  38.                 $2 - 1,
  39.                 $3 - 1
  40.             ];
  41.     }
  42.     else
  43.     {
  44.         printf("Other: $e\n");
  45.     }
  46.     if ($e =~ /feature/i )
  47.     {
  48.         $models++;
  49.         if ($models > 1)
  50.         {
  51.             #last;
  52.         }
  53.     }
  54. }
  55. close READ;
  56. printf("%d %d\n", $#vtx, $#faces);
  57. printf("%f %f %f\n", $vtx[0]->[0], $vtx[0]->[1], $vtx[0]->[2] );
  58. my @nums;
  59. grep { push @nums, @{$_} } @faces;
  60. @nums = (sort { $a <=> $b } @nums);
  61. printf("\n %d\n", $nums[$#nums]);
  62. &Main();
  63. sub normalize
  64. {
  65.     my $v = shift;
  66.     my $d = sqrt($v->[0]*$v->[0] + $v->[1]*$v->[1] + $v->[2]*$v->[2]);
  67.     if ($d == 0.0)
  68.     {
  69.         printf("length zero!\n");
  70.         return;
  71.     }
  72.     $v->[0] /= -$d;
  73.     $v->[1] /= -$d;
  74.     $v->[2] /= -$d;
  75. }
  76. sub normcrossprod
  77. {
  78.     my ( $v1, $v2, $out ) = @_;
  79.     $out->[0] = $v1->[1] * $v2->[2] - $v1->[2] * $v2->[1];
  80.     $out->[1] = $v1->[2] * $v2->[0] - $v1->[0] * $v2->[2];
  81.     $out->[2] = $v1->[0] * $v2->[1] - $v1->[1] * $v2->[0];
  82.     normalize( $out );
  83. }
  84. sub initlist
  85. {
  86.     my $idx;
  87.     my $base = glGenLists(1);
  88.     my ($a, $b, $c);
  89.     my @tpa;
  90.     my @tpb;
  91.     my @norm = ();
  92.     glNewList($base, GL_COMPILE);
  93.     glBegin(GL_TRIANGLES);
  94.     for my $i ( 0 ..  $#faces )
  95.     {
  96.         ($a, $b, $c) = @{ $faces[$i] } ;
  97.         for ( 0 .. 2 )
  98.         {
  99.             $tpa[$_] = $vtx[$b]->[$_] - $vtx[$a]->[$_] ;
  100.             $tpb[$_] = $vtx[$c]->[$_] - $vtx[$a]->[$_] ;
  101.         }
  102.         glColor3f( 0.9, 0.6, 0.2 );
  103.         normcrossprod( \@tpa, \@tpb, \@norm );
  104.         glNormal3f( @norm );
  105.         glVertex3f( @{$vtx[$a]} );
  106.         glVertex3f( @{$vtx[$b]} );
  107.         glVertex3f( @{$vtx[$c]} );
  108.     }
  109.     glEnd();
  110.     glEndList();
  111. }
  112. sub display
  113. {
  114.     my $idx;
  115.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  116.     glPushMatrix();
  117.     glRotatef($rx, 1.0, 0.0, 0.0);
  118.     glRotatef($ry, 0.0, 1.0, 0.0);
  119.     glRotatef($rz, 0.0, 0.0, 1.0);
  120.     glTranslatef(0.0, -150.0, 0.0);
  121.     glColor4f(0.8, 0.8, 0.5, 0.5);
  122.     glCallList(1);
  123.     glPopMatrix();
  124.     glutSwapBuffers();
  125. }
  126. sub init
  127. {
  128.     glClearColor(0.0, 0.0, 0.0, 0.5);
  129.     glPointSize(1.0);
  130.     glLineWidth(1.0);
  131.     glEnable(GL_DEPTH_TEST);
  132.     glEnable(GL_POINT_SMOOTH);
  133.     glEnable(GL_LINE_SMOOTH);
  134.    
  135.     my @mat_ambient = ( 0.5, 0.5, 0.5, 1.0 );
  136.     my @mat_specular = ( 1.0, 1.0, 1.0, 1.0 );
  137.     my @mat_shininess = ( 10.0 );
  138.     my @mat_diffuse = (0.5, 0.5, 0.5, 1.0);
  139.     my @light_specular = ( 0.5, 0.5, 0.5, 1.0 );
  140.     my @light_position = ( 200.0, 400.0, 0.0, 0.0 );
  141.     my $ambient  = OpenGL::Array->new( 4, GL_FLOAT);
  142.     my $specular = OpenGL::Array->new( 4, GL_FLOAT);
  143.     my $diffuse  = OpenGL::Array->new( 4, GL_FLOAT);
  144.     my $shininess = OpenGL::Array->new( 1, GL_FLOAT);
  145.     my $light_position = OpenGL::Array->new( 4, GL_FLOAT);
  146.     my $light_specular = OpenGL::Array->new( 4, GL_FLOAT);
  147.     $ambient->assign(0,  ( 0.5, 0.5, 0.5, 1.0 ) );
  148.     $specular->assign(0, ( 1.0, 1.0, 1.0, 1.0 ) );
  149.     $diffuse->assign(0,  ( 0.5, 0.5, 0.5, 1.0 ) );
  150.     $shininess->assign(0,  10.0 );
  151.     $light_position->assign(0, ( 200.0, 200.0, 0.0, 0.0 ) );
  152.     glMaterialfv_c(GL_FRONT_AND_BACK, GL_AMBIENT, $ambient->ptr );
  153.     glMaterialfv_c(GL_FRONT_AND_BACK, GL_SPECULAR, $specular->ptr );
  154.     glMaterialfv_c(GL_FRONT_AND_BACK, GL_DIFFUSE, $diffuse->ptr );
  155.     glMaterialfv_c(GL_FRONT_AND_BACK, GL_SHININESS, $shininess->ptr );
  156.     glLightfv_c(GL_LIGHT0, GL_POSITION, $light_position->ptr);
  157.     glEnable(GL_LIGHTING);
  158.     glEnable(GL_LIGHT0);
  159.     glColorMaterial(GL_FRONT, GL_DIFFUSE);
  160.     glEnable(GL_COLOR_MATERIAL);
  161.     initlist();
  162. }
  163. sub idle
  164. {
  165.     sleep 0.001;
  166.     glutPostRedisplay();
  167. }
  168. sub Reshape
  169. {
  170.     my ($w, $h) = (shift, shift);
  171.     my $half = 200.0;
  172.     my $fa = 250.0;
  173.     glViewport(0, 0, $w, $h);
  174.     glMatrixMode(GL_PROJECTION);
  175.     glLoadIdentity();
  176.     #glOrtho(-$half, $half, -$half, $half, 0.0, $fa*2.0);
  177.     gluPerspective( 90.0, 1.0, 1.0, $fa*2.0 );
  178.     glMatrixMode(GL_MODELVIEW);
  179.     glLoadIdentity();
  180.     gluLookAt(0.0,0.0,$fa,0.0,0.0,0.0, 0.0,1.0, $fa);
  181. }
  182. sub hitkey
  183. {
  184.     our $WinID;
  185.     my $k = lc(chr(shift));
  186.     given ($k)
  187.     {
  188.         when ('q') { glutDestroyWindow( $WinID ); }
  189.         when ('a') { $ry-=3.0; }
  190.         when ('d') { $ry+=3.0; }
  191.         when ('w') { $rx+=3.0; }
  192.         when ('s') { $rx-=3.0; }
  193.         when ('j') { $rz+=3.0; }
  194.         when ('k') { $rz-=3.0; }
  195.     }
  196. }
  197. sub Main
  198. {
  199.     glutInit();
  200.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE |GLUT_DEPTH |GLUT_MULTISAMPLE );
  201.     glutInitWindowSize(500, 500);
  202.     glutInitWindowPosition(1,1);
  203.     our $WinID = glutCreateWindow("bunny");
  204.     &init();
  205.     glutDisplayFunc(\&display);
  206.     glutReshapeFunc(\&Reshape);
  207.     glutKeyboardFunc(\&hitkey);
  208.     glutIdleFunc(\&idle);
  209.     glutMainLoop();
  210. }
复制代码
5

评分人数

本帖最后由 523066680 于 2017-1-10 14:21 编辑

强行转 Perl 代码发帖。

转换过程中感到的明显缺点是,大量的敲打 $ 符号。
爽快的地方:

  • given when 语句比 switch case 整洁多了。
  • 从纯文本文件中读取数据、处理数据相对方便

TOP

回复 3# codegay


    另一种扫描没这么精细的三角形网格反而好看一些。
http://graphics.stanford.edu/pub/3Dscanrep/bunny.tar.gz

bun_zipper_res3.ply



代码稍作修改

TOP

返回列表