使用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這個領域,做一些普及工作,讓這個領域在中國能向前邁進一大步。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM