threejs 自定义材质 熔浆,云雾效果

效果如下:

它其实就是使用了两种图片在着色器中经过拉伸,扭曲得到的效果;

需要两张图片:

上面那种云雾的很重要,它可以勉去在着色器中随机的运算,

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js shader教程</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 {
            color: #ffffff;
            font-family: Monospace;
            font-size: 13px;
            text-align: center;
            font-weight: bold;

            background-color: #000000;
            margin: 0px;
            overflow: hidden;
        }

        #info {
            position: absolute;
            top: 0px;
            width: 100%;
            padding: 5px;
        }

        a {

            color: #ffffff;
        }

        #oldie a {
            color: #da0
        }
    </style>
</head>
<body>

<div id="container"></div>
<div id="info">WebGL中文网,学习加群:331962041</div>

<script src="js/three.js"></script>

<script src="js/shaders/ConvolutionShader.js"></script>
<script src="js/shaders/CopyShader.js"></script>
<script src="js/shaders/FilmShader.js"></script>

<script src="js/postprocessing/EffectComposer.js"></script>
<script src="js/postprocessing/ShaderPass.js"></script>
<script src="js/postprocessing/MaskPass.js"></script>
<script src="js/postprocessing/RenderPass.js"></script>
<script src="js/postprocessing/BloomPass.js"></script>
<script src="js/postprocessing/FilmPass.js"></script>

<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>

<script id="fragmentShader" type="x-shader/x-fragment">

         uniform float time;
         uniform vec2 resolution;

         uniform float fogDensity;
         uniform vec3 fogColor;

         uniform sampler2D texture1;
         uniform sampler2D texture2;

         varying vec2 vUv;

            void main( void ) {

            vec2 position = -1.0 + 2.0 * vUv;//转化成平面格式(-1到1)

            vec4 noise = texture2D( texture1, vUv );//取纹理像素点(纹理设置的是重复纹理)
            vec2 T1 = vUv + vec2( 1.5, -1.5 ) * time  * 0.02;//噪音图流动基础uv(流动方向右下角至左上角)
            vec2 T2 = vUv + vec2( -0.5, 2.0 ) * time * 0.01;   //纹理图流动基础uv(流动方向左上角到右下角)

            //使噪音低采样坐标放大缩小
            T1.x += noise.x * 2.0;
            T1.y += noise.y * 2.0;
            T2.x -= noise.y * 0.2;
            T2.y += noise.z * 0.2;

            float p = texture2D( texture1, T1 * 2.0 ).a;//随机好的uv坐标缩小成4格,采样透明通道用于混合流动

            vec4 color = texture2D( texture2, T2 * 2.0 );//片元(随机好的uv坐标采样)
            //混合颜色(相同透明度下,color越小,越明;透明度越大,越明,就是color各个分量越大)
            vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color - 0.1 );

            //混合颜色大于1时处理
            if( temp.r > 1.0 ){ temp.bg += clamp( temp.r - 2.0, 0.0, 100.0 ); }
            if( temp.g > 1.0 ){ temp.rb += temp.g - 1.0; }
            if( temp.b > 1.0 ){ temp.rg += temp.b - 1.0; }

            gl_FragColor = temp;


            float depth = gl_FragCoord.z / gl_FragCoord.w;//获取深度
            const float LOG2 = 1.442695;
            //雾的密度计算(它范围时0到1之间)
            float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );
            //雾的颜色计算,并归一化;
            fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );
            //返回线性混合
            gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
         }

         }

      
</script>

<script id="vertexShader" type="x-shader/x-vertex">

         uniform vec2 uvScale;
         varying vec2 vUv;

         void main()
         {

            vUv = uvScale * uv;
            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            gl_Position = projectionMatrix * mvPosition;

         }

      
</script>

