基於threejs開發的卡通風格着色器

        作爲一個大學一直在玩3D的同學,還是應該多寫寫關於3D的東西,正好把原來做得着色器整理整理,供大家參考也供自己以後回顧吧~

        一般的現實中的物體講求一個平滑着色,能夠使其看起來更加真實,而卡通風格的物體則是讓被着色物體顯得過渡的不那麼好,明暗交界線很明顯,這樣的風格獨樹一幟,也運用到了很多卡通風格的遊戲當中,我在網上看到的卡通風格着色器基於Unity開發的有很多,這裏我來基於threejs實現一下卡通着色器的開發。

                首先是three創建場景的代碼擺放攝像機,加上方向光,加載物體的位置,鼠標移動事件,render開始渲染。這些都不是主要的,最重要的是着色器材質的創建,這裏傳了2個uniform的參數一個是方向光的方向,另一個是顏色值,由於這兩個參數都是固定的,所以不用在每一幀進行改變,傳一次值即可。

function init() {

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

    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
    camera.position.z = 20;

    // scene

    scene = new THREE.Scene();
    

    var directionalLight = new THREE.DirectionalLight( 0xffffff );
    directionalLight.position.set( 1, 1, 1 );
    scene.add( directionalLight );
    var material = new THREE.MeshPhongMaterial( {color: 0x0908EF} );

        //着色器材質
        sm = new THREE.ShaderMaterial(
            {
                uniforms:
                    {
                        light: {type: 'v3', value: directionalLight.position},
                        color: {        // 方塊的基礎色
                            type: 'v3', // 指定變量類型爲三維向量
                            value: new THREE.Color('#1308EF')
                        }
                    },
                vertexShader:   document.getElementById( 'fish-vertexShader'   ).textContent,
                fragmentShader: document.getElementById( 'fish-fragmentShader' ).textContent,
                side: THREE.FrontSide,
                blending: THREE.AdditiveBlending,
                transparent: true
            }   );

    var geometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
    var cube = new THREE.Mesh( geometry, sm );
    scene.add( cube );
    //

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    container.appendChild( renderer.domElement );

    document.addEventListener( 'mousemove', onDocumentMouseMove, false );

    //

    window.addEventListener( 'resize', onWindowResize, false );

}
        下面是頂點着色器的開發,在頂點着色器中用法向量矩陣乘法向量,並進行規格化從而得出每個頂點法線的方向。這裏的normal和normalMatrix都是內建變量,不用傳給着色器,當需要用到時直接用就行了,然後用投影矩陣X模型矩陣X點的位置,就得到了該頂點在視口座標系的位置。(這裏不懂的同學可以看看圖形學方面的書)。

<script id="fish-vertexShader" type="x-shader/x-vertex">
varying vec3 vNormal;
void main()
{
     vNormal = normalize(normalMatrix * normal);
     gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
        頂點着色器還是比較簡單的,下面就到了重頭戲——片元着色器,該功能的實現都是由片元着色器實現的。先介紹原理:片元着色器的功能就是先將光照強度分級,並且將該等級映射到顏色上,然後根據每個片元受到的光照強度給予該片元一個等級的顏色。這樣就會人爲的製造出着色不平滑的色塊效果。diffuse是光強的意思,這裏由於我們使用的是方向光,所以直接用方向光乘法線,得到方向光在法線上的投影,這個投影就是光照強度,然後我們將其分爲0.8/0.6/0.4/0.2四個等級,根據等級的不同對這四種區域製造出不同的色塊,最終實現卡通的效果。

<script id="fish-fragmentShader" type="x-shader/x-vertex">
uniform vec3 light;
varying vec3 vNormal;
uniform vec3 color;
void main()
{
    float diffuse = dot(normalize(light), vNormal);
    if (diffuse > 0.8) {
    diffuse = 1.0;
}
else if (diffuse > 0.5) {
    diffuse = 0.6;
}
else if (diffuse > 0.2) {
    diffuse = 0.4;
}
else {
    diffuse = 0.2;
}
    gl_FragColor = vec4( color* diffuse, 1.0);
}
</script>
下面放效果圖(MeshPhongMaterial紋理與卡通紋理):

github地址:https://github.com/StringKun/ThreeJSToonShader

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章