5款最好用的免费3D建模软件(附下载链接)
虽然网上有需要现成的免费三维模型,但对于许多人而言,3D打印机最吸引他们之处是可以设计创造完全属于自己的模型。问题是,现代专业级CAD软件大多价格高昂,例如Solidworks或Zbrush这样的程序至少需要1000美元,大多数普通用户并不愿意为此买单。幸运的是,业内还有不少免费的CAD软件,并且可以提供专业级的设计能力,本文介绍了其中最好的5款免费在线CAD软件工具。(部分软件功能可能需要少量月租)
Blender
▲Blender还提供动画工具
▲Blender3.2.1界面
Blende是一款系统全面的3D建模套件,它提供了大量专业级功能和模块,目前并已成为免费3D软件的代名词。Blender通常被称为TheBlenderProject,因为它不仅仅是一个软件,还是一个完整的社区,致力于创建最完整的3D建模和动画开发方案。并且这款软件是开源的,每天都有开发者提供新的模块和插件,软件也在不断更新。
这款软件的用户评价比较高,偶有的抱怨也是它的界面有点差,然而这是由于社区过于庞大,需要在线提供教程过多,有时会让部分用户迷茫。另外,Blender不仅仅是3D设计造型,它允许用户研究甚至创作自己动画,使用Blender创建的一些动画甚至会让Pixar的顶级设计师脸红。总体来看,Blender社区非常强大,令人印象深刻。
使用难度:4/5
功能集合:4/5
目标用户:需要高级3D建模功能,各种华丽效果的人
TinkerCAD
▲在TinkerCAD中设计的扳手
TinkerCAD由行业标准软件公司AutoDesk出品,是一款友好型初级三维CAD软件。虽然他不是这个列表中最强大的软件,TinkerCAD也提供了很多令人惊讶的功能,他特别适合初次使用者,但也适用于最资深的CAD用户。这款软件提供了一批快速简便的建模方法,例如,如果你想制作一个立方体,你可以拖放立方体,输入你的测量数据,然后就完成了。
TinkerCAD堪称一款“所见即所得”工具,他有许多预先设计可供选择,使用者可以根据自己的需要进行修改。虽然在艺术造型功能方面比较薄弱,但它可以非常简单友好的方式进行准系统3D设计。此外,TinkerCAD也有一个非常专业的在线社区,允许用户看到这个基本的,完全基于云的3D CAD软件的潜力。
使用难度:1/5
功能集合:2/5
目标用户:初级CAD设计师和想要创建基本3D模型的人
下载地址: https://www.tinkercad.com/
Fusion360
▲Fusion360提供了大量的教程来制作出色的模型
AutoDesk还提供了面向学生的产品Fusion360,这款软件对教育工作者和学术机构免费。Fusion360比TinkerCAD强大的多,但并不一定是初学者可以直接使用的产品,因此AutoDesk为那些想要专研和学习的人提供了一个完整的教程套件。
与TinkerCAD非常相似,Fusion360提供的所有文件都完全基于云。它允许用户在项目中保存各种模型并测试它们,以查看它们在相互交互时将承受的压力。虽然没有在角色建模的方式中提供大型套件,但是有一些小功能允许用户使用网格创建和精细造型。
此外,这款软件还有大量的3D打印机集成,可以与切片软件配合使用,进一步简化您的工作流程。Fusion360是TinkerCAD的进阶版,对于已经掌握TinkerCAD基础知识和操作的人,这款软件非常适合。
使用难度:3/5
功能集合:4/5
目标用户:需要比具有许多工程功能的TinkerCAD更高级别的定制的用户。
下载地址: https://www.autodesk.com/products/fusion-360/students-teachers-educators
OnShape
▲OnShape提供多部件装配和力学测试集成
就功能而言,OnShape可以说是本文中最令人印象深刻的软件。它由两位前Solidworks首席执行官JonHirschtick和JohnMcEleney共同创建,完全免费并且完全基于云端。
OnShape毫无疑问是免费在线CAD软件选项中功能最多、最轻量级的,也是唯一一款拥有Android和iOS应用程序的应用程序,允许您从平板电脑或智能手机查看和修改设计。OnShape提供了许多先前在Fusion360中提到的类似功能,例如模拟多部件组件的功能。
而在工程集成方面,OnShape也并不逊色,它完美地将整个工程工作流程从头到尾简化为一个完全基于云的模型。此外,还有大量的自定义功能,这将吸引许多熟悉其他程序(如AutoCAD或Solidworks)的CAD用户。2016年,Onshape添加了一项名为FeatureScript的功能,这是一种用于创建和自定义CAD功能的新型开源编程语言。毫无疑问,OnShape是目前地球上最强大的免费CAD软件。
使用难度:4/5
功能集合:5/5
目标用户:需要最多功能和工程功能的高级用户
下载地址: https://www.onshape.com/
Sculptris
▲在Sculptris模仿和绘制恐龙
Sculptris可以将工程部件转移到建模软件,出自ZBrush的作者,这款软件可以使用虚拟粘土球进行建模,它允许推、拉、捏等等动作,以创建连贯的网格,并且可以立即3D打印。Sculptris有一些轻微的缺点,因为有时你需要修复像MakePrintable这样的模型,但Sculptris的极端用户友好设计和直观界面远远超过了它的缺点,笔者几乎没有3D动物建模经验,都能够在很短的时间内以非常小的指令做出一头猪的模型。
如果你已经拥有ZBrush,Sculptris可以通过GoZ按钮与软件集成,从而可以在ZBrush界面中进一步建模您的项目。就创建静态3D模型而言,Sculptris的可能性几乎是无穷无尽的,网上有大量的艺术作品和教程可供选择。Sculptris非常适合3D建模的初学者,并且非常适用于3D打印。
使用难度:2/5
功能集合:3/5
目标用户:建模者/数字艺术家/3D角色创作者
下载地址: http://pixologic.com/sculptris/
其实呢,类似的3D建模软件还有很多,比如知名的3DS Max,Maya等,但3DS Max,Maya都需一两百块钱,相比于Blender,贵而且不太实用,功能较复杂,容易搞混。这7款建模软件(包括3DS Max,Maya)我最推荐Blender3.2.1,功能实而不华,非常好用。
宇宙之大,无奇不有(一个玩暗区的人): 问一下能不能运行(a+b)/c这种的。
yshz673: 这玩意用多了会退登
2301_80103301: 你好,为什么我运行不出来啊
acan___: #pragma once #include<iostream> #include<Windows.h>//定义控制台应用程序的入口点 using namespace std; //界面颜色 void setcolor(char str[]) { if(str=="lightblue") SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|1); if(str=="lightred") SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED); if(str=="lightyellow") SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE); if(str=="lightpink" ) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE); if(str=="blue") SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE); if(str=="red") SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED); if(str=="yellow") SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE); if(str=="pink") SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE); if(str=="lightgray") SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN |8); if(str=="gray") SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 8); else return; } //定义敌人结构 其中最后面Frame代表结构体类型 若不加typedef代表定义的结构体变量 typedef struct Frame { COORD position[2]; // COORD 是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标。 // 其定义为: // typedef struct _COORD { // SHORT X; // SHORT Y; // } COORD; int flag; }Frame; class Game { public: COORD position[10]; COORD bullet[10];//子弹坐标 Frame enemy[8];//敌人数量 int score; int rank;//级别,难度 int rankf;//等级标志 string title; int flag_rank;//等级标志 //构造函数 Game(); //初始化所有 //设定位置 void initPlane(); void initBullet(); void initEnemy(); //填充所有 --画出形状和消失的形状 void drawPlane(); void drawPlaneToNull(); void drawBullet(); void drawBulletToNull(); void drawEnemy(); void drawEnemyToNull(); //执行某一个操作 void Playing();//游戏主循环 void planeMove(char x);//飞机移动 void judgePlane();//判断飞机是否与障碍物重叠 void GameOver();//游戏失败 void Pause();// 该成员函数用来使得游戏暂停 void Shoot();//发射子弹 void bulletMove();//子弹移动 void drawThisBulletToNull(COORD c);//画出失效子弹 void judgeEnemy();//判断子弹是否击中障碍物 void drawThisEnemyToNull(Frame f); //击败的障碍物清空 void enemyMove();//障碍物移动 void printScore();//输出分数 }; //主菜单 int drawMenu(); //隐藏光标 void HideCursor(); void SetPos(int i, int j);//设置光标 COORD random(COORD a, COORD b);//产生随机障碍物位置 void drawFrame(COORD a, COORD b, char row, char col);//画出障碍物 //把第y行,[x1, x2) 之间的坐标填充为 ch void drawRow(int y, int x1, int x2, char ch); //把第x列,[y1, y2] 之间的坐标填充为 ch void drawCol(int x, int y1, int y2, char ch); // 绘制游戏界面 void drawPlaying(); void drawFrame(Frame frame, char row, char col);//画坠毁后的战机 // 该函数用来判断战机的某一部分是否与障碍物有接触 bool judgeCoordInFrame(Frame frame, COORD spot); void drawRow(COORD a, COORD b, char ch); #include<Windows.h> #include<conio.h> #include<iostream> #include<ctime> #include<string> using namespace std; Game::Game() { // 调用类成员函数来进行初始化 initPlane(); initBullet(); initEnemy(); // 初始化四个int型数据成员,采用赋值的方式进行初始化 // string类型的数据成员title没有进行初始化,因为: // string本身就是一个标准库类类型,它的类定义中设置了默认构造函数, // 这些默认构造函数会将对象初始化为合理的默认状态, // string的默认构造函数会产生空字符串,相当于"" 。 this->score = 0; rank = 25; rankf = 25; flag_rank = 0; } void Game::initPlane() { COORD centren; centren.X = 39; centren.Y = 22; position[0].X = position[5].X = position[7].X = position[9].X = centren.X; position[1].X = centren.X - 2; position[2].X = position[6].X = centren.X - 1; position[3].X = position[8].X = centren.X + 1; position[4].X = centren.X + 2; for (int i = 0; i <= 4; i++) { position[i].Y = centren.Y; } for (int i = 6; i <= 8; i++) { position[i].Y = centren.Y + 1; } position[5].Y = centren.Y - 1; position[9].Y = centren.Y - 2; // 这个函数体类的代码其实就是为了初始化战机的十个部分的位置,战机的组成如下所示: // | 5 // | 9 // ***** 12034 // *** 678 // 第一排5个0的坐标依次对应了position[1]position[2]position[0]position[3]position[4] // 第二排三个0的坐标依次对应了position[6]position[7]position[8] // 两排0上面的两|的坐标从上往下依次对应了position[5]position[9] } void Game::drawPlane() { for (int i = 0; i < 9; i++) { SetPos(position[i].X,position[i].Y); if (i != 5) { setcolor("yellow"); cout << "*"; } else if (i == 5) { setcolor("yellow"); cout << "|"; } } } // 这个成员函数通过将战机的每个坐标处输出" "来代替"0"和"|", // 来达到将战机消除的目的。 void Game::drawPlaneToNull() { for (int i = 0; i < 9; i++) { SetPos(position[i].X, position[i].Y); cout << " "; } } // 该成员函数用来初始化子弹, // 即将每个子弹的Y坐标初始化为30(bullet[i].Y = 30)来表示子弹处于失效状态 void Game::initBullet() { for (int i = 0; i < 10; i++) { bullet[i].Y = 30; } } // 该成员函数用来画出子弹 // 首先检查每颗子弹的有效性,如果子弹有效,则定位到该子弹的坐标处,输出 "^",表示该子弹, // 如果子弹是无效的,则不绘制 void Game::drawBullet() { for (int i = 0; i < 10; i++) { if (bullet[i].Y != 30) { SetPos(bullet[i].X,bullet[i].Y); setcolor("blue"); cout << "^"; } } } //子弹失效 void Game::drawBulletToNull() { for (int i = 0; i < 10; i++) if (bullet[i].Y != 30) { SetPos(bullet[i].X, bullet[i].Y + 1); cout << " "; } } // 这个函数用来初始障碍物的位置, // 屏幕当中只能同时存在八架障碍物, // 且每架障碍物用如下结构体Frame来表示,如下所示: // typedef struct Frame // { // COORD position[2]; // int flag; // }Frame; COORD random(COORD a, COORD b) { int x = rand() % (a.X - b.X) + a.X; int y = rand() % (a.Y - b.Y) + a.Y; COORD c = { x,y }; return c; } void Game::initEnemy() { COORD a = { 1, 1 }; COORD b = { 45, 15 }; for (int i = 0; i < 8; i++) { enemy[i].position[0] = random(a, b); // random(a, b)是调用了一个重载的函数,它表示在坐标a、b之间的矩形框 // 内随机生成一个坐标值,并将该坐标值作为障碍物的左上角的坐标。 // enemy[i].position[0]中是一个Frame结构体类型的变量,存放了障碍物i的左上角的坐标。 enemy[i].position[1].X = enemy[i].position[0].X + 3; enemy[i].position[1].Y = enemy[i].position[0].Y + 2; // enemy[i].position[1]也中是一个Frame结构体类型的变量,存放了障碍物i的右下角的坐标。 } } // 接下来要根据障碍物的左上角坐标和右下角坐标画出障碍物, // 显然,障碍物的外形如下所示: // -- // | | // -- void Game::drawEnemy() { for (int i = 0; i < 8; i++) { setcolor("gray"); drawFrame(enemy[i].position[0], enemy[i].position[1], '-', '|'); } } // 将障碍物消除,通过输出空白的方式 void Game::drawEnemyToNull() { for (int i = 0; i < 8; i++) { drawFrame(enemy[i].position[0], enemy[i].position[1], ' ', ' '); } } //隐藏光标 void HideCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1,0 };//第二个值0表示隐藏光标 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); } void SetPos(int i, int j)//设置坐标点位(光标) { HANDLE hout; COORD coord; coord.X = i; coord.Y = j; hout = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hout, coord); } //左上角坐标、右下角坐标、用row填充行、用col填充列 void drawFrame(COORD a, COORD b, char row, char col) { drawRow(a.Y, a.X + 1, b.X - 1, row); drawRow(b.Y, a.X + 1, b.X - 1, row); drawCol(a.X, a.Y + 1, b.Y - 1, col); drawCol(b.X, a.Y + 1, b.Y - 1, col); } //把第y行,[x1, x2) 之间的坐标填充为 ch void drawRow(int y, int x1, int x2, char ch) { SetPos(x1, y); for (int i = 0; i <= (x2 - x1); i++) { cout << ch; } } //把第x列,[y1, y2] 之间的坐标填充为 ch void drawCol(int x, int y1, int y2, char ch) { int y = y1; while (y != y2 + 1) { SetPos(x, y); cout << ch; y++; } } //主菜单绘制 int drawMenu() { setcolor("lightgreen"); system("Title 飞 机 大 战"); SetPos(30,1); cout << "飞 机 大 战"; drawRow(3, 0, 79, '-'); drawRow(5, 0, 79, '-'); SetPos(28, 4); setcolor("red"); cout << "↑和↓选择,回车确定"; int j = 11; SetPos(12, j); cout << ">>"; SetPos(15, 11); cout << "1. 简单的任务"; SetPos(15, 13); cout << "2. 困难的任务"; drawRow(20, 0, 79, '-'); SetPos(47, 11); setcolor("yellow"); cout << "简单的任务:"; SetPos(51, 13); cout << "简单任务的自动飞行速度较慢,任务难度较小。 "; SetPos(30, 21); setcolor("lightblue"); cout << "纳米核心"; setcolor("red"); drawRow(22, 0, 79, '-'); while (true) { if (_kbhit()) { char x = _getch(); switch (x) { case 72: { if (j == 13) { SetPos(12, j); cout << " "; j = 11; SetPos(12, j); setcolor("red"); cout << ">>"; SetPos(51, 13); cout << " "; SetPos(47, 11); setcolor("yellow"); cout << "简单的任务:"; SetPos(51, 13); cout << "简单任务的自动飞行速度较慢,任务难度较小。 "; } break; } case 80: { if (j == 11) { SetPos(12, j); cout << " "; j = 13; SetPos(12, j); setcolor("red"); cout << ">>"; SetPos(51, 13); cout << " "; SetPos(47, 11); setcolor("yellow"); cout << "困难的任务:";