THREE.JS真实火焰着色器实现

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Title</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-color: #000000;
            margin: 0px;
            overflow: hidden;
        }
        a{
            color: #0078ff;
        }
    </style>
</head>
<body onload="draw();">
</body>
<script src="../build/three.js"></script>
<script src="../node_modules/three/examples/js/renderers/Projector.js"></script>
<script src="../node_modules/three/examples/js/renderers/CanvasRenderer.js"></script>
<script src="../node_modules/three/examples/js/libs/stats.min.js"></script>
<script src="../node_modules/three/examples/js/libs/tween.min.js"></script>
<script src="../THREE.MeshLine/demo/js/dat.gui.min.js"></script>
<script src="../node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script type="text/javascript" src="../build/three.js"></script><script id="vertexShader" type="x-shader/x-vertex">
      precision mediump float;
      precision mediump int;
      attribute vec4 color;
      uniform float blend;
      uniform sampler2D gradient;
      uniform sampler2D blendPattern;
      varying vec2 vUv;
      varying float vFade;
      varying float dissolve;
      void main()	{
            vUv = uv;
            dissolve = texture2D(blendPattern, vUv).r * 0.1;
            vec4 localPosition = vec4( position*(1.+(dissolve*5.)), 1);
            vFade = clamp((localPosition.y + 3.0) / 6.0, 0.0, 1.0);
			gl_Position = projectionMatrix * modelViewMatrix * localPosition;
	  }
</script>
<script id="fragmentShader" type="x-shader/x-vertex">

			precision mediump float;
			precision mediump int;

			uniform float time;
			uniform float blend;

			uniform sampler2D gradient;
			uniform sampler2D blendPattern;

      varying float vFade;
      varying vec2 vUv;
  		varying float dissolve;

			void main()	{

        float spread = 0.2;

        float fadeAmount = smoothstep(
          max(0., vFade - spread),
          min(1., vFade + spread),
          blend + dissolve*1.2
	      );

				gl_FragColor = texture2D(gradient, vec2(vUv.x, fadeAmount));
			}
