专栏首页大史住在大前端【带着canvas去流浪(14)】Three.js中凹浮雕模型的生成方式

【带着canvas去流浪(14)】Three.js中凹浮雕模型的生成方式

目录

示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:《大史住在大前端》原创博文目录 华为云社区地址:【你要的前端打怪升级指南】

浮雕模型,简单地说就是在木板上刻字时所形成的效果,如果把字的部分都剔除掉,就得到一个凹浮雕模型,如果把字以外的部分都剔除掉,就得到一个凸浮雕模型。本文分别对利用Three.js在Web环境中生成凹浮雕模型时的几种策略进行讲解。

一. 方案1:ThreeBSP.js或ThreeCSG.js扩展库

在众多技术博客里,提及最多的就是上述两个库,它们声称是Three.js的扩展库,用来对模型进行实体布尔操作。

But!不要用!不要用!不要用!

查看github的仓库就可以发现,这两个库早在N年前已经停止维护,完全是没有保障的。而笔者亲测后发现除了官方提供的示例外,它们连最基本的立方体挖孔都无法做到,按照官方示例的写法最终只得到了下面的模型,而笔者原本的期望是在大立方体上挖出一个小立方体凹槽,字体模型就更不用提了。

二. 方案2:平面镂空模型拉伸

由于期望实现的凹浮雕模型并不算复杂,可以换一种实现思路,先在平面上生成一个矩形,然后从其中去掉字体的形状,最后再将剩余的部分拉伸成几何体,当然如果期望的浮雕模型并没有完全穿过毛坯模型时,还需要使用一个额外的立方体来补全剩余的部分。

字体文件的加载是异步的,当完成加载后,就可以获得字体对象,将它传入下面的函数来生成一个大小为40M字符,它本质上是一个shape实例,将其作为参数就可以生成拉伸体模型:

所有的shape实例都有holes属性,顾名思义它就是用来在封闭的平面图形上进行挖孔操作的,正好符合凹浮雕模型的制作需求,我们只需要生成一个尺寸略大于字体模型包围盒的矩形,然后将字体模型的数据填入包围盒shape实例的holes数组中,Three.js就可以自动将其识别为孔:

关键代码如下所示(完整示例可在附件或文章开头的github仓库中获取):

/*在平面上生成镂空字体*/
    function calcShape(font) {
        fontShape = font.generateShapes('M',40);
        boxShape = new THREE.Shape();
        boxShape.moveTo(-20,-20);
        boxShape.lineTo(50,-20);
        boxShape.lineTo(50,50);
        boxShape.lineTo(-20,50);
        boxShape.lineTo(-20,-20);
        boxShape.holes.push(fontShape[0]);
        return boxShape;
}
/*生成拉伸体*/
 textGeometry = new THREE.ExtrudeGeometry(calcShape(font), {
                    depth:10,
                    bevelEnabled: false,
                    curveSegments: 4
                });

对于更为复杂的模型,这种方式仍然显得不够直观。

三. 方案3:Cinema 4D建模后输出模型文件

Three.js这种基于编程的建模方式并不够直观,面对复杂模型时,通用的解决办法是使用三维建模软件进行模型构建,然后导出Three.js能够识别的模型文件,使用加载器载入后再对模型进行微调,Three.js为数十种通用的三维模型文件都提供了加载器,本节以C4D为例演示基本的实现过程,如果你它的基本使用方法还不清楚,可以在【慕课网】上找到免费的使用教程。

C4D的主界面如下所示,建模的主要工具主要在图中红框标记的部分:

在图标上长按左键就可以看到每个大类详细的功能:

本例中恰好每个大类均用到一个功能(上图中红框标记的功能),立方体功能生成立体包围盒毛坯模型,文本功能生成需要雕刻的文字,使用挤压功能生成一个拉伸体对象后,在界面右侧的对象管理面板中将“文本模型”拖放到挤压文字上,就可以得到一个基于文本形状的拉伸体,最后生成一个实体布尔模型,在对象管理面板中将立方体挤压体依次拖放到对象名布尔这两个字上,它们就会成为布尔运算的成员,在布尔模型的配置中将操作类型选择为A减B,就可以得到凹浮雕模型了。建模的通用思路就像是函数式编程,先指定操作,再传入数据。

