基于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

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