从Maya中把模型搬运至网页的过程
晓晓 2018-03-08 来源 :网络 阅读 1542 评论 0

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

虽然利用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直接用选择这种编码)如下图所示:

从Maya中把模型搬运至网页的过程

2、动画的分类

变形动画(threejs中MorphAnimMesh类)

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

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

从Maya中把模型搬运至网页的过程

骨骼动画(threejs中SkinnedMesh类)

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

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

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

从Maya中把模型搬运至网页的过程

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

从Maya中把模型搬运至网页的过程

3、从maya中导出fbx至blender中

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

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

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

从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();
    });
}

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

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

从Maya中把模型搬运至网页的过程

解决方法:

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

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

从Maya中把模型搬运至网页的过程

解决方法:

//设置这个属性为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);

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

从Maya中把模型搬运至网页的过程

5、调试技巧

gui


helper


topView


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

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

从Maya中把模型搬运至网页的过程

实现代码:

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.整个场景动画优化


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标常用软件Maya频道!


本文由 @晓晓 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程