Three.js官方建议的模型格式为*.gltf格式,想要在C4D中直接导出这种格式需要安装相应的插件(GLTF格式工具仓库)。本例中我们采用另一种方式来实现,先在“文件”菜单中选择“导出”得到模型文件,本例中以*.obj扩展名为例。如果添加了表面材质,生成obj数据的同时还会带有一个同名的mtl文件(Material Template Library),它携带着obj几何体表面的材质信息,接下来使用命令行工具obj2gltfnpm上可以直接搜出来)对导出的文件进行格式转换,最后只需要将生成的marvel.gltf文件利用Three.js提供的GLTFLoader加载器导入到网页中即可,相关代码如下:

// instantiate a loader
    var loader = new THREE.GLTFLoader();

    // load a resource
    loader.load(
        // resource URL
        'assets/marvel.gltf',
        // called when resource is loaded
        function (event) {
            console.log(event);
            event.scene.scale.set(0.2,0.2,0.2);
            scene.add(event.scene);
            render();
        },
        // called when loading is in progresses
        function (xhr) {
            console.log((xhr.loaded / xhr.total * 100) + '% loaded');
        },
        // called when loading has errors
        function (error) {
            console.log('An error happened');
        }
    );

可以看到网页中加载的模型既包含了凹浮雕模型,也包含了我们在建模软件中添加的蓝色材质(途中的亮蓝色区域是点光源照射的效果)。

本节的示例Demo可在文章开头的github仓库中获取到,如果觉得对你有用,可以在仓库帮我点个星星~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2018年8月中级前端开发推荐书籍

    推荐理由:曾经有一个前端大神说过,如果你想成为前端架构师,首先你得忘记自己是个前端。

    大史不说话
  • Angularjs1.X进阶笔记(1)—两种不同的双向数据绑定

    html-Controller的双向数据绑定,在开发中非常常见,也是Angularjs1.x的宣传点之一,使用中并没有太多问题。

    大史不说话
  • React组件方法中为什么要绑定this

    上例仅仅是一个组件类的定义,当在其他组件中调用或是使用ReactDOM.render( )方法将其渲染到界面上时会生成一个组件的实例,因为组件是可以复用的,面向...

    大史不说话
  • 腾讯AI Lab开源世界首款自动化模型压缩框架PocketFlow:将深度学习装进口袋

    ? 导语:腾讯AI Lab机器学习中心今日宣布成功研发出世界上首款自动化深度学习模型压缩框架——PocketFlow,并即将在近期发布开源代码。这是一款面向移...

    腾讯技术工程官方号
  • 业界 | 腾讯 AI Lab 正式开源PocketFlow,让深度学习放入手机!

    项目访问地址:https://github.com/Tencent/PocketFlow

    机器之心
  • 开发 | 谷歌对无监督解耦方法进行了大规模评估,还开源了用来实验的开发库!

    AI 科技评论按:如何能够以无监督的方式去理解高维数据,并进一步将这些知识提炼为有用的表示仍然是深度学习中的一个关键难题。该问题的一种解决方法便是解耦表示(di...

    AI科技评论
  • 学习asp.net_IIS6.0进程模型

    如果Web服务器操作系统是Windowsserver2003,则IIS6.0进程模型是asp.net的默认选择。其名称明确之处,该模型需要IIS6.0、然后,在...

    习惯说一说
  • android 两个APK调用

    @Override     public boolean onTouchEvent(MotionEvent event) ...

    用户2192970
  • ML基石_HW0

    Let C(N, K) = 1 for K = 0 or K = N, and C(N, K) = C(N − 1, K) + C(N − 1, K − 1) ...

    用户1147754
  • 8.实战篇_关于前端路由

    写在前面的话:有的读者提意见“文字太多,图片太少,不活泼可爱”,我已经尽力了。 1.一张图理解“页面路由” 这就是页面路由,很古老的J2EE开发,一般一个页面路...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券