WEBGL真实火焰实现(完整)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type = "text/css">
        html, body{
            margin: 0;
            height: 100%;
        }

        canvas{
            display: block;
        }
    </style>

<body onload="drawFire2();">
</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.7;
    var fireY = 0.7;
    var fireZ = 0.7;
    var renderer;
    function initRender() {
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setClearColor(new THREE.Color(0x000000));
        renderer.setSize(window.innerWidth,window.innerHeight);
        document.body.appendChild(renderer.domElement);
    }
    //
    var camera;
    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
        camera.position.set(0, 0, 10);
    }
    //
    let scene = new THREE.Scene();
    let tempFireObj = new THREE.Group();
    scene.add(tempFireObj);
    //
    var light;
    function initLight() {
        let light = new THREE.PointLight(0xffffff, 1, 100)
        light.position.set(10, 10, 20);
        tempFireObj.add(light);
    }
    //
    function initModel(){  //初始化轴辅助
        var object = new THREE.AxesHelper(500);
        scene.add(object);
    }
    //
    var stats;
    function initStats() {
        stats = new Stats();
        document.body.appendChild(stats.dom);
    }
    //
    var controls1;
    function  initControls() {
        controls1 = new THREE.OrbitControls(camera,renderer.domElement);
        controls1.enableDamping = true;
        controls1.enableZoom = true;
        controls1.autoRotate = false;
        controls1.enablePan = true;
    }
    //
    function initRoughTexture() {
        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;
        tempFireObj.add(groundMesh);
    }


    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() * 6;
                }

            }

            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;
        f.object.scale.set(fireX,fireY,fireZ);
        tempFireObj.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)
    //

    //
    function resize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        stats.update();
        //controls1.update();
        f.update();
        renderer.render(scene, camera);
    }
    function drawFire2() {
        initRender();
        initCamera();
        initLight();
        initModel();
        initRoughTexture();  //测试用
        //initControls();
        initStats();
        resize();
        animate();
    }



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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值