虽然利用threejs来在网页中渲染3d模型不是第一次折腾了,但是还是遇到了各种问题。总结下我所遇到的问题,希望能给正在使用threejs的小伙伴一个帮助。

一、所使用的软件与开发环境

  1. Maya2014、Blender2.77a

  2. threejs-r82

  3. webpack + gulp

二、 动画模型的导入导出

1、格式的选择

threejs支持的动画模型有Collada(.dae)、mmd(用过MikuMikuDance的应该知道) 、fbx、json。

Collada里面包含了你场景中所有数据(camera、scene、light),因为手生所有这次没有采用这种格式。

fbx虽然网页中可以加载fbx,但我常用的是从其它软件中导个fbx给blender用。不过这里值的注意一下,以maya为栗子。

maya导出fbx的时候会有一个文件格式的选项: 二进制(导出给blender选择这种编码)ASCII(导出给threejs直接用选择这种编码)如下图所示:

2、动画的分类

  • 变形动画(threejs中MorphAnimMesh类)

变形动画简单点来说就是通过变形物体来改变物体的样子,复杂的动画用这种方法处理就不合试了,因为改变一下所有的顶点都会随之改变。数据量挺大的。

在blender中的导出json选择如下所示:

  • 骨骼动画(threejs中SkinnedMesh类)

骨骼动画也就是蒙皮动画,通过给物体绑定骨骼来对物体进行操作。

在blender中的导出json时存在以下两种情况:

1、keyframe animation 导出选项以及json代码如下所示:

2、skeletal animation 导出选项以及json代码如下所示:

3、从maya中导出fbx至blender中

  1. 在maya中导出fbx给blender的时候文件格式选择二进制

  2. 做模型绑定的时候对模型的数据进行清零(这点很重要,不然blender导出json的会出现错误情况)、绑定方法的话按照做游戏的绑定方法就可以了。

  3. 软边显示与硬边显示(导出时在maya中选择软边显示)照理说应该是硬边显示才对,瞎猜是blender与maya设置不同吧。在页面中渲染的情况如下所示:

三、 模型渲染到网页中

1、创建场景

var camera,scene,renderer

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera(40, 750 / 1200, 0.1, 10000);

renderer = new THREE.WebGLRenderer({antialias: true, alpha: false, preserveDrawingBuffer: true});

renderer.shadowMap.enabled = true;

renderer.autoClear = true;

var render = function () {

	renderer.render(scene, camera);

}
var animate = function () { requestAnimationFrame(_that.animate); render(); } //一个简单的场景就写好了

2、创建动画模型

这里我导出的是json格式的蒙皮动画所以我采用了threejs中提供的BlendCharacter()方法来创建我的动画模型。具体代码如下所示:

var createSkinningAnimate = function (model) {

    var blendMesh = new THREE.BlendCharacter();

    blendMesh.modelId = model.id;

    blendMesh.load( model.modelSrc, function(){

         blendMesh.name = model.modelName;

         blendMesh.scale.set(model.scaleX, model.scaleY, model.scaleZ);

         blendMesh.position.set(model.x, model.y, model.z);

         blendMesh.frustumCulled = false;

         blendMesh.material.transparent =  true;
//
blendMesh.material.opacity = 0; if(model.shadow) { blendMesh.castShadow = true; //表示这个物体是可以产生阴影的 } if(model.receive) { blendMesh.receiveShadow = true; //表示这个物体是可以接受(显示)阴影的 } if(model.side) { blendMesh.material.side = THREE.DoubleSide; //解决单双面显示问题 } blendMesh.visible = false; for(var i = 0, len = model.action.length; i < len; i++) { blendMesh.applyWeight( model.action[i].name, model.action[i].weight);
}; blendModelGroup.add(blendMesh); loadModelProgress(); }); }

创建这个模型的时候我遇到了两个问题:

  • 模型出现渲染的时候单双面问题吗,具体表现如下所示。

解决方法:

//设置material的side

blendMesh.material.side = THREE.DoubleSide;  //解决单双面显示问题

  • 当镜头拉近的时候模型从视野中消失,具体表现如下所示

解决方法:

//设置这个属性为false时这个bug就好了。

blendMesh.frustumCulled = false;

frustumCulled 这个属性是至今干嘛用的我不太清楚,求告知。

3、灯光渲染

场景中利用了两个灯光全局灯(AmbientLight)与聚光灯(SpotLight)代码如下:

_that.ambientLight = new THREE.AmbientLight( 0xffffff);

scene.add(_that.ambientLight);

var spotLight = new THREE.SpotLight(0xffffff);

_that.spotLight = spotLight;

