使用Three.js + Blender构建在浏览器端显示的3D模型(5)

第四章 使用three.js加载以图片为纹理的模型(下)

在上一章里,为了演示的方便,我们选择了一个简单的模型。但是如前所述,在实际的生产环境中,一方面我们的模型更为复杂,另一方面我们的贴图也不是普通的照片,而是处理过的uv图。uv图就是xyz三维图通过变换形成的二维图,类似数学里面学的极坐标变换。UV图的制作可以借用一些软件工具完成,在blender里面也有UV图编辑器。

这一节我们选用three.js官方例程中的一个加载头部模型的示例。原示例有三百多行代码,我把它精简到一百行多一点,包括扩了核心的uv图加载显示部分。而更多的处理代码则直接删掉,虽然显示效果因此差了一些,但精简的代码更适合说明和演示。

效果图如下:

对应的代码如下:

var container, loader;
var camera, scene, renderer;
var mesh, directionalLight;
var mouseX = 0, mouseY = 0;
var targetX = 0, targetY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

init();
animate();

function init() {
    container = document.createElement( 'div' );
    document.body.appendChild( container );

    // 添加摄像机
    camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.z = 900;
    scene = new THREE.Scene();

    // 添加光源
    scene.add( new THREE.AmbientLight( 0x222222 ));

    directionalLight = new THREE.DirectionalLight( 0xffeedd, 1 );
    directionalLight.position.set( 1, -1, 1 ).normalize();
    scene.add( directionalLight );

    // 添加材质,其中包括uv图纹理
    var ambient = 0x111111, diffuse = 0xbbbbbb, specular = 0x070707, shininess = 50;

    specular = 0x555555;

    var shader = THREE.ShaderSkin[ "skin" ];
    var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

    // normal纹理,diffuse纹理,涉及3D建模知识,目前还不了解具体意义
    uniforms[ "tNormal" ].value = THREE.ImageUtils.loadTexture( "leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg" );
    uniforms[ "uNormalScale" ].value = 0.75;
    
    uniforms[ "tDiffuse" ].value = THREE.ImageUtils.loadTexture( "leeperrysmith/Map-COL.jpg" );

    uniforms[ "passID" ].value = 1;

    // 设置一些颜色值
    uniforms[ "uDiffuseColor" ].value.setHex( diffuse );
    uniforms[ "uSpecularColor" ].value.setHex( specular );
    uniforms[ "uAmbientColor" ].value.setHex( ambient );

    uniforms[ "uRoughness" ].value = 0.185;
    uniforms[ "uSpecularBrightness" ].value = 0.8;

    var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true };

    material = new THREE.ShaderMaterial( parameters );

    // JSON加载器,需要自己指定uv贴图时一般都使用JSON加载器
    loader = new THREE.JSONLoader( true );
    document.body.appendChild( loader.statusDomElement );

    // 回调中暴露加载的模型的形状
    loader.load("leeperrysmith/LeePerrySmith.js", function( geometry ) { 
        geometry.computeTangents();

        // 以加载的模型的geometry和代码创建的材质对象组建mesh对象加载到场景中显示
        mesh = new THREE.Mesh( geometry, material );
        mesh.position.y = - 50;
        // scale参数一般是经验参数,自己调节获得
        mesh.scale.set( 100, 100, 100 );

        scene.add( mesh );
    });

    // 渲染
    renderer = new THREE.WebGLRenderer( { antialias: false } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setClearColorHex( 0x050505, 1 );
    renderer.autoClear = false;

    container.appendChild( renderer.domElement );

    // 鼠标移动事件,用来移动头部转动
    document.addEventListener( 'mousemove', function ( event ) {
        mouseX = ( event.clientX - windowHalfX );
        mouseY = ( event.clientY - windowHalfY );
    }, false );
}

function animate() {
    requestAnimationFrame( animate );

    targetX = mouseX * .001;
    targetY = mouseY * .001;

    // 通过mesh的rotation实现动画,和之前旋转摄像机实现动画不同
    if ( mesh ) {
        // 目前尚不清楚0.05的参数如何计算得到,或许也是经验值,调节获得?
        mesh.rotation.y += 0.05 * ( targetX - mesh.rotation.y );
        mesh.rotation.x += 0.05 * ( targetY - mesh.rotation.x );
    }

    renderer.clear();
    renderer.render( scene, camera );
}

对应的html代码如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - materials - skin [Lee Perry-Smith]</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                background:#000;
            }
        </style>
    </head>

    <body>
        <script src="js/three.js"></script>
        <script src="js/ShaderSkin.js"></script>
                ....
        </body>
</html>

工程中用到了一些资源,最主要的就是模型的JSON文件:http://mrdoob.github.com/three.js/examples/obj/leeperrysmith/LeePerrySmith.js, 然后是ShaderSkin.js的一个THREE扩展:http://mrdoob.github.com/three.js/examples/js/ShaderSkin.js,另外还有两个uv图片:http://mrdoob.github.com/three.js/examples/obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg 和 http://mrdoob.github.com/three.js/examples/obj/leeperrysmith/Map-COL.jpg 

自己去试试吧!

 

另,吐槽一些个人感受,仅供参考。在探索Three.js的过程中,深感文档的缺失,不仅中文文档少到可怜,英文文档也极少。对初学者来说这是很恼火的事情。在无望之际,只能反复研究它的示例代码,然后做一点反向工程,通过不断的试验去确定某些函数或API的具体作用。虽然最后结果还不错,但回头想想,如果文档中对API介绍细致,同时配合详尽的示例文档,我花掉这么多时间做的探索或许就可以浓缩成半天的文档阅读了,这样能节省多少时间哪。这个现象本身也说明three.js还处在发展的初期,还有非常多的工作要做。所以对那些打算使用three.js做产品的同仁,希望能慎之又慎,否则很有可能陷入泥沼不能自拔。当然,对那些本身以具备丰富的3D建模知识的同仁来说,很多困难都不值一提,我非常希望这样的牛人能关注three.js这个领域,做一些普及工作,让这个领域在中国能向前迈进一大步。

 

posted @ 2012-10-16 16:49  yunfan85  阅读(10186)  评论(5编辑  收藏  举报