<script>

    if (!Detector.webgl) Detector.addGetWebGLMessage();

    var container, stats;

    var clock = new THREE.Clock();

    var camera, scene, renderer, composer;

    var uniforms, material, mesh;

    var mouseX = 0, mouseY = 0,
        lat = 0, lon = 0, phy = 0, theta = 0;

    var width = window.innerWidth || 2;
    var height = window.innerHeight || 2;

    var windowHalfX = width / 2;
    var windowHalfY = height / 2;

    init();
    animate();

    function init() {

        container = document.getElementById('container');

        camera = new THREE.PerspectiveCamera(35, windowHalfX / windowHalfY, 1, 3000);
        camera.position.z = 4;

        scene = new THREE.Scene();

        uniforms = {

            fogDensity: {type: "f", value: 0.45},//雾的密度
            fogColor: {type: "v3", value: new THREE.Vector3(0, 0, 0)},//雾的颜色
            time: {type: "f", value: 1.0},
            resolution: {type: "v2", value: new THREE.Vector2()},//分辨
            uvScale: {type: "v2", value: new THREE.Vector2(1.0, 1.0)},//uv 缩放
            texture1: {type: "t", value: THREE.ImageUtils.loadTexture("lava/cloud.png")},//云
            texture2: {type: "t", value: THREE.ImageUtils.loadTexture("lava/lavatile.jpg")}//熔浆

        };

        uniforms.texture1.value.wrapS = uniforms.texture1.value.wrapT = THREE.RepeatWrapping;
        uniforms.texture2.value.wrapS = uniforms.texture2.value.wrapT = THREE.RepeatWrapping;

        var size = 0.65;

        material = new THREE.ShaderMaterial({

            uniforms: uniforms,
            vertexShader: document.getElementById('vertexShader').textContent,
            fragmentShader: document.getElementById('fragmentShader').textContent

        });
        mesh = new THREE.Mesh(new THREE.CylinderGeometry(0.51, 1, 2), material);
        //mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2,1), material );

        //mesh = new THREE.Mesh( new THREE.TorusGeometry( size, 0.3, 30, 30 ), material );
        mesh.rotation.x = 0.3;
        scene.add(mesh);

        //

        renderer = new THREE.WebGLRenderer({antialias: true});
        container.appendChild(renderer.domElement);
        renderer.autoClear = false;

        //

        stats = new Stats();
        stats.domElement.style.position = 'absolute';
        stats.domElement.style.top = '0px';
        //container.appendChild( stats.domElement );

        //

        var renderModel = new THREE.RenderPass(scene, camera);
        var effectBloom = new THREE.BloomPass(1.25);
        var effectFilm = new THREE.FilmPass(0.35, 0.95, 2048, false);

        effectFilm.renderToScreen = true;

        composer = new THREE.EffectComposer(renderer);

        composer.addPass(renderModel);
        composer.addPass(effectBloom);
        composer.addPass(effectFilm);

        //

        onWindowResize();

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

    }

    function onWindowResize(event) {

        uniforms.resolution.value.x = window.innerWidth;
        uniforms.resolution.value.y = window.innerHeight;

        renderer.setSize(window.innerWidth, window.innerHeight);

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        composer.reset();

    }

    //

    function animate() {

        requestAnimationFrame(animate);

        render();
        stats.update();

    }

    function render() {

        var delta = 5 * clock.getDelta();

        uniforms.time.value += 0.2 * delta;

        /*          mesh.rotation.y += 0.0125 * delta;
                        mesh.rotation.x += 0.05 * delta;*/

        renderer.clear();
        composer.render(0.01);
//                renderer.render( scene, camera );
    }

</script>

</body>
</html>

 

不要考虑后期处理与它没有关系;

把低图换成白色的,就可以得到云雾效果;

 

函数:
exp2 表示以2位低的指数;而上面它是负半轴上,所以区间就为0到1;
clamp(a,min,max) 表示a 在min到max区间,如果a小于最小的min,返回min,如果大于max,返回max,在两者之间,返回本身
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值