spotLight.angle = 0.74;
spotLight.position.set(0, 60, -1);
spotLight.castShadow = true;
spotLight.penumbra = 0.7;
spotLight.intensity = 2;
spotLight.distance = 200;
spotLight.shadow.camera.near = 50;
spotLight.shadow.camera.far = 200;
spotLight.shadow.camera.fov = 35;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.mapSize.width = 1024; spotLight.name = 'spotLight'; scene.add(spotLight); spotLight.target.position.set(-15,0,0); //scene.add(new THREE.SpotLightHelper( spotLight )); scene.add(spotLight.target);

灯光的调试主要靠guiLightHelper,这两个东西调试起来非常方便省了不少时间。调试前与调试后如图所示:

5、调试技巧

  • gui

  • helper

  • topView

helper:threejs的相机、灯光都提供了Helper这个方法,在页面中渲染添加一个参考线。

topView: 意思就是在页面中渲染一个顶视图,如果需要做相机的移动这个方法比较靠谱可以清楚的看见相机是这么运动的。然后发现问题的所在。渲染如下图所示:

实现代码:

var testW = 750,
testH = 1200; var views = {
left: 0.5,
bottom: 0,
width: 0.5,
height: 0.5,
eye: [0, 0, 50],
direction: [-1, 0, 0]
}; var orthoCam = new THREE.OrthographicCamera(testW / -2, testW / 2, testH / 2, testH / -2, -500, 10000);
view.orthoCam = orthoCam; update () {
var left = Math.floor( testW * 0.0 );
var bottom = Math.floor( testH * 0 );
var width = Math.floor( testW * 1.0 );
var height = Math.floor( testH * 1.0 ); renderer.setViewport( left, bottom, width, height );
renderer.setScissor( left, bottom, width, height );
renderer.setScissorTest ( true ); camera.updateProjectionMatrix(); cameraHelper.update();
cameraHelper.visible = false; renderer.render(scene, camera);
cameraHelper.visible = true; var view = views;
orthoCam = view.orthoCam;
orthoCam.left = testW / - 2;
orthoCam.right = testW / 2;
orthoCam.top = testH / 2;
orthoCam.bottom = testH / - 2;
orthoCam.position.x = view.eye[ 0 ];
orthoCam.position.y = view.eye[ 1 ];
orthoCam.position.z = view.eye[ 2 ];
orthoCam.rotation.x = view.direction[ 0 ] * Math.PI * 0.5;
orthoCam.rotation.y = view.direction[ 1 ] * Math.PI * 0.5;
orthoCam.rotation.z = view.direction[ 2 ] * Math.PI * 0.5;
orthoCam.updateProjectionMatrix(); var left1 = Math.floor( testW * view.left );
var bottom1 = Math.floor( testH * view.bottom );
var width1 = Math.floor( testW * view.width );
var height1 = Math.floor( testH * view.height );
renderer.setViewport( left1, bottom1, width1, height1 );
renderer.setScissor( left1, bottom1, width1, height1 );
renderer.setScissorTest ( true );
renderer.shadowMap.enabled = true;
renderer.render( scene, orthoCam );
}

核心创建一个正交相机OrthographicCamera

6、兼容判断

因为不是所有手机都支持webgl所以需要做一下兼容性的判断。

  • 在ios8虽然支持webgl但是时间跟踪clock不支持,但在不报错。查看源码的情况下估计是var newTime = ( performance || Date ).now()没有得到正确的值。因为时间关系没有过多的深入,所以页面在ios8直接跳转至2d版本。

-getExtension('WEBGL_depth_texture')经过测试在一些安卓上返回为null,所以没有用这个去做区分。

兼容代码如下所示:

