虽然利用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. MIP 官方发布 v1稳定版本

    近期,MIP官方发布了MIP系列文件的全新v1版本,我们建议大家尽快完成升级. 一. 我是开发者,如何升级版本? 对于MIP页面开发者来说,只需替换线上引用的MIP文件为v1版本,就可以完成升级.所有 ...

  2. “四核”驱动的“三维”导航 -- 淘宝新UI(需求分析篇)

    前言 孔子说:"软件是对客观世界的抽象". 首先声明,这里的"三维导航"和地图没一毛钱关系,"四核驱动"和硬件也没关系,而是为了复杂的应用而 ...

  3. C++中的const

    一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...

  4. 获取微软原版“Windows 10 推送器(GWX)” 卸载工具

    背景: 随着Windows 10 免费更新的结束,针对之前提供推送通知的工具(以下简称GWX)来说使命已经结束,假设您还未将Windows 8.1 和Windows 7 更新到Windows 10 的 ...

  5. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  6. Velocity初探小结--Velocity在spring中的配置和使用

    最近正在做的项目前端使用了Velocity进行View层的数据渲染,之前没有接触过,草草过了一遍,就上手开始写,现在又回头细致的看了一遍,做个笔记. velocity是一种基于java的模板引擎技术, ...

  7. WebApi基于Token和签名的验证

    最近一段时间在学习WebApi,涉及到验证部分的一些知识觉得自己并不是太懂,所以来博客园看了几篇博文,发现一篇讲的特别好的,读了几遍茅塞顿开(都闪开,我要装逼了),刚开始读有些地方不理解,所以想了很久 ...

  8. C# 序列化与反序列化几种格式的转换

    这里介绍了几种方式之间的序列化与反序列化之间的转换 首先介绍的如何序列化,将object对象序列化常见的两种方式即string和xml对象; 第一种将object转换为string对象,这种比较简单没 ...

  9. Register-SPWorkflowService 404

    最近需要做一个SharePoint 2013工作流演示环境. 于是在自己的本子上安装了一个虚拟机. 虚拟机操作系统是Windows Server 2012 R2,计划把AD.SQL Server 20 ...

  10. Maven安装

    开发分布式的商场系统,用到了一些新的技术,做一个记录和分享 这里讲一下maven安装 首先什么是Maven Maven作为一个构建工具,不仅帮我们自动化构建,还能抽象构建过程,提供构建任务实现.他跨平 ...