</script>
<script>
    var fireX = 0.5;
    var fireY = 0.5;
    var fireZ = 0.5;
    const renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    document.body.appendChild(renderer.domElement);

    let scene = new THREE.Scene();
    let camera = new THREE.PerspectiveCamera(
        45, window.innerWidth / window.innerHeight,
        0.1, 2000);
    camera.position.set(0, 0, 10);


    let rig = new THREE.Group();
    rig.add(camera);

    scene.add(rig);

    var texture = new THREE.TextureLoader().load(
        "/example/textures/Rough.jpg",
        function() {
            console.log("loaded");
        },
        undefined,
        function(e) {
            console.log("error", e);
        }
    );
    texture.crossOrigin = ""; //"anonymous";

    let plane = new THREE.PlaneGeometry(100, 100, 100, 100)
    let planeMaterial = new THREE.MeshStandardMaterial({
        color: 0x999999,
        roughness: 0.8,

        displacementMap: texture,
        displacementScale: 2,
        displacementBias: -1.4,
        map: texture,
    });
    let groundMesh = new THREE.Mesh(plane, planeMaterial);
    groundMesh.rotateX(-90 * THREE.Math.DEG2RAD);
    groundMesh.position.y = -2;
    scene.add(groundMesh);

    var stats;
    stats = new Stats();
    document.body.appendChild(stats.dom);


    class fire {
        constructor(density = 30, height = 8, r = 0.2, resolution = 64) {
            this.object = new THREE.Group();
            this.fireballs = [];
            this.height = height;
            this.radius = r;
            //加载纹理
            var texture = new THREE.TextureLoader().load(
                "/example/textures/Tendrils.png",
                function() {
                    console.log("loaded");
                },
                undefined,
                function(e) {
                    console.log("error", e);
                }
            );
            texture.crossOrigin = ""; //"anonymous";
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            var fireGradient = new THREE.TextureLoader().load(
                "/example/textures/Fire2.png",
                function() {
                    console.log("loaded");
                },
                undefined,
                function(e) {
                    console.log("error", e);
                }
            );
            texture.crossOrigin = ""; //"anonymous";
            //设置属性,调用着色器
            this.fireMaterial = new THREE.ShaderMaterial({
                uniforms: {
                    time: {
                        value: 1.0
                    },
                    blend: {
                        value: 1.0
                    },
                    gradient: {
                        type: "t",
                        value: fireGradient
                    },
                    blendPattern: {
                        type: "t",
                        value: texture
                    },
                },
                vertexShader: document.getElementById('vertexShader').textContent,
                fragmentShader: document.getElementById('fragmentShader').textContent,
                transparent: true,
                side: THREE.DoubleSide,
                //blending:THREE.AdditiveBlending
            });

            this.light = new THREE.PointLight(0xFF5500, 1, 100)
            this.light.position.set(0, 0.4, 0);
            this.lightIntensity = Math.random() * 5;

            this.object.add(this.light);
            //this.fireMaterial = new THREE.MeshStandardMaterial(0x661100);

            for (var i = 0; i < density; i++) {
                let geometry = new THREE.SphereGeometry(1, resolution, resolution);
                let mat = this.fireMaterial.clone();
                mat.uniforms.blendPattern.value = texture;
                mat.uniforms.gradient.value = fireGradient;
                mat.needsUpdate = true;
                let sphere = new THREE.Mesh(geometry, mat);
                sphere.position.y = Math.random() * height;
                sphere.position.x = (0.5 - Math.random()) * this.radius;
                sphere.position.z = (0.5 - Math.random()) * this.radius;
                sphere.rotateX(Math.random() * 1);
                sphere.rotateZ(Math.PI + (0.5 - Math.random()));
                sphere.rotateY(Math.random() * 3);
                sphere.dirX = ((0.5 - Math.random()) * 0.02);
                sphere.dirY = 0.02;
                sphere.dirZ = ((0.5 - Math.random()) * 0.02);

                this.fireballs.push(sphere);
            }

            this.object.add(...this.fireballs);

        }

        update() {

            this.fireballs.forEach(ball => {

                ball.position.y += ball.dirY + Math.sin(ball.position.y * 0.002);
                ball.position.x += Math.sin(ball.position.y * 0.5) * ball.dirX;
                ball.position.z += Math.cos(ball.position.y * 0.25) * ball.dirZ;
                if (ball.position.y > this.height) {
                    ball.position.y = -0.01
                    ball.position.x = (0.5 - Math.random()) * this.radius;
                    ball.position.z = (0.5 - Math.random()) * this.radius;
                }

                let p = ball.position.y / this.height;

                // ball.rotateZ((1.2-p)*0.01);
                ball.rotateY((1.2 - p) * 0.01)
                ball.scale.set(0.4 + p, 0.4 + p, 0.4 + p);
                ///ball.opacity = p;
                ball.material.uniforms.blend.value = p;
                //ball.material.needsUpdate = true;
            })

            this.light.intensity += (this.lightIntensity - this.light.intensity) * 0.02;

            if (Math.random() > 0.8) {
                this.lightIntensity = Math.random() * 5;
            }

        }
        env(val, envelope = [0., 0., 0.1, 1., 1., 0.]) {

            function lerp(v0, v1, t) {
                return v0 * (1 - t) + v1 * t
            }

        }

    }
    let f = new fire();
    f.object.position.y = -2.4;
    f.object.scale.set(fireX,fireY,fireZ);
    scene.add(f.object)
    // let cubeGeometry = new THREE.CubeGeometry(2, 2)
    // let cubeMaterial = new THREE.MeshStandardMaterial();
    // let cubeMesh = new THREE.Mesh(cubeGeometry, cubeMaterial);
    // scene.add(cubeMesh)
    //
    let light = new THREE.PointLight(0xffffff, 1, 100)
    light.position.set(10, 10, 20);
    scene.add(light);
    //
    function resize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function draw() {
        requestAnimationFrame(draw)
        stats.update();
        f.update();
        renderer.render(scene, camera);
    }
    function drawFire2() {
        resize();
        draw();
    }
    drawFire2();



</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值