var canvas = document.createElement("canvas");
var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if( gl ){ var OES_TextureExtension = gl.getExtension('OES_texture_half_float'); var EXT_TextureExtension = gl.getExtension( 'EXT_texture_filter_anisotropic' );
} if(gl && OES_TextureExtension && EXT_TextureExtension&& !(isIos && version < 9)) { //..3d code }else { //..2d code };

TODO:

虽然这个项目上线了,但是还有很多东西需要去细化完善- -!!。

  1. 更好的完成相机的移动

  2. 人物的动画拆分

  3. 整个场景动画优化

之前用threejs做的一个小项目点击这里查看

最后附上体验地址:

从Maya中把模型搬运至网页的过程的更多相关文章

  1. C#开发BIMFACE系列38 网页集成开发2:审图系统中的模型或图纸批注

    系列目录     [已更新最新开发文章,点击查看详细] 在运维或协同的场景中,经常需要对模型或图纸进行批注,及时记录已发现的问题并交给相关负责的人员. 在开始实现功能之前,先了解一下BIMFACE中有 ...

  2. 从Maya中导入LightMap到unity中

    导入步骤 1.在Maya中为每一个模型烘焙好帖图(tif格式),会发现烘焙好的图和UV是一一对应的 2.把模型和烘焙帖图导入到Unity中 3.选中材质,修改Shader为 Legacy Shader ...

  3. maya中MFnMesh.h使用说明的翻译

    由于最近要修改一个maya中的deformer脚本,于是开始系统学习openMaya的一些知识,当然少不了得把一堆头文件说明看一遍.首先把MFnMesh.h这个文件翻译一下吧,不废话,上译文: 首先M ...

  4. unity3d 资源文件从MAX或者MAYA中导出的注意事项

    unity3d 资源文件从MAX或者MAYA中导出的注意事项     1.首先,Unity3d 中,导出带动画的资源有2种导出方式可以选择:    1) 导出资源时,只导出一个文件,保留模型,骨骼和所 ...

  5. 总结一下一般游戏中3D模型各种勾边方法遇到的工程性问题

    以前做过简单的rim light勾边,几何勾边,这次又做了后处理的勾边,工程化的时候,都遇到很多问题,简单总结一下. 首先是火炬之光勾边效果,类似轮廓光的实现,简单的卡通渲染也是通过类似的算法加采样色 ...

  6. 15SpringMvc_在业务控制方法中写入模型变量收集参数,且使用@InitBind来解决字符串转日期类型

    之前第12篇文章中提到过在业务控制方法中写入普通变量收集参数的方式,也提到了这种凡方式的弊端(参数很多怎么办),所以这篇文章讲的是在业务控制方法中写入模型变量来收集参数.本文的案例实现的功能是,在注册 ...

  7. ThinkPHP中的模型二

    ThinkPHP中的模型 1.为什么要创建数据对象 案例:使用ThinkPHP完成部门管理 ① 设计数据库 ② 创建Dept控制器 路径:./Application/Admin/Controller创 ...

  8. ThinkPHP中的模型

    ThinkPHP中的模型 1.什么是模型(Model) 模型表示企业数据和业务规则,实际项目开发中,主要实现与数据库进行操作. 2.模型的定义规则 模型类的命名规则是除去表前缀的数据表名称,采用驼峰法 ...

  9. 从3dmax中导入模型到UDK Editor(供个人备忘)

    笔记从3dmax中导入模型到UDK Editor 1)      在3dmax中导出 2)      选择FBX格式,保存 3)      在UDK中打开content browser,自己选个pac ...

随机推荐

  1. SQL:指定名称查不到数据的衍伸~空格 换行符 回车符的批量处理

    异常处理汇总-数据库系列  http://www.cnblogs.com/dunitian/p/4522990.html 先看看啥情况 复制查询到的数据,粘贴一下看看啥情况 那就批量处理一下~ 就这样 ...

  2. CoreCRM 开发实录——开始之新项目的技术选择

    2016年11月,接受了一个工作,是对"悟空CRM"进行一些修补.这是一个不错的 CRM,开源,并提供一个 SaaS 的服务.正好微软的 .NET Core 和 ASP.NET C ...

  3. 深入浅出JavaScript之闭包(Closure)

    闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面写下我的学习笔记~ 闭包-无处不 ...

  4. winform异步加载数据到界面

    做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowD ...

  5. 拦截UIViewController的popViewController事件

    实现拦截UIViewController的pop操作有两种方式: 自定义实现返回按钮,即设置UIBarButtonItem来实现自定义的返回操作. 创建UINavigatonController的Ca ...

  6. 解决WINDOWS防火墙开启后Ping不通

    WINDOWS系统由于安全考虑,当开启防火墙时,默认不允许外主机对其进行ping功能,即别的电脑ping不通本机.别的主机ping不通本机是因为本机的防火墙关闭了ICMP回显功能,只要把这回显功能打开 ...

  7. Windows Server 2008 R2常规安全设置及基本安全策略

    这篇文章主要介绍了Windows Web Server 2008 R2服务器简单安全设置,需要的朋友可以参考下 用的腾讯云最早选购的时候悲催的只有Windows Server 2008 R2的系统,原 ...

  8. .NET Core性能测试组件BenchmarkDotNet 支持.NET Framework Mono

    .NET Core 超强性能测试组件BenchmarkDotNet 支持Full .NET Framework, .NET Core (RTM), Mono. BenchmarkDotNet支持 C# ...

  9. 【初码干货】在Window Server 2016中使用Web Deploy方式发布.NET Web应用的重新梳理

    在学习和工作的过程中,发现很多同事.朋友,在做.NET Web应用发布的时候,依然在走 生成-复制到服务器 这样的方式,稍微高级一点的,就是先发布到本地,再上传到服务器 这种方式不仅效率低下,而且不易 ...

  10. 《深入理解Java虚拟机》调优案例分析与实战

    上节学习回顾 在上一节当中,主要学习了Sun JDK的一些命令行和可视化性能监控工具的具体使用,但性能分析的重点还是在解决问题的思路上面,没有好的思路,再好的工具也无补于事. 本节学习重点 在书本上本 ...